forked from Telodendria/Telodendria
Compare commits
10 commits
419017bcc9
...
e0327b8769
Author | SHA1 | Date | |
---|---|---|---|
e0327b8769 | |||
c626b2f4f2 | |||
3ecbef27af | |||
b9263c4819 | |||
b9e5d885f4 | |||
0b820b80f7 | |||
6dcfa7dc02 | |||
024482d4e8 | |||
7a091c5b93 | |||
9e8523d92e |
27 changed files with 4154 additions and 928 deletions
|
@ -1,7 +1,7 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: General Matrix Room
|
- name: General Matrix Room
|
||||||
- url: https://matrix.to/#/#telodendria-general:bancino.net
|
url: "https://matrix.to/#/#telodendria-general:bancino.net"
|
||||||
- about: |
|
about: |
|
||||||
General discussion on Telodendria happens in this Matrix room. You
|
General discussion on Telodendria happens in this Matrix room. You
|
||||||
may get quicker feedback from there.
|
may get quicker feedback from there.
|
||||||
|
|
25
.gitea/pull_request_template.md
Normal file
25
.gitea/pull_request_template.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Please review the developer certificate of origin:
|
||||||
|
|
||||||
|
1. The contribution was created in whole or in part by me, and I have
|
||||||
|
the right to submit it under the open source licenses of the
|
||||||
|
Telodendria project; or
|
||||||
|
1. The contribution is based upon a previous work that, to the best of
|
||||||
|
my knowledge, is covered under an appropriate open source license and
|
||||||
|
I have the right under that license to submit that work with
|
||||||
|
modifications, whether created in whole or in part by me, under the
|
||||||
|
Telodendria project license; or
|
||||||
|
1. The contribution was provided directly to me by some other person
|
||||||
|
who certified (1), (2), or (3), and I have not modified it.
|
||||||
|
1. I understand and agree that this project and the contribution are
|
||||||
|
made public and that a record of the contribution—including all
|
||||||
|
personal information I submit with it—is maintained indefinitely
|
||||||
|
and may be redistributed consistent with this project or the open
|
||||||
|
source licenses involved.
|
||||||
|
|
||||||
|
- [ ] I have read the Telodendria Project development certificate of
|
||||||
|
origin, and I certify that I have permission to submit this patch
|
||||||
|
under the conditions specified in it.
|
||||||
|
|
|
@ -196,7 +196,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
char *pathPart;
|
char *pathPart;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
HttpRouteFunc *exec = NULL;
|
HttpRouteFunc *exec = NULL;
|
||||||
Array *matches;
|
Array *matches = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -254,14 +254,18 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
{
|
{
|
||||||
/* pmatch[0] is the whole string, not the first
|
/* pmatch[0] is the whole string, not the first
|
||||||
* subexpression */
|
* subexpression */
|
||||||
|
char * substr;
|
||||||
|
regmatch_t cpmatch;
|
||||||
for (i = 1; i < REG_MAX_SUB; i++)
|
for (i = 1; i < REG_MAX_SUB; i++)
|
||||||
{
|
{
|
||||||
|
cpmatch = pmatch[i];
|
||||||
|
substr = StrSubstr(pathPart, cpmatch.rm_so, cpmatch.rm_eo);
|
||||||
if (pmatch[i].rm_so == -1)
|
if (pmatch[i].rm_so == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayAdd(matches, StrSubstr(pathPart, pmatch[i].rm_so, pmatch[i].rm_eo));
|
ArrayAdd(matches, substr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,6 @@ StrSubstr(const char *inStr, size_t start, size_t end)
|
||||||
}
|
}
|
||||||
|
|
||||||
len = end - start;
|
len = end - start;
|
||||||
|
|
||||||
outStr = Malloc(len + 1);
|
outStr = Malloc(len + 1);
|
||||||
if (!outStr)
|
if (!outStr)
|
||||||
{
|
{
|
||||||
|
|
163
docs/CONTRIBUTING.md
Normal file
163
docs/CONTRIBUTING.md
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Telodendria is a fully open source project. As such, it welcomes
|
||||||
|
contributions. There are many ways you can contribute, and any way you
|
||||||
|
can is greatly appreciated. This document details the ways you can
|
||||||
|
contribute, and how to go about contributing.
|
||||||
|
|
||||||
|
## Sponsoring Telodendria
|
||||||
|
|
||||||
|
If you would like to sponsor Telodendria, see the
|
||||||
|
[Sponsorship](../README.md#sponsorship) section on the main project
|
||||||
|
page. Donations of any size are greatly appreciated.
|
||||||
|
|
||||||
|
## Reporting Issues
|
||||||
|
|
||||||
|
An important way to get involved is to just report issues you find with
|
||||||
|
Telodendria during experimentation or normal use. To report an issue,
|
||||||
|
go to [Issues](/Telodendria/telodendria/issues) →
|
||||||
|
[New Issue](/Telodendria/telodendria/issues/new/choose) and follow the
|
||||||
|
instructions.
|
||||||
|
|
||||||
|
> **Note:** GitHub issues are not accepted. Issues may only be
|
||||||
|
> submitted to the official [Gitea](https://git.telodendria.io)
|
||||||
|
> instance.
|
||||||
|
|
||||||
|
### Feature Requests
|
||||||
|
|
||||||
|
Feature requests are allowed, but note that they are low-priority in
|
||||||
|
comparison to existing issues and features. That being said, don't
|
||||||
|
hesitate to submit feature requests. Just select the "Feature Request"
|
||||||
|
option when submitting an issue.
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
If you want to write code for Telodendria, either to fix an issue or
|
||||||
|
add a new feature, you're in the right place. Please follow all the
|
||||||
|
guidelines in this document to ensure the contribution workflow goes
|
||||||
|
as smoothly as possible.
|
||||||
|
|
||||||
|
### Who can develop Telodendria?
|
||||||
|
|
||||||
|
Everyone is welcome to contribute code to Telodendria, provided that
|
||||||
|
they are willing to license their contributions under the same license
|
||||||
|
as the project itself.
|
||||||
|
|
||||||
|
The primary language used to write Telodendria code is ANSI C. Other
|
||||||
|
languages you'll find in the Telodendria repository include shell
|
||||||
|
scripts, `mdoc`, a little bit of HTML and CSS, and `Makefiles`.
|
||||||
|
Experience with any of these is preferred, but if you want to use
|
||||||
|
Telodendria to learn, that's okay too! Telodendria's code base should
|
||||||
|
hopefully be a good learning tool, and if you are serious about
|
||||||
|
submitting quality work, we'll guide you through the process and
|
||||||
|
offer suggestions.
|
||||||
|
|
||||||
|
### What do I need?
|
||||||
|
|
||||||
|
You'll need a couple of things to develop Telodendria:
|
||||||
|
|
||||||
|
- A Unix-like operating system that provides standard POSIX behavior,
|
||||||
|
or the Windows Subsystem for Linux (WSL), Cygwin, or Msys2 if you are
|
||||||
|
running Windows.
|
||||||
|
- A C compiler capable of compiling ANSI C89 code (pretty much all of
|
||||||
|
them do—pick your favorite, and if you find it doesn't work,
|
||||||
|
open an issue!).
|
||||||
|
- `make` for building the project.
|
||||||
|
- `git` for managing your changes.
|
||||||
|
|
||||||
|
Optionally, you may also find these tools helpful:
|
||||||
|
|
||||||
|
- `indent` for formatting code.
|
||||||
|
- `valgrind` for debugging particularly nasty issues.
|
||||||
|
|
||||||
|
### Getting The Code
|
||||||
|
|
||||||
|
Telodendria is developed using Git. The easiest way to contribute
|
||||||
|
changes is to fork the main repository, and then creating a pull
|
||||||
|
request to ask us to pull your changes into our repo.
|
||||||
|
|
||||||
|
1. If you don't have an account on the
|
||||||
|
[Gitea instance](https://git.telodendria.io), create one and sign in.
|
||||||
|
1. Fork this repository.
|
||||||
|
1. In your development environment, clone your fork:
|
||||||
|
```shell
|
||||||
|
git clone https://git.telodendria.io/[YOUR_USERNAME]/telodendria.git
|
||||||
|
cd telodendria
|
||||||
|
```
|
||||||
|
|
||||||
|
Please base your changes on the `master` branch. If you need help
|
||||||
|
getting started with Git, that is beyond the scope of this
|
||||||
|
document, but you can find many good tutorials on the web.
|
||||||
|
|
||||||
|
### Building & Running
|
||||||
|
|
||||||
|
Telodendria uses the `make` build system.
|
||||||
|
|
||||||
|
**TODO:** Update this section before #19 is closed. Provide quick
|
||||||
|
make, run, and install directions (maybe just redirect to Porting for
|
||||||
|
install directions), then list all the `make` recipes. Shouldn't be
|
||||||
|
as many as were in `td`.
|
||||||
|
|
||||||
|
### Pull Requests
|
||||||
|
|
||||||
|
> **Note:** Telodendria does not accept GitHub pull requests at this
|
||||||
|
> time. Please submit your pull requests via Gitea.
|
||||||
|
|
||||||
|
Telodendria follows the standard pull request procedures. Once you have
|
||||||
|
made your changes, committed them, and pushed to your fork, you should
|
||||||
|
be able to open a pull request on the main repository. When you do, you
|
||||||
|
will be prompted to write a description. Be sure to include the
|
||||||
|
related issue that you are closing in your description.
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
|
||||||
|
In general, these are the conventions used by the code base. This
|
||||||
|
guide may be slightly outdated or subject to change, but it should be
|
||||||
|
a good start. The source code itself is always the absolute source of
|
||||||
|
truth, so as long as you make your code look like the code surrounding
|
||||||
|
it, you should be fine.
|
||||||
|
|
||||||
|
- All function, enumeration, structure, and header names are
|
||||||
|
`CamelCase`. This is preferred to `snake_case` because it is more
|
||||||
|
compact.
|
||||||
|
- All variable names are `lowerCamelCase`. This is preferred to
|
||||||
|
`snake_case` because it is more compact. One exception to this rule is
|
||||||
|
if a variable name, such as a member of a struct, directly represents
|
||||||
|
a JSON key in an object specified by the Matrix specification, which
|
||||||
|
may be in `snake_case`.
|
||||||
|
- Enumerations and structures are always `typedef`-ed to their same
|
||||||
|
name. The `typedef` should occur in the public API header, and the
|
||||||
|
actual declaration should live in the implementation file, unless
|
||||||
|
the enumeration or structure is intended to be made fully public.
|
||||||
|
- A feature of the code base lives in a single C source file that has a
|
||||||
|
matching header. The header file should only export public symbols;
|
||||||
|
everything else in the C source should be static.
|
||||||
|
- Except where absolutely necessary, global variables are forbidden
|
||||||
|
to prevent problems with threads and whatnot. Every variable a
|
||||||
|
function needs should be passed to it either through a structure, or
|
||||||
|
as a separate argument.
|
||||||
|
- Anywhere that C allows curly braces to be optional, there still must
|
||||||
|
be curly braces. This makes it easier to read the code by making it
|
||||||
|
less ambiguous, and it makes it easier to add on to the code later.
|
||||||
|
|
||||||
|
As far as actually formatting the code goes, such as where to put
|
||||||
|
brackets, and whether or not to use tabs or spaces, use `indent` to
|
||||||
|
take care of that. The repository contains a `.indent.pro` that should
|
||||||
|
automatically be loaded by `indent` to set the correct rules. If you
|
||||||
|
don't have a working `indent`, then just indicate in your pull
|
||||||
|
request that I should run my `indent` on the code.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
This project places a strong emphasis on documentation. Well-documented
|
||||||
|
code is fundamental to a successful project, so when you are writing
|
||||||
|
code, please also make sure that it is documented appropriately.
|
||||||
|
|
||||||
|
- If you are adding a header, make sure you add the necessary comments
|
||||||
|
detailing the header and the functions in it.
|
||||||
|
- If you are adding a function, make sure you add the necessary
|
||||||
|
comments to the appropriate header.
|
||||||
|
|
||||||
|
If your pull request does not also include proper documentation, it
|
||||||
|
will likely be rejected.
|
||||||
|
|
246
docs/user/config.md
Normal file
246
docs/user/config.md
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
Telodendria is designed to be configurable. It is configured using
|
||||||
|
JSON, which is intended to be submitted to the [Administrator
|
||||||
|
API](admin/README.md). This document details Telodendria's configuration
|
||||||
|
JSON format, which is used in both the administrator API and on-disk
|
||||||
|
in the database. The configuration file on the disk in the databsae
|
||||||
|
is `config.json`, though that file should not be edited by hand.
|
||||||
|
Use the API described in
|
||||||
|
[Administrator API → Configuration](admin/config.md).
|
||||||
|
|
||||||
|
## JSON Format
|
||||||
|
|
||||||
|
Telodendria's configuration is just a JSON object in the standard
|
||||||
|
key-value form:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"serverName": "telodendria.io",
|
||||||
|
"listen": [
|
||||||
|
{
|
||||||
|
"port": 8008,
|
||||||
|
"tls": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Some keys, called *directives* in this document, have values that are
|
||||||
|
objects themselves.
|
||||||
|
|
||||||
|
## Directives
|
||||||
|
|
||||||
|
Here are the top-level directives:
|
||||||
|
|
||||||
|
- **listen:** `Array`
|
||||||
|
|
||||||
|
An array of listener description objects. Telodendria supports
|
||||||
|
listening on multiple ports, and each port is configured
|
||||||
|
independently of the others. A listener object looks like this:
|
||||||
|
|
||||||
|
- **port:** `integer`
|
||||||
|
|
||||||
|
The port to listen on. Telodendria will bind to all interfaces,
|
||||||
|
so it is recommended to configure your firewall to only allow
|
||||||
|
access on the desired interfaces. Note that Telodendria offers all
|
||||||
|
APIs over each port, including the administrator APIs; there is no
|
||||||
|
way to control which APIs are made available over which ports. If
|
||||||
|
this is a concern, a reverse-proxy such as `relayd` can be placed
|
||||||
|
in front of Telodendria to block access to undesired APIs.
|
||||||
|
|
||||||
|
- **tls:** `Object|null|false`
|
||||||
|
|
||||||
|
Telodendria can be compiled with TLS support. If it is, then a
|
||||||
|
particular listener can be set to use TLS for connections. If
|
||||||
|
**tls** is not `null` or `false`, then it can be an object with
|
||||||
|
the following directives:
|
||||||
|
|
||||||
|
- **cert:** `String`
|
||||||
|
|
||||||
|
The full path—or path relative to the data
|
||||||
|
directory—of the certificate file to load. The certificate
|
||||||
|
file should be in the format expected by the platform's TLS
|
||||||
|
library.
|
||||||
|
|
||||||
|
- **key:** `String`
|
||||||
|
|
||||||
|
Same as **cert**, but this should be the private key that matches
|
||||||
|
the certificate being used.
|
||||||
|
|
||||||
|
- **threads:** `Integer`
|
||||||
|
|
||||||
|
How many worker threads to spin up to handle requests for this
|
||||||
|
listener. This should generally be less than the total CPU core
|
||||||
|
count, to prevent overloading the system. The most efficient number
|
||||||
|
of threads ultimately depends on the configuration of the machine
|
||||||
|
running Telodendria, so you may just have to play around with
|
||||||
|
different values here to see which gives the best performance.
|
||||||
|
|
||||||
|
Note that this can be set as low as 0; in that case, the listener
|
||||||
|
will never respond to requests. Each listener needs to have at
|
||||||
|
least one thread to be useful. Also note that Telodendria may spin
|
||||||
|
up additional threads for background work, so the actual total
|
||||||
|
thread count at any given time may exceed the sum of threads
|
||||||
|
specified in the configuration.
|
||||||
|
|
||||||
|
This directive is optional. The default value is `4` in the upstream
|
||||||
|
code, but your software distribution may have patched this to be
|
||||||
|
different.
|
||||||
|
|
||||||
|
- **maxConnections:** `Integer`
|
||||||
|
|
||||||
|
The maximum number of simultanious connections to allow to the
|
||||||
|
daemon. This option prevents the daemon from allocating large
|
||||||
|
amounts of memory in the event that it undergoes a denial of
|
||||||
|
service attack. It is optional, defaults to `32`, and typically
|
||||||
|
does not need to be adjusted.
|
||||||
|
|
||||||
|
- **serverName:** `String`
|
||||||
|
|
||||||
|
Configure the domain name of your homeserver. Note that Matrix
|
||||||
|
servers cannot be migrated to other domains, so once this is set,
|
||||||
|
it should never change unless you want unexpected things to happen
|
||||||
|
or you want to start over. **serverName** should be a DNS name that
|
||||||
|
can be publicly resolved. This directive is required.
|
||||||
|
|
||||||
|
- **baseUrl:** `String`
|
||||||
|
|
||||||
|
Set the server's base URL. **baseUrl** should be a valid URL,
|
||||||
|
complete with the protocol. It does not need to be the same as the
|
||||||
|
server name; in fact, it is common for a subdomain of the server name
|
||||||
|
to be the base URL for the Matrix homeserver.
|
||||||
|
|
||||||
|
This URL is the URL at which Matrix clients will connect to the
|
||||||
|
server, and is thus served as a part of the `.well-known`
|
||||||
|
manifest.
|
||||||
|
|
||||||
|
This directive is optional. If unspecified, it is automatically
|
||||||
|
deduced from the server name.
|
||||||
|
|
||||||
|
- **identityServer:** `String`
|
||||||
|
|
||||||
|
The identity server that clients should use to perform identity
|
||||||
|
lookups. **identityServer** folows the same rules as **baseUrl**.
|
||||||
|
It also is optional, and is set to be the same as the **baseUrl**
|
||||||
|
if left unspecified.
|
||||||
|
|
||||||
|
- **runAs:** `Object`
|
||||||
|
|
||||||
|
The effective Unix user and group to drop to after binding to the
|
||||||
|
socket and completing any setup that may potentially require
|
||||||
|
elevated privileges. This directive only takes effect if
|
||||||
|
Telodendria is started as the root user, and is used as a security
|
||||||
|
mechanism. If this option is set and Telodendria is started as a
|
||||||
|
non-privileged user, then a warning is printed to the log if that
|
||||||
|
user and group do not match what's specified here. This directive
|
||||||
|
is optional, but should be used as a sanity check even if not
|
||||||
|
running as `root`, just to make sure you have your permissions
|
||||||
|
working properly.
|
||||||
|
|
||||||
|
This directive takes an object with the following directives:
|
||||||
|
|
||||||
|
- **uid:** `String`
|
||||||
|
|
||||||
|
The Unix username to switch to. If **runAs** is specified, this
|
||||||
|
directive is required.
|
||||||
|
|
||||||
|
- **gid:** `String`
|
||||||
|
|
||||||
|
The Unix group to switch to. This directive is optional; if left
|
||||||
|
unspecified, then the value of **uid** is copied.
|
||||||
|
|
||||||
|
- **federation:** `Boolean`
|
||||||
|
|
||||||
|
Whether or not to enable federation with other Matrix homeservers.
|
||||||
|
Matrix by its very nature is a federated protocol, but if you just
|
||||||
|
want to rn your own internal chat server with no contact with the
|
||||||
|
outside, then you can use this option to disable federation. It is
|
||||||
|
highly recommended to set this to `true`, however, if you wish to
|
||||||
|
be able to communicate with users on other Matrix servers. This
|
||||||
|
directive is required.
|
||||||
|
|
||||||
|
- **registration:** `Boolean`
|
||||||
|
|
||||||
|
Whether or not to enable new user registration or not. For security
|
||||||
|
and anti-spam reasons, you can set this to `false`. If you do, you
|
||||||
|
can still allow only certain users to be registered using
|
||||||
|
registration tokens, which can be managed via the administrator API.
|
||||||
|
This directive is required.
|
||||||
|
|
||||||
|
In an ideal world, everyone would run their own Matrix homeserver,
|
||||||
|
so no public registration would ever be required. Unfortunately,
|
||||||
|
not everyone has the means to run their own homeserver, especially
|
||||||
|
because of the fact that IPv4 addresses are becoming increasingly
|
||||||
|
hard to come by. If you would like to provide a service to those
|
||||||
|
that are unable to run their homeserver, then set this to `true`,
|
||||||
|
thereby allowing anyone to create an account.
|
||||||
|
|
||||||
|
Telodendria *should* be capable of handling a large amount of users
|
||||||
|
without difficulty, but it is targetted at smaller deployments.
|
||||||
|
|
||||||
|
- **log:** `Object`
|
||||||
|
|
||||||
|
The logging configuration. Telodendria uses its own logging
|
||||||
|
facility, which can output logs to standard output, a file, or the
|
||||||
|
syslog. This directive is required, and it takes an object with the
|
||||||
|
following directives:
|
||||||
|
|
||||||
|
- **output:** `Enum`
|
||||||
|
|
||||||
|
The log output destination. This can either be `stdout`, `file`,
|
||||||
|
or `syslog`. If set to `file`, Telodendria will log to
|
||||||
|
`telodendria.log` inside the data directory.
|
||||||
|
|
||||||
|
- **level:** `Enum`
|
||||||
|
|
||||||
|
The level of messages to log. Each level shows all the levels above
|
||||||
|
it. The levels are as follows:
|
||||||
|
|
||||||
|
- `error`
|
||||||
|
- `warning`
|
||||||
|
- `notice`
|
||||||
|
- `message`
|
||||||
|
- `debug`
|
||||||
|
|
||||||
|
For example, setting the level to `error` will show only errors,
|
||||||
|
while setting the level to `warning` will show both warnings
|
||||||
|
*and* errors. The `debug` level shows all messages.
|
||||||
|
|
||||||
|
- **timestampFormat:** `Enum`
|
||||||
|
|
||||||
|
If you want to customize the timestamp format shown in the log,
|
||||||
|
or disable it altogether, you can do so via this option. Acceptable
|
||||||
|
values are `none`, `default`, or a formatter string as described
|
||||||
|
by your system's `strftime()` documentation. This option only
|
||||||
|
applies if **log** is `stdout` or `file`.
|
||||||
|
|
||||||
|
- **color:** `Boolean`
|
||||||
|
|
||||||
|
Whether or not to enable colored output on TTYs. Note that ANSI
|
||||||
|
color sequences will not be written to a log file, only a real
|
||||||
|
terminal, so this option only applies if the log is being written
|
||||||
|
to a standard output which is connected to a terminal.
|
||||||
|
|
||||||
|
- **maxCache:** `Integer`
|
||||||
|
|
||||||
|
The maximum size of the cache. Telodendria relies heavily on caching
|
||||||
|
for performance reasons. The cache grows as data is loaded from the
|
||||||
|
data directory. All cache is stored in memory. This option limits the
|
||||||
|
size of the memory cache. If you have a system with a lot of memory
|
||||||
|
to spare, you'll get better performance if this option is set higher.
|
||||||
|
Otherwise, this value should be lowered on systems that have a
|
||||||
|
minimal amount of memory available.
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
A number of example configuration files are shipped with Telodendria's
|
||||||
|
source code. They can be found in the `contrib/` directory if you are
|
||||||
|
viewing the source code directly. Otherwise, if you installed
|
||||||
|
Telodendria from a package, it is possible that the example
|
||||||
|
configurations were placed in the default locations for such files on
|
||||||
|
your operating system.
|
||||||
|
|
|
@ -48,4 +48,13 @@ binaries.
|
||||||
|
|
||||||
## From Source
|
## From Source
|
||||||
|
|
||||||
**TODO:** Update this section before #19 is closed.
|
If you would like to build Telodendria from source, you can download
|
||||||
|
the latest release code from the
|
||||||
|
[Releases](/Telodendria/telodendria/releases) page. After extracting
|
||||||
|
the tarball, read
|
||||||
|
[Contributing → Developing → Building & Running](../CONTRIBUTING#building-and-running)
|
||||||
|
for details on how to build Telodendria.
|
||||||
|
|
||||||
|
If all goes well, you will find the server binary in the `build/`
|
||||||
|
directory. If an error occured, and you didn't modify the code,
|
||||||
|
please open an issue.
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
.Dd $Mdocdate: April 29 2023 $
|
|
||||||
.Dt SEND-PATCH 1
|
|
||||||
.Os Telodendria Project
|
|
||||||
.Sh NAME
|
|
||||||
.Nm send-patch
|
|
||||||
.Nd Submit a patch file to the Telodendria Patches Matrix room
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op patch
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
is a simple shell script for submitting patch files to Telodendria's patch
|
|
||||||
room for review.
|
|
||||||
.Pp
|
|
||||||
.Nm
|
|
||||||
takes a single argument, a patch file. It also reads a number of environment
|
|
||||||
variables, as described in the following section. This script is designed to be
|
|
||||||
simple; it only pushes files into a hard-coded Matrix room. Thus, as far as
|
|
||||||
Matrix clients go, this one is a rather minimal one, and that is by design.
|
|
||||||
.Pp
|
|
||||||
This script exists so that users who are working on a machine that doesn't have
|
|
||||||
a Matrix client installed can still submit work to the Telodendria project. The
|
|
||||||
goal is to make development as accessible as possible.
|
|
||||||
.Pp
|
|
||||||
This script only supports password login, so if your homeserver does not
|
|
||||||
support password login, it will not work.
|
|
||||||
.Sh ENVIRONMENT
|
|
||||||
.Pp
|
|
||||||
.Nm
|
|
||||||
utilizes the following environment variables:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ev MXID
|
|
||||||
Your Matrix ID in the standard format. This is used to connect to your
|
|
||||||
homeserver to send the message.
|
|
||||||
.It Ev MXPW
|
|
||||||
Your Matrix account's password. If not set, you will be prompted for your
|
|
||||||
password by the script, unless
|
|
||||||
.Ev ACCESS_TOKEN
|
|
||||||
is set.
|
|
||||||
.It Ev ACCESS_TOKEN
|
|
||||||
If you already have an access token for your account, such as one from an
|
|
||||||
existing session, then you can set this environment variable to bypass the
|
|
||||||
password authentication flow.
|
|
||||||
.El
|
|
||||||
.Sh FILES
|
|
||||||
.Pp
|
|
||||||
.Nm
|
|
||||||
does utilize the
|
|
||||||
.Pa .env
|
|
||||||
file, just like
|
|
||||||
.Xr td 1 .
|
|
||||||
Consult that page for the specifics of the
|
|
||||||
.Pa .env
|
|
||||||
file.
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr td 1
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
.Dd $Mdocdate: April 29 2023 $
|
|
||||||
.Dt TP 1
|
|
||||||
.Os Telodendria Project
|
|
||||||
.Sh NAME
|
|
||||||
.Nm tp
|
|
||||||
.Nd Manage the official patch queue.
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Np
|
|
||||||
.Op action
|
|
||||||
.Op patch
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Pp
|
|
||||||
This script is probably not going to be very useful for anyone other
|
|
||||||
than the official project managers, but for completeness, this page
|
|
||||||
documents it.
|
|
||||||
.Pp
|
|
||||||
.Nm
|
|
||||||
is a simple script that is used to manage the patch queue. It offers a
|
|
||||||
simple way to fetch patches from the patch Matrix room and queue them
|
|
||||||
in a patch directory, which is then updated as patches are handled.
|
|
||||||
Contributions to Telodendria are entirely patch-based, so this script
|
|
||||||
makes dealing with patch files much more convenient.
|
|
||||||
.Pp
|
|
||||||
.Nm
|
|
||||||
doesn't implement a complex command line interface. It simply takes an
|
|
||||||
action as the first argument, and a patch file ID as the second
|
|
||||||
argument to some actions. The actions are as follows:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It ingress
|
|
||||||
Download all new patches from the patches room. This action is intended
|
|
||||||
to be called periodically from
|
|
||||||
.Xr cron 8
|
|
||||||
to fetch new patches.
|
|
||||||
.It queue
|
|
||||||
List all the patches in the queue, printing the first three lines of
|
|
||||||
each one so they can be easily identified.
|
|
||||||
.It view
|
|
||||||
View the specified patch. Note that the specified patch must be in
|
|
||||||
the queue. Once it is applied or rejected, this script offers no
|
|
||||||
facility for viewing it.
|
|
||||||
.It apply
|
|
||||||
Apply the specified patch to the current working directory.
|
|
||||||
.It reverse
|
|
||||||
Reverse the specified patch on the current working directory.
|
|
||||||
.It accept|reject
|
|
||||||
Accept or reject the specified patch by moving it to the appropriate
|
|
||||||
directory. These actions also prompt for a message, into which it is
|
|
||||||
expected that an explanation for why the patch was accepted or rejected
|
|
||||||
will be placed.
|
|
||||||
.El
|
|
||||||
.Sh ENVIRONMENT
|
|
||||||
.Pp
|
|
||||||
The following environment variables are read by the
|
|
||||||
.Nm
|
|
||||||
script:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ev TELODENDRIA_PUB
|
|
||||||
The base directory inside which the patch directory relies.
|
|
||||||
.It Ev HOMESERVER
|
|
||||||
The Matrix homeserver to contact for receiving patches.
|
|
||||||
.It Ev ACCESS_TOKEN
|
|
||||||
The access token to use to authenticate with the Matrix homeserver.
|
|
||||||
.El
|
|
|
@ -1,218 +0,0 @@
|
||||||
.Dd $Mdocdate: April 20 2023 $
|
|
||||||
.Dt TELODENDRIA-CONFIG 7
|
|
||||||
.Os Telodendria Project
|
|
||||||
.Sh NAME
|
|
||||||
.Nm telodendria-config
|
|
||||||
.Nd Telodendria configuration.
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Pp
|
|
||||||
Telodendria is designed to be configurable. It is configured using
|
|
||||||
JSON, which is intended to be submitted via the administrator API.
|
|
||||||
This page documents Telodendria's configuration JSON format, which
|
|
||||||
is used both in the administrator API, and on the disk in the
|
|
||||||
database. The configuration file on the disk in the database is
|
|
||||||
.Pa config.json ,
|
|
||||||
though that file should not be edited directly. Use the API described
|
|
||||||
in
|
|
||||||
.Xr telodendria-admin 7
|
|
||||||
instead.
|
|
||||||
.Sh DIRECTIVES
|
|
||||||
Here are the top-level directives:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ic listen Ar listenArr
|
|
||||||
An array of listener description objects. Telodendria supports
|
|
||||||
listening on multiple ports, and each port is configured
|
|
||||||
independently of the others. A listener description object looks
|
|
||||||
like this:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ic port Ar port
|
|
||||||
The port to listen on. Telodendria will bind to all interfaces, so it
|
|
||||||
is recommended to configure your firewall so you can control what is
|
|
||||||
allowed to access the Telodendria ports. Note that
|
|
||||||
Telodendria offers all APIs over each port; there is no way to
|
|
||||||
control which APIs are available over which ports, although all
|
|
||||||
APIs should be safe against attacks, so this should not be a
|
|
||||||
major concern.
|
|
||||||
.Pp
|
|
||||||
.Ar port
|
|
||||||
should be a decimal port number. This directive is required. Common
|
|
||||||
port numbers are 8008 for non-TLS, and 8448 for TLS.
|
|
||||||
.It Ic tls Ar tlsObj|null|false
|
|
||||||
Telodendria can be compiled with TLS support. If it is, then a
|
|
||||||
particular listener can be set to use TLS for connections. If
|
|
||||||
.Ic tls
|
|
||||||
is not
|
|
||||||
.Ar null
|
|
||||||
or
|
|
||||||
.Ar false ,
|
|
||||||
then it can be an object with the following directives:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ic cert Ar file
|
|
||||||
A certificate file in the format native to the platform's TLS
|
|
||||||
library. This can be an absolute path, otherwise it is relative
|
|
||||||
to the data directory.
|
|
||||||
.It Ic key Ar file
|
|
||||||
A key file in the format native to the platform's TLS library.
|
|
||||||
It follows the same rules as the certificate file.
|
|
||||||
.El
|
|
||||||
.El
|
|
||||||
.It Ic serverName Ar name
|
|
||||||
Configure the domain name of your homeserver. Note that Matrix servers
|
|
||||||
cannot be migrated to other domains, so once this is set, it should never
|
|
||||||
change unless you want unexpected things to happen, or you want to start
|
|
||||||
over.
|
|
||||||
.Ar name
|
|
||||||
should be a DNS name that can be publically resolved. This directive
|
|
||||||
is required.
|
|
||||||
.It Ic baseUrl Ar url
|
|
||||||
Set the server's base URL.
|
|
||||||
.Ar url
|
|
||||||
should be a valid URL, complete with the protocol. It does not need to
|
|
||||||
be the same as the server name; in fact, it is common for a subdomain of
|
|
||||||
the server name to be the base URL for the Matrix homeserver.
|
|
||||||
.Pp
|
|
||||||
This URL is the URL at which Matrix clients will connect to the server,
|
|
||||||
and is thus served as a part of the
|
|
||||||
.Pa .well-known
|
|
||||||
manifest.
|
|
||||||
.Pp
|
|
||||||
This directive is optional. If it is not specified, it is automatically
|
|
||||||
deduced from the server name.
|
|
||||||
.It Ic identityServer Ar url
|
|
||||||
The identity server that clients should use to perform identity lookups.
|
|
||||||
.Pp
|
|
||||||
.Ar url
|
|
||||||
follows the same rules as
|
|
||||||
.Ic baseUrl .
|
|
||||||
.Pp
|
|
||||||
This directive is optional. If it is not specified, it is automatically
|
|
||||||
set to be the same as the base URL.
|
|
||||||
.It Ic runAs Ar uidObj
|
|
||||||
The effective UNIX user and group to drop to after binding to the socket
|
|
||||||
and changing the filesystem root for the process. This only works if
|
|
||||||
Telodendria is running as the root user, and is used as a security mechanism.
|
|
||||||
If this option is set and Telodendria is started as a non-priviledged user,
|
|
||||||
then a warning is printed to the log if that user does not match what's
|
|
||||||
specified here. This directive is optional, but should be used as a sanity
|
|
||||||
check, if nothing more, to make sure the permissions are working properly.
|
|
||||||
.Pp
|
|
||||||
This directive takes an object with the following directives:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ic uid Ar user
|
|
||||||
The UNIX username to drop to. If
|
|
||||||
.Ic runAs
|
|
||||||
is specified, this directive is required.
|
|
||||||
.It Ic gid Ar group
|
|
||||||
The UNIX group to drop to. This directive is optional; if it is not
|
|
||||||
specified, then the value of
|
|
||||||
.Ic uid
|
|
||||||
is copied.
|
|
||||||
.El
|
|
||||||
.Ic log
|
|
||||||
directive is configured to write to a file, the log file will be written
|
|
||||||
in the data directory.
|
|
||||||
.Ar directory
|
|
||||||
should be an absolute path, under which all Telodendria data will live.
|
|
||||||
.It Ic federation Ar true|false
|
|
||||||
Whether to enable federation with other Matrix homeservers or not. Matrix is
|
|
||||||
by its very nature a federated protocol, but if you just want to run your
|
|
||||||
own internal chat server with no contact with the outside, then you can use
|
|
||||||
this option to disable federation. It is highly recommended to set this to
|
|
||||||
.Ar true ,
|
|
||||||
however, if you wish to be able to communicate with users on other Matrix
|
|
||||||
servers. This directive is required.
|
|
||||||
.It Ic registration Ar true|false
|
|
||||||
Whether or not to enable new user registration or not. For security and anti-spam
|
|
||||||
reasons, you can set this to
|
|
||||||
.Ar false .
|
|
||||||
If you do, you can still add users via the administrator API. In an ideal world,
|
|
||||||
everyone would run their own homeserver, so no public registration would ever
|
|
||||||
be required. Unfortunately, not everyone has the means to run their own homeserver,
|
|
||||||
especially because of the fact that public IPv4 addresses are becoming increasingly
|
|
||||||
harder to come by. If you would like to provide a service to those that are unable
|
|
||||||
to run their own homeserver, you can set this to
|
|
||||||
.Ar true ,
|
|
||||||
which will allow anyone to create an account. Telodendria should be capable of handling
|
|
||||||
a large amount of users without difficulty or security issues. This directive is
|
|
||||||
required.
|
|
||||||
.It Ic log Ar logObj
|
|
||||||
The log file configuration. Telodendria uses its own logging facility, which can
|
|
||||||
output logs to standard output, a file, or the syslog. This directive is required,
|
|
||||||
and it takes an object with the following directives:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ic output Ar stdout|file|syslog
|
|
||||||
The lot output destination. If set to
|
|
||||||
.Ar file ,
|
|
||||||
Telodendria will log to
|
|
||||||
.Pa telodendria.log
|
|
||||||
inside the data directory.
|
|
||||||
.It Ic level Ar error|warning|notice|message|debug
|
|
||||||
The level of messages to log at. Each level shows all the levels above it. For
|
|
||||||
example, setting the level to
|
|
||||||
.Ar error
|
|
||||||
will show only errors, while setting the level to
|
|
||||||
.Ar warning
|
|
||||||
will show warnings and errors.
|
|
||||||
.Ar notice
|
|
||||||
shows notices, warnings, and errors, and so on. The
|
|
||||||
.Ar debug
|
|
||||||
level shows all messages.
|
|
||||||
.It Ic timestampFormat Ar format|none|default
|
|
||||||
If you want to customize the timestamp format shown in the log, or disable it
|
|
||||||
altogether, you can do so via this option. Acceptable values are
|
|
||||||
.Ar none ,
|
|
||||||
.Ar default ,
|
|
||||||
or a formatter string as described by your system's
|
|
||||||
.Xr strftime 3 .
|
|
||||||
This option only applies if
|
|
||||||
.Ic log
|
|
||||||
is "stdout" or "file".
|
|
||||||
.It Ic color Ar true|false
|
|
||||||
Whether or not to enable colored output on TTYs. Note that ANSI color sequences
|
|
||||||
will not be written to a log file, only a real terminal, so this option only
|
|
||||||
applies if the log is being written to a standard output which is connected to
|
|
||||||
a terminal.
|
|
||||||
.Pp
|
|
||||||
This option only applies if
|
|
||||||
.Ic log
|
|
||||||
is "stdout".
|
|
||||||
.El
|
|
||||||
.It Ic threads Ar count
|
|
||||||
How many worker threads to spin up to handle requests. This should generally be
|
|
||||||
less than the total CPU core count, to prevent overloading the system. The most
|
|
||||||
efficient number of threads ultimately depends on the configuration of the
|
|
||||||
machine running Telodendria, so you may just have to play around with different
|
|
||||||
values here to see which gives the best performance.
|
|
||||||
.It Ic maxConnections Ar count
|
|
||||||
The maximum number of simultanious connections to allow to the daemon. This option
|
|
||||||
prevents the daemon from allocating large amounts of memory in the event that it
|
|
||||||
undergoes a denial of service attack. It typically does not need to be adjusted.
|
|
||||||
.It Ic maxCache Ar bytes
|
|
||||||
The maximum size of the cache. Telodendria relies heavily on caching to speed
|
|
||||||
things up. The cache grows as data is loaded from the data directory. All cache
|
|
||||||
is stored in memory. This option limits the size of the memory cache. If you have
|
|
||||||
a system that has a lot of memory, you'll get better performance if this option
|
|
||||||
is set higher. Otherwise, this value should be lowered on systems that have
|
|
||||||
minimal memory available.
|
|
||||||
.El
|
|
||||||
.Sh FILES
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Pa config.json
|
|
||||||
The configuration file stored on the filesystem in the data
|
|
||||||
directory. It is not recommended to edit this directly.
|
|
||||||
.It Pa /var/telodendria
|
|
||||||
The recommended data directory.
|
|
||||||
.El
|
|
||||||
.Sh EXAMPLES
|
|
||||||
.Pp
|
|
||||||
A number of example configuration files are shipped with
|
|
||||||
Telodendria's source code. They can be found in the
|
|
||||||
.Pa contrib/
|
|
||||||
directory if you are viewing the source code directly. Otherwise,
|
|
||||||
if you installed Telodendria as a package, it is possible that the
|
|
||||||
example configurations were placed in the default locations for
|
|
||||||
such files on your operating system.
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr telodendria-setup 7 ,
|
|
||||||
.Xr telodendria-admin 7
|
|
||||||
.Xr telodendria 8
|
|
|
@ -1,268 +0,0 @@
|
||||||
.Dd $Mdocdate: March 10 2023 $
|
|
||||||
.Dt TELODENDRIA-CONTRIBUTING 7
|
|
||||||
.Os Telodendria Project
|
|
||||||
.Sh NAME
|
|
||||||
.Nm telodendria-contributing
|
|
||||||
.Nd Guide to contributing to the Telodendria project.
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
Telodendria is an open source project. As such, it welcomes
|
|
||||||
contributions. There are many ways you can contribute, and any
|
|
||||||
way you can is greatly appreciated. This page contains some of
|
|
||||||
the ways you can help out.
|
|
||||||
.Sh REPORTING ISSUES
|
|
||||||
Please reach out to the Matrix rooms mentioned at the top of
|
|
||||||
.Xr telodendria 7 .
|
|
||||||
All issue tracking takes place in those rooms. Start by reaching
|
|
||||||
out to the general room, and if you think there's a legitimate
|
|
||||||
problem with Telodendria itself, then stick the issue in the
|
|
||||||
issues room, where it can be discussed further. Issues usually
|
|
||||||
remain in the Matrix rooms, but severe enough issues may be put
|
|
||||||
in a
|
|
||||||
.Pa TODO
|
|
||||||
file in the
|
|
||||||
.Xr cvs 1
|
|
||||||
repository so that they don't get lost.
|
|
||||||
.Sh DEVELOPING
|
|
||||||
The primary language used to write Telodendria code is ANSI C.
|
|
||||||
Other languages you'll find in the Telodendria repository include
|
|
||||||
shell scripts,
|
|
||||||
.Xr mdoc 7 ,
|
|
||||||
and a little bit of HTML and CSS. If you have any experience with
|
|
||||||
any of these languages, your contributions are valuable! Please follow
|
|
||||||
the guidelines on this page to ensure the contribution workflow goes
|
|
||||||
as smoothly as possible.
|
|
||||||
.Ss Getting the Code
|
|
||||||
If you'd like to hack on Telodendria, you'll need the following tools
|
|
||||||
in addition to a C compiler and POSIX shell:
|
|
||||||
.Bl -tag
|
|
||||||
.It Xr cvs 1
|
|
||||||
For checking out and updating your local copy of the source code.
|
|
||||||
.It Xr indent 1
|
|
||||||
For formatting your code before generating patches.
|
|
||||||
.It Xr patch 1
|
|
||||||
For applying patches to your local copy of the source code.
|
|
||||||
.El
|
|
||||||
.sp
|
|
||||||
All of these tools are built into OpenBSD. While you don't have to
|
|
||||||
use OpenBSD to develop Telodendria, it may make the process a bit
|
|
||||||
easier. In fact, these tools where chosen precisely because they
|
|
||||||
were built into my operating system of choice.
|
|
||||||
.sp
|
|
||||||
You can download an official release tarball from the website if
|
|
||||||
you would really like, but the preferred way to get the source
|
|
||||||
code for development is to check it out from CVS. This makes generating
|
|
||||||
patches a lot easier.
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ cvs -d anoncvs@bancino.net:/cvs checkout -P Telodendria
|
|
||||||
$ cd Telodendria
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
If you already checked out the code previously, make sure you update
|
|
||||||
your local copy before you start developing:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ cvs -q update -dP
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
You should now have the latest source code. Follow the
|
|
||||||
.Sx CODE STYLE
|
|
||||||
as you make your changes. If the
|
|
||||||
.Xr cvs 1
|
|
||||||
command fails with a "Connection refused" error message, try setting
|
|
||||||
the
|
|
||||||
.Ev CVS_RSH
|
|
||||||
environment variable to "ssh", like this:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ export CVS_RSH=ssh
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
Then run the checkout command again. Some versions of CVS on some
|
|
||||||
systems don't use SSH to checkout by default, so if yours doesn't,
|
|
||||||
you might want to put the above line into your shell init script.
|
|
||||||
.Ss Submitting Patches
|
|
||||||
Telodendria aims at remaining as minimal as possible. This doesn't just
|
|
||||||
mean minimal code, it also means a minimal development process, which is
|
|
||||||
why Telodendria doesn't use GitHub, GitLab, or even SourceHut. Instead,
|
|
||||||
the contribution workflow operates on submitting patch files to a public
|
|
||||||
Matrix room, sort of like the OpenBSD project operates on patch files
|
|
||||||
sent to a public mailing list.
|
|
||||||
.sp
|
|
||||||
If you're not used to manually creating and submitting patches instead of
|
|
||||||
just opening a "pull request," you should be pleased to hear that submitting
|
|
||||||
patches is fairly easy to do if you've got the CVS sources checked out. In
|
|
||||||
fact, I find it easier than having to make a GitHub account, forking a
|
|
||||||
project's repository, and then making a pull request for it. Once you have
|
|
||||||
made your changes in your local copy of the code, and you've configured your
|
|
||||||
environment properly as noted in the manual for
|
|
||||||
.Xr td 1 ,
|
|
||||||
just run the patch recipe:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
$ td patch
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
This will automatically generate a patch file for all your changes, and then
|
|
||||||
open it in your preferred editor. You can also generate a patch file for only
|
|
||||||
certain files and directories. To do that, set
|
|
||||||
.Ev PATCHSET ,
|
|
||||||
like this:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
# Only write a patch for README.txt and the files in docs/
|
|
||||||
$ PATCHSET="README.txt docs/" td patch
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
As you'll notice, the top of the patch file should have some email-style
|
|
||||||
headers that look like this:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
From: Jordan Bancino <@jordan:bancino.net>
|
|
||||||
Date: Fri Jul 29 03:21:21 PM EDT 2022
|
|
||||||
Subject: Document Patch Procedure
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
As much information should be filled out for you, such as the date. An
|
|
||||||
attempt to fill out the From header was also made by
|
|
||||||
.Xr td 1 ,
|
|
||||||
but the information there can be modifed as necessary. Consult the manual
|
|
||||||
for
|
|
||||||
.Xr td 1
|
|
||||||
for more details. The Subject should very briefly describe what the patch
|
|
||||||
is about.
|
|
||||||
.sp
|
|
||||||
You'll also notice these lines in the patch:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
[ ] I have read the Telodendria Project development certificate of
|
|
||||||
origin, and certify that I have permission to submit this patch
|
|
||||||
under the conditions specified in it.
|
|
||||||
.Ed
|
|
||||||
.sp
|
|
||||||
This is a checkbox that tells me whether or not you actually have the
|
|
||||||
rights to submit your patch, and that once you submit your patch, your
|
|
||||||
code is bound by the Telodendria project license, which you can and
|
|
||||||
should view in
|
|
||||||
.Xr telodendria 7 .
|
|
||||||
The full text of the developer certificate of origin is as follows:
|
|
||||||
.Bl -enum
|
|
||||||
.It
|
|
||||||
The contribution was created in whole or in part by me, and I have the right
|
|
||||||
to submit it under the open source licenses of the Telodendria project; or
|
|
||||||
.It
|
|
||||||
The contribution is based upon a previous work that, to the best of my knowledge,
|
|
||||||
is covered under an appropriate open source license and I have the right under
|
|
||||||
that license to submit that work with modifications, whether created in whole
|
|
||||||
or in part by me, under the Telodendria project license; or
|
|
||||||
.It
|
|
||||||
The contribution whas provided directly to me by some other person who certified
|
|
||||||
(1), (2), or (3), and I have not modifed it.
|
|
||||||
.It
|
|
||||||
I understand and agree that this project and the contribution are made public
|
|
||||||
and that a record of the contribution\(emincluding all personal information
|
|
||||||
I submit with it\(emis maintained indefinitely and may be redistributed
|
|
||||||
consistent with this project or the open source licenses involved.
|
|
||||||
.El
|
|
||||||
.sp
|
|
||||||
If you agree to the above, fill in the square brackets with an 'x', and then after
|
|
||||||
the headers, but before the checkbox, write a more thorough description of the
|
|
||||||
patch and why it was created. Then, send the resulting patch file to the public
|
|
||||||
Matrix room using
|
|
||||||
.Xr send-patch 1 .
|
|
||||||
.sp
|
|
||||||
Try to keep your patches on topic\(emmake one patch file per feature or bug fix
|
|
||||||
being implemented. It is okay if your patches depend on previous patches, just
|
|
||||||
indicate that in the patch description. Note that it may take a while for
|
|
||||||
patches to be committed, and some patches may not be comitted at all. In either
|
|
||||||
case, all sent patches are queued from the Matrix room into the public patch
|
|
||||||
directory, so they can be referenced easier in the future. If you want to
|
|
||||||
reference a submitted patch in a Matrix message, email, or other digital medium,
|
|
||||||
it might be a good idea to link to it in the public patch directory.
|
|
||||||
.sp
|
|
||||||
The public patch directory works as follows: when you send your patch to the
|
|
||||||
Matrix room, it is downloaded by Telodendria Bot and placed in the
|
|
||||||
.Pa ingress/
|
|
||||||
directory, named as the message ID. Then, it is assigned a patch ID and
|
|
||||||
copied to the
|
|
||||||
.Pa p/
|
|
||||||
directory as just "%d.patch", where "%d" is obviously the patch ID. This is
|
|
||||||
a permanent link that will always reference your patch. Then, your patch will
|
|
||||||
be symlinked into the
|
|
||||||
.Pa queue/
|
|
||||||
directory. I have a script that automatically ingresses patches and queues them
|
|
||||||
for me, and I use this to review patches. If your patch is accepted, the queue
|
|
||||||
symlink will be moved to
|
|
||||||
.Pa accepted/
|
|
||||||
and the submitted patch will be committed to the official CVS repository.
|
|
||||||
If your patch is rejected for some reason, its symlink will be moved to the
|
|
||||||
.Pa rejected/
|
|
||||||
directory. Regardless of the state of your patch, it will always remain
|
|
||||||
permalinked in the
|
|
||||||
.Pa p/
|
|
||||||
directory, and when it is accepted or rejected, Telodendria Bot will send a
|
|
||||||
message to the Matrix room.
|
|
||||||
.sp
|
|
||||||
You're always welcome to inquire about rejected patches, and request that they
|
|
||||||
be reviewed again, or you can use them as a starting point for future patches.
|
|
||||||
.sp
|
|
||||||
The public patch directory is located at
|
|
||||||
.Lk https://telodendria.io/patches/
|
|
||||||
.Sh CODE STYLE
|
|
||||||
In general, these are the conventions used by the code base. This guide
|
|
||||||
may be slightly outdated or subject to change, but it should be a good
|
|
||||||
start. The source code itself is always the absolute source of truth, so
|
|
||||||
as long as you make your code look like the code surrounding it, you should
|
|
||||||
be fine.
|
|
||||||
.Bl -bullet
|
|
||||||
.It
|
|
||||||
All function, enumeration, structure, and header names are CamelCase. This
|
|
||||||
is preferred to snake_case because it is more compact.
|
|
||||||
.It
|
|
||||||
All variable names are lowerCamelCase. This is preferred to snake_case
|
|
||||||
because it is more compact.
|
|
||||||
.It
|
|
||||||
enumerations and structures are always typedef-ed to their same name. The
|
|
||||||
typedef should occur in the public API header, and the actual declaration
|
|
||||||
should live in the implementation file.
|
|
||||||
.It
|
|
||||||
A feature of the code base lives in a single C source file that has a
|
|
||||||
matching header. The header file should only export public symbols;
|
|
||||||
everything else in the C source should be static.
|
|
||||||
.It
|
|
||||||
Except where absolutely necessary, global variables are forbidden to
|
|
||||||
prevent problems with threads and whatnot. Every variable a function
|
|
||||||
needs should be passed to it either through a structure, or as a
|
|
||||||
separate argument.
|
|
||||||
.It
|
|
||||||
Anywhere curly braces are optional, there still must be curly braces. This
|
|
||||||
makes it easier to add on to the code later, and just makes things a bit
|
|
||||||
less ambiguous.
|
|
||||||
.El
|
|
||||||
.sp
|
|
||||||
As far as actually formatting the code goes, such as where to put brackets,
|
|
||||||
and whether or not to use tabs or spaces, use
|
|
||||||
.Xr indent 1
|
|
||||||
to take care of all of that. The root of the CVS repository has a
|
|
||||||
.Pa .indent.pro
|
|
||||||
that should automatically be loaded by
|
|
||||||
.Xr indent 1
|
|
||||||
to set the correct rules. If you don't have a working
|
|
||||||
.Xr indent 1 ,
|
|
||||||
then just indicate in your patch that I should run my
|
|
||||||
.Xr indent 1
|
|
||||||
on the code after applying it. Although in reality, I'll likely
|
|
||||||
run my own
|
|
||||||
.Xr indent 1
|
|
||||||
on the code anyway, just to make sure the spacing is consistent, if nothing
|
|
||||||
else.
|
|
||||||
.Pp
|
|
||||||
This project places a strong emphasis on documentation. Well-documented
|
|
||||||
code is fundamental to a successful project, so when you are writing code,
|
|
||||||
please also make sure it is documented appropriately.
|
|
||||||
.Bl -bullet
|
|
||||||
.It
|
|
||||||
If you are adding a header, make sure you add a man page that documents
|
|
||||||
all the functions in the header.
|
|
||||||
.It
|
|
||||||
If you're adding a function, make sure you add documentation for it
|
|
||||||
to the appropriate man page for the header that your function resides
|
|
||||||
in. Do note that you do not have to document static functions, only
|
|
||||||
public API functions.
|
|
||||||
.El
|
|
||||||
.Pp
|
|
||||||
If your patch does not also include proper documentation, it will
|
|
||||||
likely be rejected.
|
|
|
@ -71,6 +71,7 @@ RouterBuild(void)
|
||||||
|
|
||||||
R("/_matrix/client/v3/profile/(.*)", RouteUserProfile);
|
R("/_matrix/client/v3/profile/(.*)", RouteUserProfile);
|
||||||
R("/_matrix/client/v3/profile/(.*)/(avatar_url|displayname)", RouteUserProfile);
|
R("/_matrix/client/v3/profile/(.*)/(avatar_url|displayname)", RouteUserProfile);
|
||||||
|
R("/_matrix/client/v3/user_directory/search", RouteUserDirectory);
|
||||||
|
|
||||||
R("/_matrix/client/v3/user/(.*)/filter", RouteFilter);
|
R("/_matrix/client/v3/user/(.*)/filter", RouteFilter);
|
||||||
R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter);
|
R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter);
|
||||||
|
|
213
src/Routes/RouteUserDirectory.c
Normal file
213
src/Routes/RouteUserDirectory.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <Routes.h>
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Json.h>
|
||||||
|
#include <Str.h>
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <User.h>
|
||||||
|
#include <Db.h>
|
||||||
|
|
||||||
|
ROUTE_IMPL(RouteUserDirectory, path, argp)
|
||||||
|
{
|
||||||
|
RouteArgs *args = argp;
|
||||||
|
HashMap *response = NULL;
|
||||||
|
HashMap *request = NULL;
|
||||||
|
|
||||||
|
Array *users = NULL;
|
||||||
|
Array *results = NULL;
|
||||||
|
|
||||||
|
Db *db = args->matrixArgs->db;
|
||||||
|
|
||||||
|
Config *config = NULL;
|
||||||
|
|
||||||
|
User *user = NULL;
|
||||||
|
|
||||||
|
JsonValue *val = NULL;
|
||||||
|
|
||||||
|
char *token = NULL;
|
||||||
|
char *searchTerm = NULL;
|
||||||
|
char *requesterName = NULL;
|
||||||
|
|
||||||
|
char *error;
|
||||||
|
|
||||||
|
size_t limit = 10;
|
||||||
|
|
||||||
|
size_t i, included;
|
||||||
|
|
||||||
|
(void) path;
|
||||||
|
|
||||||
|
|
||||||
|
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
response = MatrixErrorCreate(M_UNRECOGNIZED, NULL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
request = JsonDecode(HttpServerStream(args->context));
|
||||||
|
if (!request)
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
response = MatrixErrorCreate(M_NOT_JSON, NULL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
response = MatrixGetAccessToken(args->context, &token);
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Actually use information related to the user. */
|
||||||
|
user = UserAuthenticate(db, token);
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
requesterName = UserGetName(user);
|
||||||
|
|
||||||
|
/* Parse limit and search_term */
|
||||||
|
if (!(val = JsonGet(request, 1, "search_term")) ||
|
||||||
|
JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
/* The Spec requires search_term to be set to a string. */
|
||||||
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
|
error = "search_term is not a string, or is non-existent";
|
||||||
|
response = MatrixErrorCreate(M_BAD_JSON, error);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
searchTerm = StrLower(JsonValueAsString(val));
|
||||||
|
|
||||||
|
if ((val = JsonGet(request, 1, "limit")) &&
|
||||||
|
JsonValueType(val) == JSON_INTEGER)
|
||||||
|
{
|
||||||
|
/* It is however far more leinent on limit, with 10 by default. */
|
||||||
|
limit = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
response = HashMapCreate();
|
||||||
|
results = ArrayCreate();
|
||||||
|
|
||||||
|
/* TODO: Check for users matching search term and users outside our
|
||||||
|
* local server. */
|
||||||
|
users = DbList(db, 1, "users");
|
||||||
|
|
||||||
|
|
||||||
|
/* Offending line? */
|
||||||
|
config = ConfigLock(db);
|
||||||
|
if (!config)
|
||||||
|
{
|
||||||
|
error = "Directory endpoint failed to lock configuration.";
|
||||||
|
Log(LOG_ERR, error);
|
||||||
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
response = MatrixErrorCreate(M_UNKNOWN, error);
|
||||||
|
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, included = 0; i < ArraySize(users) && included < limit; i++)
|
||||||
|
{
|
||||||
|
HashMap *obj;
|
||||||
|
User *currentUser;
|
||||||
|
char *name = ArrayGet(users, i);
|
||||||
|
char *displayName;
|
||||||
|
char *lowerDisplayName;
|
||||||
|
char *avatarUrl;
|
||||||
|
|
||||||
|
if (!StrEquals(name, requesterName))
|
||||||
|
{
|
||||||
|
currentUser = UserLock(db, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentUser = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayName = UserGetProfile(currentUser, "displayname");
|
||||||
|
lowerDisplayName = StrLower(displayName);
|
||||||
|
avatarUrl = UserGetProfile(currentUser, "avatar_url");
|
||||||
|
|
||||||
|
/* Check for the user ID and display name. */
|
||||||
|
if (strstr(name, searchTerm) ||
|
||||||
|
(lowerDisplayName && strstr(lowerDisplayName, searchTerm)))
|
||||||
|
{
|
||||||
|
included++;
|
||||||
|
|
||||||
|
obj = HashMapCreate();
|
||||||
|
if (displayName)
|
||||||
|
{
|
||||||
|
JsonSet(obj, JsonValueString(displayName), 1, "display_name");
|
||||||
|
}
|
||||||
|
if (avatarUrl)
|
||||||
|
{
|
||||||
|
JsonSet(obj, JsonValueString(displayName), 1, "avatar_url");
|
||||||
|
}
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
char *userID = StrConcat(4, "@", name, ":", config->serverName);
|
||||||
|
JsonSet(obj, JsonValueString(userID), 1, "user_id");
|
||||||
|
Free(userID);
|
||||||
|
}
|
||||||
|
ArrayAdd(results, JsonValueObject(obj));
|
||||||
|
}
|
||||||
|
if (lowerDisplayName)
|
||||||
|
{
|
||||||
|
Free(lowerDisplayName);
|
||||||
|
}
|
||||||
|
if (!StrEquals(name, requesterName))
|
||||||
|
{
|
||||||
|
UserUnlock(currentUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JsonSet(response, JsonValueArray(results), 1, "results");
|
||||||
|
JsonSet(response, JsonValueBoolean(included == limit), 1, "limited");
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (user)
|
||||||
|
{
|
||||||
|
UserUnlock(user);
|
||||||
|
}
|
||||||
|
if (request)
|
||||||
|
{
|
||||||
|
JsonFree(request);
|
||||||
|
}
|
||||||
|
if (searchTerm)
|
||||||
|
{
|
||||||
|
Free(searchTerm);
|
||||||
|
}
|
||||||
|
if (users)
|
||||||
|
{
|
||||||
|
DbListFree(users);
|
||||||
|
}
|
||||||
|
if (config)
|
||||||
|
{
|
||||||
|
ConfigUnlock(config);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
|
@ -172,7 +172,10 @@ ROUTE_IMPL(RouteUserProfile, path, argp)
|
||||||
}
|
}
|
||||||
finish:
|
finish:
|
||||||
ConfigUnlock(config);
|
ConfigUnlock(config);
|
||||||
Free(username);
|
|
||||||
|
/* Username is handled by the router, freeing it *will* cause issues
|
||||||
|
* (see #33). I honestly don't know how it didn't come to bite us sooner.
|
||||||
|
Free(username); */
|
||||||
Free(entry);
|
Free(entry);
|
||||||
UserIdFree(userId);
|
UserIdFree(userId);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
|
|
299
src/Schema/ClientEvent.c
Normal file
299
src/Schema/ClientEvent.c
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#include <Schema/ClientEvent.h>
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <Json.h>
|
||||||
|
#include <Str.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
ClientEventUnsignedDataFromJson(HashMap *json, ClientEventUnsignedData *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to ClientEventUnsignedDataFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "redacted_because");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "ClientEventUnsignedData.redacted_because must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->redacted_because = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "transaction_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEventUnsignedData.transaction_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->transaction_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "prev_content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "ClientEventUnsignedData.prev_content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->prev_content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "age");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "ClientEventUnsignedData.age must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->age = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
ClientEventUnsignedDataToJson(ClientEventUnsignedData *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "redacted_because", JsonValueObject(JsonDuplicate(val->redacted_because)));
|
||||||
|
HashMapSet(json, "transaction_id", JsonValueString(val->transaction_id));
|
||||||
|
HashMapSet(json, "prev_content", JsonValueObject(JsonDuplicate(val->prev_content)));
|
||||||
|
HashMapSet(json, "age", JsonValueInteger(val->age));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClientEventUnsignedDataFree(ClientEventUnsignedData *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonFree(val->redacted_because);
|
||||||
|
Free(val->transaction_id);
|
||||||
|
JsonFree(val->prev_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ClientEventFromJson(HashMap *json, ClientEvent *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to ClientEventFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "origin_server_ts");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.origin_server_ts must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->origin_server_ts = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.origin_server_ts is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.content is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "room_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.room_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->room_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.room_id is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "sender");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.sender must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->sender = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.sender is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "state_key");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.state_key must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->state_key = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "event_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.event_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->event_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.event_id is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "type");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.type must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->type = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.type is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "unsigned");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "ClientEvent.unsigned must be of type ClientEventUnsignedData.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ClientEventUnsignedDataFromJson(JsonValueAsObject(val), &out->_unsigned, errp))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
ClientEventToJson(ClientEvent *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "origin_server_ts", JsonValueInteger(val->origin_server_ts));
|
||||||
|
HashMapSet(json, "content", JsonValueObject(JsonDuplicate(val->content)));
|
||||||
|
HashMapSet(json, "room_id", JsonValueString(val->room_id));
|
||||||
|
HashMapSet(json, "sender", JsonValueString(val->sender));
|
||||||
|
HashMapSet(json, "state_key", JsonValueString(val->state_key));
|
||||||
|
HashMapSet(json, "event_id", JsonValueString(val->event_id));
|
||||||
|
HashMapSet(json, "type", JsonValueString(val->type));
|
||||||
|
HashMapSet(json, "unsigned", JsonValueObject(ClientEventUnsignedDataToJson(&val->_unsigned)));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClientEventFree(ClientEvent *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonFree(val->content);
|
||||||
|
Free(val->room_id);
|
||||||
|
Free(val->sender);
|
||||||
|
Free(val->state_key);
|
||||||
|
Free(val->event_id);
|
||||||
|
Free(val->type);
|
||||||
|
ClientEventUnsignedDataFree(&val->_unsigned);
|
||||||
|
}
|
||||||
|
|
1193
src/Schema/Filter.c
Normal file
1193
src/Schema/Filter.c
Normal file
File diff suppressed because it is too large
Load diff
477
src/Schema/PduV1.c
Normal file
477
src/Schema/PduV1.c
Normal file
|
@ -0,0 +1,477 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#include <Schema/PduV1.h>
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <Json.h>
|
||||||
|
#include <Str.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV1EventHashFromJson(HashMap *json, PduV1EventHash *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV1EventHashFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "sha256");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1EventHash.sha256 must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->sha256 = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1EventHash.sha256 is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV1EventHashToJson(PduV1EventHash *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "sha256", JsonValueString(val->sha256));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV1EventHashFree(PduV1EventHash *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(val->sha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV1FromJson(HashMap *json, PduV1 *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV1FromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "origin_server_ts");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.origin_server_ts must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->origin_server_ts = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.origin_server_ts is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.content is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "redacts");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.redacts must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->redacts = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "sender");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.sender must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->sender = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.sender is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "depth");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.depth must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->depth = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.depth is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "prev_events");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.prev_events must be of type array.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->prev_events = JsonValueAsArray(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.prev_events is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "type");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.type must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->type = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.type is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "unsigned");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.unsigned must be of type PduV1UnsignedData.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PduV1UnsignedDataFromJson(JsonValueAsObject(val), &out->_unsigned, errp))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "auth_events");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.auth_events must be of type array.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->auth_events = JsonValueAsArray(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.auth_events is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "room_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.room_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->room_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.room_id is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "state_key");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.state_key must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->state_key = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "signatures");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.signatures must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->signatures = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.signatures is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "event_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.event_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->event_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.event_id is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "hashes");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV1.hashes must be of type PduV1EventHash.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PduV1EventHashFromJson(JsonValueAsObject(val), &out->hashes, errp))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV1.hashes is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV1ToJson(PduV1 *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "origin_server_ts", JsonValueInteger(val->origin_server_ts));
|
||||||
|
HashMapSet(json, "content", JsonValueObject(JsonDuplicate(val->content)));
|
||||||
|
HashMapSet(json, "redacts", JsonValueString(val->redacts));
|
||||||
|
HashMapSet(json, "sender", JsonValueString(val->sender));
|
||||||
|
HashMapSet(json, "depth", JsonValueInteger(val->depth));
|
||||||
|
if (val->prev_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->prev_events); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueDuplicate(ArrayGet(val->prev_events, i)));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "prev_events", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "type", JsonValueString(val->type));
|
||||||
|
HashMapSet(json, "unsigned", JsonValueObject(PduV1UnsignedDataToJson(&val->_unsigned)));
|
||||||
|
if (val->auth_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->auth_events); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueDuplicate(ArrayGet(val->auth_events, i)));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "auth_events", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "room_id", JsonValueString(val->room_id));
|
||||||
|
HashMapSet(json, "state_key", JsonValueString(val->state_key));
|
||||||
|
HashMapSet(json, "signatures", JsonValueObject(JsonDuplicate(val->signatures)));
|
||||||
|
HashMapSet(json, "event_id", JsonValueString(val->event_id));
|
||||||
|
HashMapSet(json, "hashes", JsonValueObject(PduV1EventHashToJson(&val->hashes)));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV1Free(PduV1 *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonFree(val->content);
|
||||||
|
Free(val->redacts);
|
||||||
|
Free(val->sender);
|
||||||
|
if (val->prev_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->prev_events); i++)
|
||||||
|
{
|
||||||
|
JsonValueFree(ArrayGet(val->prev_events, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->prev_events);
|
||||||
|
}
|
||||||
|
Free(val->type);
|
||||||
|
PduV1UnsignedDataFree(&val->_unsigned);
|
||||||
|
if (val->auth_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->auth_events); i++)
|
||||||
|
{
|
||||||
|
JsonValueFree(ArrayGet(val->auth_events, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->auth_events);
|
||||||
|
}
|
||||||
|
Free(val->room_id);
|
||||||
|
Free(val->state_key);
|
||||||
|
JsonFree(val->signatures);
|
||||||
|
Free(val->event_id);
|
||||||
|
PduV1EventHashFree(&val->hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV1UnsignedDataFromJson(HashMap *json, PduV1UnsignedData *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV1UnsignedDataFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "age");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV1UnsignedData.age must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->age = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV1UnsignedDataToJson(PduV1UnsignedData *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "age", JsonValueInteger(val->age));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV1UnsignedDataFree(PduV1UnsignedData *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
500
src/Schema/PduV3.c
Normal file
500
src/Schema/PduV3.c
Normal file
|
@ -0,0 +1,500 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#include <Schema/PduV3.h>
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <Json.h>
|
||||||
|
#include <Str.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV3EventHashFromJson(HashMap *json, PduV3EventHash *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV3EventHashFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "sha256");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3EventHash.sha256 must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->sha256 = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3EventHash.sha256 is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV3EventHashToJson(PduV3EventHash *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "sha256", JsonValueString(val->sha256));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV3EventHashFree(PduV3EventHash *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(val->sha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV3FromJson(HashMap *json, PduV3 *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV3FromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "origin_server_ts");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.origin_server_ts must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->origin_server_ts = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.origin_server_ts is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.content is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "redacts");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.redacts must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->redacts = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "sender");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.sender must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->sender = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.sender is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "depth");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.depth must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->depth = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.depth is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "prev_events");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.prev_events must be of type [string].";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->prev_events = ArrayCreate();
|
||||||
|
if (!out->prev_events)
|
||||||
|
{
|
||||||
|
*errp = "Failed to allocate memory for PduV3.prev_events.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array *arr = JsonValueAsArray(val);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i <ArraySize(arr); i++)
|
||||||
|
{
|
||||||
|
JsonValue *v = ArrayGet(arr, i);
|
||||||
|
if (JsonValueType(v) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.prev_events[] contains an invalid value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArrayAdd(out->prev_events, StrDuplicate(JsonValueAsString(v)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.prev_events is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "type");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.type must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->type = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.type is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "unsigned");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.unsigned must be of type PduV3UnsignedData.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PduV3UnsignedDataFromJson(JsonValueAsObject(val), &out->_unsigned, errp))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "auth_events");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.auth_events must be of type [string].";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->auth_events = ArrayCreate();
|
||||||
|
if (!out->auth_events)
|
||||||
|
{
|
||||||
|
*errp = "Failed to allocate memory for PduV3.auth_events.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array *arr = JsonValueAsArray(val);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i <ArraySize(arr); i++)
|
||||||
|
{
|
||||||
|
JsonValue *v = ArrayGet(arr, i);
|
||||||
|
if (JsonValueType(v) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.auth_events[] contains an invalid value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArrayAdd(out->auth_events, StrDuplicate(JsonValueAsString(v)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.auth_events is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "room_id");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.room_id must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->room_id = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.room_id is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "state_key");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.state_key must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->state_key = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "signatures");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.signatures must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->signatures = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.signatures is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "hashes");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "PduV3.hashes must be of type PduV3EventHash.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PduV3EventHashFromJson(JsonValueAsObject(val), &out->hashes, errp))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "PduV3.hashes is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV3ToJson(PduV3 *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "origin_server_ts", JsonValueInteger(val->origin_server_ts));
|
||||||
|
HashMapSet(json, "content", JsonValueObject(JsonDuplicate(val->content)));
|
||||||
|
HashMapSet(json, "redacts", JsonValueString(val->redacts));
|
||||||
|
HashMapSet(json, "sender", JsonValueString(val->sender));
|
||||||
|
HashMapSet(json, "depth", JsonValueInteger(val->depth));
|
||||||
|
if (val->prev_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->prev_events); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->prev_events, i)));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "prev_events", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "type", JsonValueString(val->type));
|
||||||
|
HashMapSet(json, "unsigned", JsonValueObject(PduV3UnsignedDataToJson(&val->_unsigned)));
|
||||||
|
if (val->auth_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->auth_events); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->auth_events, i)));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "auth_events", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "room_id", JsonValueString(val->room_id));
|
||||||
|
HashMapSet(json, "state_key", JsonValueString(val->state_key));
|
||||||
|
HashMapSet(json, "signatures", JsonValueObject(JsonDuplicate(val->signatures)));
|
||||||
|
HashMapSet(json, "hashes", JsonValueObject(PduV3EventHashToJson(&val->hashes)));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV3Free(PduV3 *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonFree(val->content);
|
||||||
|
Free(val->redacts);
|
||||||
|
Free(val->sender);
|
||||||
|
if (val->prev_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->prev_events); i++)
|
||||||
|
{
|
||||||
|
Free(ArrayGet(val->prev_events, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->prev_events);
|
||||||
|
}
|
||||||
|
Free(val->type);
|
||||||
|
PduV3UnsignedDataFree(&val->_unsigned);
|
||||||
|
if (val->auth_events)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->auth_events); i++)
|
||||||
|
{
|
||||||
|
Free(ArrayGet(val->auth_events, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->auth_events);
|
||||||
|
}
|
||||||
|
Free(val->room_id);
|
||||||
|
Free(val->state_key);
|
||||||
|
JsonFree(val->signatures);
|
||||||
|
PduV3EventHashFree(&val->hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PduV3UnsignedDataFromJson(HashMap *json, PduV3UnsignedData *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to PduV3UnsignedDataFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "age");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_INTEGER)
|
||||||
|
{
|
||||||
|
*errp = "PduV3UnsignedData.age must be of type integer.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->age = JsonValueAsInteger(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
PduV3UnsignedDataToJson(PduV3UnsignedData *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "age", JsonValueInteger(val->age));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PduV3UnsignedDataFree(PduV3UnsignedData *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
712
src/Schema/RoomCreateRequest.c
Normal file
712
src/Schema/RoomCreateRequest.c
Normal file
|
@ -0,0 +1,712 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#include <Schema/RoomCreateRequest.h>
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <Json.h>
|
||||||
|
#include <Str.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
RoomVisibilityFromStr(char *str)
|
||||||
|
{
|
||||||
|
if (StrEquals(str, "public"))
|
||||||
|
{
|
||||||
|
return ROOM_PUBLIC;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "private"))
|
||||||
|
{
|
||||||
|
return ROOM_PRIVATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
RoomVisibilityToStr(RoomVisibility val)
|
||||||
|
{
|
||||||
|
switch (val)
|
||||||
|
{
|
||||||
|
case ROOM_PUBLIC:
|
||||||
|
return "public";
|
||||||
|
case ROOM_PRIVATE:
|
||||||
|
return "private";
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RoomCreateRequestFromJson(HashMap *json, RoomCreateRequest *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to RoomCreateRequestFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "invite");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.invite must be of type [string].";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->invite = ArrayCreate();
|
||||||
|
if (!out->invite)
|
||||||
|
{
|
||||||
|
*errp = "Failed to allocate memory for RoomCreateRequest.invite.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array *arr = JsonValueAsArray(val);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i <ArraySize(arr); i++)
|
||||||
|
{
|
||||||
|
JsonValue *v = ArrayGet(arr, i);
|
||||||
|
if (JsonValueType(v) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.invite[] contains an invalid value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArrayAdd(out->invite, StrDuplicate(JsonValueAsString(v)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "room_version");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.room_version must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->room_version = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "invite_3pid");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.invite_3pid must be of type [RoomInvite3Pid].";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->invite_3pid = ArrayCreate();
|
||||||
|
if (!out->invite_3pid)
|
||||||
|
{
|
||||||
|
*errp = "Failed to allocate memory for RoomCreateRequest.invite_3pid.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array *arr = JsonValueAsArray(val);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i <ArraySize(arr); i++)
|
||||||
|
{
|
||||||
|
JsonValue *v = ArrayGet(arr, i);
|
||||||
|
RoomInvite3Pid *parsed;
|
||||||
|
if (JsonValueType(v) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.invite_3pid[] contains an invalid value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
parsed = Malloc(sizeof(RoomInvite3Pid));
|
||||||
|
if (!parsed)
|
||||||
|
{
|
||||||
|
*errp = "Unable to allocate memory for array value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!RoomInvite3PidFromJson(JsonValueAsObject(v), parsed, errp))
|
||||||
|
{
|
||||||
|
RoomInvite3PidFree(parsed);
|
||||||
|
Free(parsed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArrayAdd(out->invite_3pid, parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "topic");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.topic must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->topic = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "visibility");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.visibility must be of type RoomVisibility.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enumParseRes = RoomVisibilityFromStr(JsonValueAsString(val));
|
||||||
|
if (enumParseRes == -1)
|
||||||
|
{
|
||||||
|
*errp = "Invalid value for RoomCreateRequest.visibility.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out->visibility = enumParseRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "creation_content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.creation_content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->creation_content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "is_direct");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_BOOLEAN)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.is_direct must be of type boolean.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->is_direct = JsonValueAsBoolean(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "name");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.name must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->name = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "initial_state");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_ARRAY)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.initial_state must be of type [RoomStateEvent].";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->initial_state = ArrayCreate();
|
||||||
|
if (!out->initial_state)
|
||||||
|
{
|
||||||
|
*errp = "Failed to allocate memory for RoomCreateRequest.initial_state.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array *arr = JsonValueAsArray(val);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i <ArraySize(arr); i++)
|
||||||
|
{
|
||||||
|
JsonValue *v = ArrayGet(arr, i);
|
||||||
|
RoomStateEvent *parsed;
|
||||||
|
if (JsonValueType(v) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.initial_state[] contains an invalid value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
parsed = Malloc(sizeof(RoomStateEvent));
|
||||||
|
if (!parsed)
|
||||||
|
{
|
||||||
|
*errp = "Unable to allocate memory for array value.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!RoomStateEventFromJson(JsonValueAsObject(v), parsed, errp))
|
||||||
|
{
|
||||||
|
RoomStateEventFree(parsed);
|
||||||
|
Free(parsed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArrayAdd(out->initial_state, parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "power_level_content_override");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.power_level_content_override must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->power_level_content_override = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "room_alias_name");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.room_alias_name must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->room_alias_name = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "preset");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomCreateRequest.preset must be of type RoomCreatePreset.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enumParseRes = RoomCreatePresetFromStr(JsonValueAsString(val));
|
||||||
|
if (enumParseRes == -1)
|
||||||
|
{
|
||||||
|
*errp = "Invalid value for RoomCreateRequest.preset.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out->preset = enumParseRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
RoomCreateRequestToJson(RoomCreateRequest *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val->invite)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->invite); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->invite, i)));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "invite", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "room_version", JsonValueString(val->room_version));
|
||||||
|
if (val->invite_3pid)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->invite_3pid); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueObject(RoomInvite3PidToJson(ArrayGet(val->invite_3pid, i))));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "invite_3pid", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "topic", JsonValueString(val->topic));
|
||||||
|
HashMapSet(json, "visibility", JsonValueString(RoomVisibilityToStr(val->visibility)));
|
||||||
|
HashMapSet(json, "creation_content", JsonValueObject(JsonDuplicate(val->creation_content)));
|
||||||
|
HashMapSet(json, "is_direct", JsonValueBoolean(val->is_direct));
|
||||||
|
HashMapSet(json, "name", JsonValueString(val->name));
|
||||||
|
if (val->initial_state)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *jsonArr = ArrayCreate();
|
||||||
|
if (!jsonArr)
|
||||||
|
{
|
||||||
|
JsonFree(json);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(val->initial_state); i++)
|
||||||
|
{
|
||||||
|
ArrayAdd(jsonArr, JsonValueObject(RoomStateEventToJson(ArrayGet(val->initial_state, i))));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "initial_state", JsonValueArray(jsonArr));
|
||||||
|
}
|
||||||
|
HashMapSet(json, "power_level_content_override", JsonValueObject(JsonDuplicate(val->power_level_content_override)));
|
||||||
|
HashMapSet(json, "room_alias_name", JsonValueString(val->room_alias_name));
|
||||||
|
HashMapSet(json, "preset", JsonValueString(RoomCreatePresetToStr(val->preset)));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomCreateRequestFree(RoomCreateRequest *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val->invite)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->invite); i++)
|
||||||
|
{
|
||||||
|
Free(ArrayGet(val->invite, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->invite);
|
||||||
|
}
|
||||||
|
Free(val->room_version);
|
||||||
|
if (val->invite_3pid)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->invite_3pid); i++)
|
||||||
|
{
|
||||||
|
RoomInvite3PidFree(ArrayGet(val->invite_3pid, i));
|
||||||
|
Free(ArrayGet(val->invite_3pid, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->invite_3pid);
|
||||||
|
}
|
||||||
|
Free(val->topic);
|
||||||
|
JsonFree(val->creation_content);
|
||||||
|
Free(val->name);
|
||||||
|
if (val->initial_state)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ArraySize(val->initial_state); i++)
|
||||||
|
{
|
||||||
|
RoomStateEventFree(ArrayGet(val->initial_state, i));
|
||||||
|
Free(ArrayGet(val->initial_state, i));
|
||||||
|
}
|
||||||
|
ArrayFree(val->initial_state);
|
||||||
|
}
|
||||||
|
JsonFree(val->power_level_content_override);
|
||||||
|
Free(val->room_alias_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RoomInvite3PidFromJson(HashMap *json, RoomInvite3Pid *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to RoomInvite3PidFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "id_access_token");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.id_access_token must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->id_access_token = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.id_access_token is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "address");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.address must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->address = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.address is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "medium");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.medium must be of type Room3PidMedium.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enumParseRes = Room3PidMediumFromStr(JsonValueAsString(val));
|
||||||
|
if (enumParseRes == -1)
|
||||||
|
{
|
||||||
|
*errp = "Invalid value for RoomInvite3Pid.medium.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out->medium = enumParseRes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.medium is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "id_server");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.id_server must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->id_server = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomInvite3Pid.id_server is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
RoomInvite3PidToJson(RoomInvite3Pid *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "id_access_token", JsonValueString(val->id_access_token));
|
||||||
|
HashMapSet(json, "address", JsonValueString(val->address));
|
||||||
|
HashMapSet(json, "medium", JsonValueString(Room3PidMediumToStr(val->medium)));
|
||||||
|
HashMapSet(json, "id_server", JsonValueString(val->id_server));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomInvite3PidFree(RoomInvite3Pid *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(val->id_access_token);
|
||||||
|
Free(val->address);
|
||||||
|
Free(val->id_server);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Room3PidMediumFromStr(char *str)
|
||||||
|
{
|
||||||
|
if (StrEquals(str, "msisdn"))
|
||||||
|
{
|
||||||
|
return ROOM_3PID_MSISDN;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "email"))
|
||||||
|
{
|
||||||
|
return ROOM_3PID_EMAIL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
Room3PidMediumToStr(Room3PidMedium val)
|
||||||
|
{
|
||||||
|
switch (val)
|
||||||
|
{
|
||||||
|
case ROOM_3PID_MSISDN:
|
||||||
|
return "msisdn";
|
||||||
|
case ROOM_3PID_EMAIL:
|
||||||
|
return "email";
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RoomCreatePresetFromStr(char *str)
|
||||||
|
{
|
||||||
|
if (StrEquals(str, "public_chat"))
|
||||||
|
{
|
||||||
|
return ROOM_CREATE_PUBLIC;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "trusted_private_chat"))
|
||||||
|
{
|
||||||
|
return ROOM_CREATE_TRUSTED;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "private_chat"))
|
||||||
|
{
|
||||||
|
return ROOM_CREATE_PRIVATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
RoomCreatePresetToStr(RoomCreatePreset val)
|
||||||
|
{
|
||||||
|
switch (val)
|
||||||
|
{
|
||||||
|
case ROOM_CREATE_PUBLIC:
|
||||||
|
return "public_chat";
|
||||||
|
case ROOM_CREATE_TRUSTED:
|
||||||
|
return "trusted_private_chat";
|
||||||
|
case ROOM_CREATE_PRIVATE:
|
||||||
|
return "private_chat";
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RoomStateEventFromJson(HashMap *json, RoomStateEvent *out, char **errp)
|
||||||
|
{
|
||||||
|
JsonValue *val;
|
||||||
|
int enumParseRes;
|
||||||
|
|
||||||
|
(void) enumParseRes;
|
||||||
|
|
||||||
|
if (!json | !out)
|
||||||
|
{
|
||||||
|
*errp = "Invalid pointers passed to RoomStateEventFromJson()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "content");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
*errp = "RoomStateEvent.content must be of type object.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->content = JsonValueAsObject(JsonValueDuplicate(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomStateEvent.content is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "state_key");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomStateEvent.state_key must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->state_key = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(json, "type");
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
if (JsonValueType(val) != JSON_STRING)
|
||||||
|
{
|
||||||
|
*errp = "RoomStateEvent.type must be of type string.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->type = StrDuplicate(JsonValueAsString(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*errp = "RoomStateEvent.type is required.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
RoomStateEventToJson(RoomStateEvent *val)
|
||||||
|
{
|
||||||
|
HashMap *json;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json = HashMapCreate();
|
||||||
|
if (!json)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(json, "content", JsonValueObject(JsonDuplicate(val->content)));
|
||||||
|
HashMapSet(json, "state_key", JsonValueString(val->state_key));
|
||||||
|
HashMapSet(json, "type", JsonValueString(val->type));
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomStateEventFree(RoomStateEvent *val)
|
||||||
|
{
|
||||||
|
if (!val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonFree(val->content);
|
||||||
|
Free(val->state_key);
|
||||||
|
Free(val->type);
|
||||||
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ ROUTE(RouteChangePwd);
|
||||||
ROUTE(RouteDeactivate);
|
ROUTE(RouteDeactivate);
|
||||||
ROUTE(RouteTokenValid);
|
ROUTE(RouteTokenValid);
|
||||||
ROUTE(RouteUserProfile);
|
ROUTE(RouteUserProfile);
|
||||||
|
ROUTE(RouteUserDirectory);
|
||||||
ROUTE(RouteRequestToken);
|
ROUTE(RouteRequestToken);
|
||||||
|
|
||||||
ROUTE(RouteUiaFallback);
|
ROUTE(RouteUiaFallback);
|
||||||
|
|
39
src/include/Schema/ClientEvent.h
Normal file
39
src/include/Schema/ClientEvent.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#ifndef TELODENDRIA_SCHEMA_CLIENTEVENT_H
|
||||||
|
#define TELODENDRIA_SCHEMA_CLIENTEVENT_H
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ClientEventUnsignedData
|
||||||
|
{
|
||||||
|
HashMap * redacted_because;
|
||||||
|
char * transaction_id;
|
||||||
|
HashMap * prev_content;
|
||||||
|
Int64 age;
|
||||||
|
} ClientEventUnsignedData;
|
||||||
|
|
||||||
|
typedef struct ClientEvent
|
||||||
|
{
|
||||||
|
Int64 origin_server_ts;
|
||||||
|
HashMap * content;
|
||||||
|
char * room_id;
|
||||||
|
char * sender;
|
||||||
|
char * state_key;
|
||||||
|
char * event_id;
|
||||||
|
char * type;
|
||||||
|
ClientEventUnsignedData _unsigned;
|
||||||
|
} ClientEvent;
|
||||||
|
|
||||||
|
extern int ClientEventUnsignedDataFromJson(HashMap *, ClientEventUnsignedData *, char **);
|
||||||
|
extern HashMap * ClientEventUnsignedDataToJson(ClientEventUnsignedData *);
|
||||||
|
extern void ClientEventUnsignedDataFree(ClientEventUnsignedData *);
|
||||||
|
|
||||||
|
extern int ClientEventFromJson(HashMap *, ClientEvent *, char **);
|
||||||
|
extern HashMap * ClientEventToJson(ClientEvent *);
|
||||||
|
extern void ClientEventFree(ClientEvent *);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_SCHEMA_CLIENTEVENT_H */
|
80
src/include/Schema/Filter.h
Normal file
80
src/include/Schema/Filter.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#ifndef TELODENDRIA_SCHEMA_FILTER_H
|
||||||
|
#define TELODENDRIA_SCHEMA_FILTER_H
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct FilterEvent
|
||||||
|
{
|
||||||
|
Array * not_senders;
|
||||||
|
Int64 limit;
|
||||||
|
Array * senders;
|
||||||
|
Array * types;
|
||||||
|
Array * not_types;
|
||||||
|
} FilterEvent;
|
||||||
|
|
||||||
|
typedef enum FilterEventFormat
|
||||||
|
{
|
||||||
|
FILTER_FORMAT_FEDERATION,
|
||||||
|
FILTER_FORMANT_CLIENT
|
||||||
|
} FilterEventFormat;
|
||||||
|
|
||||||
|
typedef struct FilterRoomEvent
|
||||||
|
{
|
||||||
|
Array * not_rooms;
|
||||||
|
Array * not_senders;
|
||||||
|
Int64 limit;
|
||||||
|
Array * senders;
|
||||||
|
int include_redundant_members;
|
||||||
|
Array * types;
|
||||||
|
Array * rooms;
|
||||||
|
int lazy_load_members;
|
||||||
|
Array * not_types;
|
||||||
|
int contains_url;
|
||||||
|
int unread_thread_notifications;
|
||||||
|
} FilterRoomEvent;
|
||||||
|
|
||||||
|
typedef struct FilterRoom
|
||||||
|
{
|
||||||
|
Array * not_rooms;
|
||||||
|
FilterRoomEvent state;
|
||||||
|
int include_leave;
|
||||||
|
FilterRoomEvent timeline;
|
||||||
|
FilterRoomEvent account_data;
|
||||||
|
Array * rooms;
|
||||||
|
FilterRoomEvent ephemeral;
|
||||||
|
} FilterRoom;
|
||||||
|
|
||||||
|
typedef struct Filter
|
||||||
|
{
|
||||||
|
FilterEventFormat event_format;
|
||||||
|
FilterEvent presence;
|
||||||
|
FilterEvent account_data;
|
||||||
|
FilterRoom room;
|
||||||
|
Array * event_fields;
|
||||||
|
} Filter;
|
||||||
|
|
||||||
|
extern int FilterRoomFromJson(HashMap *, FilterRoom *, char **);
|
||||||
|
extern HashMap * FilterRoomToJson(FilterRoom *);
|
||||||
|
extern void FilterRoomFree(FilterRoom *);
|
||||||
|
|
||||||
|
extern int FilterEventFormatFromStr(char *);
|
||||||
|
extern char * FilterEventFormatToStr(FilterEventFormat);
|
||||||
|
|
||||||
|
extern int FilterEventFromJson(HashMap *, FilterEvent *, char **);
|
||||||
|
extern HashMap * FilterEventToJson(FilterEvent *);
|
||||||
|
extern void FilterEventFree(FilterEvent *);
|
||||||
|
|
||||||
|
extern int FilterFromJson(HashMap *, Filter *, char **);
|
||||||
|
extern HashMap * FilterToJson(Filter *);
|
||||||
|
extern void FilterFree(Filter *);
|
||||||
|
|
||||||
|
extern int FilterRoomEventFromJson(HashMap *, FilterRoomEvent *, char **);
|
||||||
|
extern HashMap * FilterRoomEventToJson(FilterRoomEvent *);
|
||||||
|
extern void FilterRoomEventFree(FilterRoomEvent *);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_SCHEMA_FILTER_H */
|
51
src/include/Schema/PduV1.h
Normal file
51
src/include/Schema/PduV1.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#ifndef TELODENDRIA_SCHEMA_PDUV1_H
|
||||||
|
#define TELODENDRIA_SCHEMA_PDUV1_H
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct PduV1UnsignedData
|
||||||
|
{
|
||||||
|
Int64 age;
|
||||||
|
} PduV1UnsignedData;
|
||||||
|
|
||||||
|
typedef struct PduV1EventHash
|
||||||
|
{
|
||||||
|
char * sha256;
|
||||||
|
} PduV1EventHash;
|
||||||
|
|
||||||
|
typedef struct PduV1
|
||||||
|
{
|
||||||
|
Int64 origin_server_ts;
|
||||||
|
HashMap * content;
|
||||||
|
char * redacts;
|
||||||
|
char * sender;
|
||||||
|
Int64 depth;
|
||||||
|
Array * prev_events;
|
||||||
|
char * type;
|
||||||
|
PduV1UnsignedData _unsigned;
|
||||||
|
Array * auth_events;
|
||||||
|
char * room_id;
|
||||||
|
char * state_key;
|
||||||
|
HashMap * signatures;
|
||||||
|
char * event_id;
|
||||||
|
PduV1EventHash hashes;
|
||||||
|
} PduV1;
|
||||||
|
|
||||||
|
extern int PduV1EventHashFromJson(HashMap *, PduV1EventHash *, char **);
|
||||||
|
extern HashMap * PduV1EventHashToJson(PduV1EventHash *);
|
||||||
|
extern void PduV1EventHashFree(PduV1EventHash *);
|
||||||
|
|
||||||
|
extern int PduV1FromJson(HashMap *, PduV1 *, char **);
|
||||||
|
extern HashMap * PduV1ToJson(PduV1 *);
|
||||||
|
extern void PduV1Free(PduV1 *);
|
||||||
|
|
||||||
|
extern int PduV1UnsignedDataFromJson(HashMap *, PduV1UnsignedData *, char **);
|
||||||
|
extern HashMap * PduV1UnsignedDataToJson(PduV1UnsignedData *);
|
||||||
|
extern void PduV1UnsignedDataFree(PduV1UnsignedData *);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_SCHEMA_PDUV1_H */
|
50
src/include/Schema/PduV3.h
Normal file
50
src/include/Schema/PduV3.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#ifndef TELODENDRIA_SCHEMA_PDUV3_H
|
||||||
|
#define TELODENDRIA_SCHEMA_PDUV3_H
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct PduV3UnsignedData
|
||||||
|
{
|
||||||
|
Int64 age;
|
||||||
|
} PduV3UnsignedData;
|
||||||
|
|
||||||
|
typedef struct PduV3EventHash
|
||||||
|
{
|
||||||
|
char * sha256;
|
||||||
|
} PduV3EventHash;
|
||||||
|
|
||||||
|
typedef struct PduV3
|
||||||
|
{
|
||||||
|
Int64 origin_server_ts;
|
||||||
|
HashMap * content;
|
||||||
|
char * redacts;
|
||||||
|
char * sender;
|
||||||
|
Int64 depth;
|
||||||
|
Array * prev_events;
|
||||||
|
char * type;
|
||||||
|
PduV3UnsignedData _unsigned;
|
||||||
|
Array * auth_events;
|
||||||
|
char * room_id;
|
||||||
|
char * state_key;
|
||||||
|
HashMap * signatures;
|
||||||
|
PduV3EventHash hashes;
|
||||||
|
} PduV3;
|
||||||
|
|
||||||
|
extern int PduV3EventHashFromJson(HashMap *, PduV3EventHash *, char **);
|
||||||
|
extern HashMap * PduV3EventHashToJson(PduV3EventHash *);
|
||||||
|
extern void PduV3EventHashFree(PduV3EventHash *);
|
||||||
|
|
||||||
|
extern int PduV3FromJson(HashMap *, PduV3 *, char **);
|
||||||
|
extern HashMap * PduV3ToJson(PduV3 *);
|
||||||
|
extern void PduV3Free(PduV3 *);
|
||||||
|
|
||||||
|
extern int PduV3UnsignedDataFromJson(HashMap *, PduV3UnsignedData *, char **);
|
||||||
|
extern HashMap * PduV3UnsignedDataToJson(PduV3UnsignedData *);
|
||||||
|
extern void PduV3UnsignedDataFree(PduV3UnsignedData *);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_SCHEMA_PDUV3_H */
|
82
src/include/Schema/RoomCreateRequest.h
Normal file
82
src/include/Schema/RoomCreateRequest.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* Generated by j2s */
|
||||||
|
|
||||||
|
#ifndef TELODENDRIA_SCHEMA_ROOMCREATE_H
|
||||||
|
#define TELODENDRIA_SCHEMA_ROOMCREATE_H
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum Room3PidMedium
|
||||||
|
{
|
||||||
|
ROOM_3PID_MSISDN,
|
||||||
|
ROOM_3PID_EMAIL
|
||||||
|
} Room3PidMedium;
|
||||||
|
|
||||||
|
typedef enum RoomCreatePreset
|
||||||
|
{
|
||||||
|
ROOM_CREATE_PUBLIC,
|
||||||
|
ROOM_CREATE_TRUSTED,
|
||||||
|
ROOM_CREATE_PRIVATE
|
||||||
|
} RoomCreatePreset;
|
||||||
|
|
||||||
|
typedef struct RoomStateEvent
|
||||||
|
{
|
||||||
|
HashMap * content;
|
||||||
|
char * state_key;
|
||||||
|
char * type;
|
||||||
|
} RoomStateEvent;
|
||||||
|
|
||||||
|
typedef struct RoomInvite3Pid
|
||||||
|
{
|
||||||
|
char * id_access_token;
|
||||||
|
char * address;
|
||||||
|
Room3PidMedium medium;
|
||||||
|
char * id_server;
|
||||||
|
} RoomInvite3Pid;
|
||||||
|
|
||||||
|
typedef enum RoomVisibility
|
||||||
|
{
|
||||||
|
ROOM_PUBLIC,
|
||||||
|
ROOM_PRIVATE
|
||||||
|
} RoomVisibility;
|
||||||
|
|
||||||
|
typedef struct RoomCreateRequest
|
||||||
|
{
|
||||||
|
Array * invite;
|
||||||
|
char * room_version;
|
||||||
|
Array * invite_3pid;
|
||||||
|
char * topic;
|
||||||
|
RoomVisibility visibility;
|
||||||
|
HashMap * creation_content;
|
||||||
|
int is_direct;
|
||||||
|
char * name;
|
||||||
|
Array * initial_state;
|
||||||
|
HashMap * power_level_content_override;
|
||||||
|
char * room_alias_name;
|
||||||
|
RoomCreatePreset preset;
|
||||||
|
} RoomCreateRequest;
|
||||||
|
|
||||||
|
extern int RoomVisibilityFromStr(char *);
|
||||||
|
extern char * RoomVisibilityToStr(RoomVisibility);
|
||||||
|
|
||||||
|
extern int RoomCreateRequestFromJson(HashMap *, RoomCreateRequest *, char **);
|
||||||
|
extern HashMap * RoomCreateRequestToJson(RoomCreateRequest *);
|
||||||
|
extern void RoomCreateRequestFree(RoomCreateRequest *);
|
||||||
|
|
||||||
|
extern int RoomInvite3PidFromJson(HashMap *, RoomInvite3Pid *, char **);
|
||||||
|
extern HashMap * RoomInvite3PidToJson(RoomInvite3Pid *);
|
||||||
|
extern void RoomInvite3PidFree(RoomInvite3Pid *);
|
||||||
|
|
||||||
|
extern int Room3PidMediumFromStr(char *);
|
||||||
|
extern char * Room3PidMediumToStr(Room3PidMedium);
|
||||||
|
|
||||||
|
extern int RoomCreatePresetFromStr(char *);
|
||||||
|
extern char * RoomCreatePresetToStr(RoomCreatePreset);
|
||||||
|
|
||||||
|
extern int RoomStateEventFromJson(HashMap *, RoomStateEvent *, char **);
|
||||||
|
extern HashMap * RoomStateEventToJson(RoomStateEvent *);
|
||||||
|
extern void RoomStateEventFree(RoomStateEvent *);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_SCHEMA_ROOMCREATE_H */
|
|
@ -1,167 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
#
|
|
||||||
# send-patch: "The Telodendria Patch Sender"
|
|
||||||
#
|
|
||||||
# This is a simple script for posting patch files to
|
|
||||||
# a single room(generally the Telodendria patch room.)
|
|
||||||
|
|
||||||
. "$(pwd)/tools/lib/common.sh"
|
|
||||||
|
|
||||||
# Path to the patch to send.
|
|
||||||
PATCHFILE="$1"
|
|
||||||
|
|
||||||
# Tries to decompose the name and the HS from an MXID using
|
|
||||||
# sed.
|
|
||||||
UR_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\1/")"
|
|
||||||
HS_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\2/")"
|
|
||||||
|
|
||||||
# Prompts the user for a password, while disabling echo-ing.
|
|
||||||
readpwd() {
|
|
||||||
printf "$1"
|
|
||||||
stty -echo -ctlecho
|
|
||||||
read -r "$2"
|
|
||||||
echo
|
|
||||||
stty echo ctlecho
|
|
||||||
}
|
|
||||||
|
|
||||||
# Makes an HTTP request, setting the RETURN variable for the
|
|
||||||
# actual reply from the server and the ERROR_CODE variable
|
|
||||||
# for a HTTP error code.
|
|
||||||
request() {
|
|
||||||
RETURN=$(http -i "$@" 2>/dev/null)
|
|
||||||
ERROR_CODE=$(echo "$RETURN" | head -n1 | awk '{print $2}')
|
|
||||||
RETURN=$(echo "$RETURN" | sed '1,/^[[:space:]]*$/d')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Prompts user to login and gives out an access token to use
|
|
||||||
# in the ACCESS_TOKEN variable
|
|
||||||
matrix_login() {
|
|
||||||
# Check authentication methods
|
|
||||||
echo "Checking authentication methods..."
|
|
||||||
request "$HS_BASE/_matrix/client/v3/login"
|
|
||||||
AUTH_METHODS=$RETURN
|
|
||||||
if [ $ERROR_CODE -ne 200 ]; then
|
|
||||||
echo "Homeserver does not support login."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! echo "$AUTH_METHODS" | grep "m.login.password" >/dev/null; then
|
|
||||||
echo "Homeserver does not support password authentication."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# Homeserver does support password authentication, so request
|
|
||||||
# them one.
|
|
||||||
if [ -z "$MXPW" ]; then
|
|
||||||
readpwd "Enter your Matrix password: " MXPW
|
|
||||||
fi
|
|
||||||
# Tries to login using the "Telodendria Patch Script" device
|
|
||||||
# name
|
|
||||||
JSON=$(
|
|
||||||
printf '{'
|
|
||||||
printf ' "identifier": {'
|
|
||||||
printf ' "type": "m.id.user",'
|
|
||||||
printf ' "user": %s' "$(json -e $UR_NAME)"
|
|
||||||
printf ' },'
|
|
||||||
printf ' "initial_device_display_name": "Telodendria Patch Script",'
|
|
||||||
printf ' "type": "m.login.password",'
|
|
||||||
printf ' "password": %s' "$(json -e "$MXPW")"
|
|
||||||
printf '}'
|
|
||||||
)
|
|
||||||
request -X POST -d "$JSON" $HS_BASE/_matrix/client/v3/login
|
|
||||||
LOGIN="$RETURN"
|
|
||||||
if [ $ERROR_CODE -ne 200 ]; then
|
|
||||||
echo "Login failed."
|
|
||||||
echo "$RETURN"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
ACCESS_TOKEN=$(echo "$LOGIN" | json -s "access_token->@decode")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Logs out of Matrix using the ACFESS_TOKEN environment variable
|
|
||||||
matrix_logout() {
|
|
||||||
if [ -z "$ACCESS_TOKEN" ]; then
|
|
||||||
echo "No access token"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
request -X POST -H "Authorization: Bearer $ACCESS_TOKEN" "$HS_BASE/_matrix/client/v3/logout"
|
|
||||||
LOGOUT=$RETURN
|
|
||||||
if [ $ERROR_CODE -ne 200 ]; then
|
|
||||||
echo "Logout failed."
|
|
||||||
echo "$RETURN"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Logged out."
|
|
||||||
}
|
|
||||||
|
|
||||||
send_patch() {
|
|
||||||
if [ -z "$ACCESS_TOKEN" ]; then
|
|
||||||
matrix_login
|
|
||||||
DO_LOGOUT=1
|
|
||||||
fi
|
|
||||||
# We are sucessfully logged in as our user, now let's
|
|
||||||
# try to upload and post our patch
|
|
||||||
echo "$PATCHFILE"
|
|
||||||
request -X POST \
|
|
||||||
-H "Content-Type: text/x-patch" \
|
|
||||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
||||||
-d "@$PATCHFILE" \
|
|
||||||
"$HS_BASE/_matrix/media/v3/upload"
|
|
||||||
MXCID=$RETURN
|
|
||||||
if [ $ERROR_CODE -ne 200 ]; then
|
|
||||||
echo "Upload failed."
|
|
||||||
echo "$RETURN"
|
|
||||||
matrix_logout
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
MXCID=$(echo "$MXCID" | json -s "content_uri->@decode")
|
|
||||||
echo "MXC ID: $MXCID"
|
|
||||||
JSON=$(
|
|
||||||
base=$(basename "$PATCHFILE")
|
|
||||||
printf '{'
|
|
||||||
printf ' "body": %s,' "$(json -e $base)"
|
|
||||||
printf ' "filename": %s,' "$(json -e $base)"
|
|
||||||
printf ' "info": {'
|
|
||||||
printf ' "mimetype": "text/x-patch",'
|
|
||||||
printf ' "size": %d' $(wc -c "$PATCHFILE" | awk '{print $1}')
|
|
||||||
printf ' },'
|
|
||||||
printf ' "msgtype": "m.file",'
|
|
||||||
printf ' "url": %s' "$(json -e $MXCID)"
|
|
||||||
printf '}'
|
|
||||||
)
|
|
||||||
http -X PUT -d "$JSON" -H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
||||||
"$HS_BASE/_matrix/client/v3/rooms/$PATCHES_ROOM/send/m.room.message/$(date +%s)" \
|
|
||||||
2>/dev/null >/dev/null && echo "Patch sent."
|
|
||||||
|
|
||||||
# Log out if we generated an access token
|
|
||||||
if [ "$DO_LOGOUT" -eq "1" ]; then
|
|
||||||
matrix_logout
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if the patch file is valid.
|
|
||||||
if [ "$(basename "$PATCHFILE" .patch)" = "$PATCHFILE" ] || [ ! -f "$PATCHFILE" ]; then
|
|
||||||
echo "Format: $0 file.patch"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Sending file '$PATCHFILE'"
|
|
||||||
echo "Checking homeserver's real address using .well-known..."
|
|
||||||
request "https://$HS_NAME/.well-known/matrix/client"
|
|
||||||
case "$ERROR_CODE" in
|
|
||||||
"200")
|
|
||||||
WELL_KNOWN=$RETURN
|
|
||||||
if [ -z "$WELL_KNOWN" ]; then
|
|
||||||
echo "well-known test returned 200 but no correct input was given."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# well-known entry is correct, we can now store our base endpoint
|
|
||||||
HS_BASE=$(printf "$WELL_KNOWN" | json -s "m.homeserver->base_url->@decode") && send_patch
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "$ERROR_CODE"
|
|
||||||
|
|
||||||
echo "well-known test failed."
|
|
||||||
printf "Please enter your homeserver base URL: "
|
|
||||||
read -r HS_BASE
|
|
||||||
echo
|
|
||||||
send_patch
|
|
||||||
;;
|
|
||||||
esac
|
|
148
tools/bin/tp
148
tools/bin/tp
|
@ -1,148 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
#
|
|
||||||
# tp: "Telodendria Patch"
|
|
||||||
#
|
|
||||||
# This script is used to manage the patch queue.
|
|
||||||
|
|
||||||
. "$(pwd)/tools/lib/common.sh"
|
|
||||||
|
|
||||||
if [ -z "$TELODENDRIA_PUB" ]; then
|
|
||||||
echo "TELODENDRIA_PUB not set."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TP_DIR="$TELODENDRIA_PUB/patches"
|
|
||||||
|
|
||||||
if [ ! -d "$TP_DIR" ]; then
|
|
||||||
echo "$TP_DIR does not exist."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
matrix_send() {
|
|
||||||
msg="$1"
|
|
||||||
if [ ! -z "$msg" ]; then
|
|
||||||
(
|
|
||||||
printf '{'
|
|
||||||
printf '"body":'
|
|
||||||
json -e "$msg"
|
|
||||||
printf ',"formatted_body":'
|
|
||||||
json -e "$msg"
|
|
||||||
printf ',"format":"org.matrix.custom.html",'
|
|
||||||
printf '"msgtype":"m.text"'
|
|
||||||
printf '}'
|
|
||||||
) > /tmp/tp-$$
|
|
||||||
http -X PUT -d @/tmp/tp-$$ "$HOMESERVER/client/v3/rooms/$PATCHES_ROOM/send/m.room.message/$(date +%s)?access_token=$ACCESS_TOKEN"
|
|
||||||
rm /tmp/tp-$$
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
"ingress")
|
|
||||||
timeline="/tmp/timeline.json"
|
|
||||||
http "$HOMESERVER/client/v3/sync?access_token=$ACCESS_TOKEN" |
|
|
||||||
json -s "rooms->join->${PATCHES_ROOM}->timeline" >"$timeline"
|
|
||||||
|
|
||||||
length=$(cat "$timeline" | json -s "events->@length")
|
|
||||||
|
|
||||||
i=0
|
|
||||||
while [ $i -lt $length ]; do
|
|
||||||
content=$(cat "$timeline" | json -s "events[$i]->content->^body->^formatted_body")
|
|
||||||
i=$((i + 1))
|
|
||||||
|
|
||||||
type=$(echo "$content" | json -s "msgtype->@decode")
|
|
||||||
if [ "$type" != "m.file" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
size=$(echo "$content" | json -s "info->size")
|
|
||||||
if [ "$size" -gt "$MAX_SIZE" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
file=$(echo "$content" | json -s "filename->@decode")
|
|
||||||
ext=$(echo "$file" | rev | cut -d '.' -f 1 | rev)
|
|
||||||
if [ "$ext" != "patch" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
url=$(echo "$content" | json -s "url->@decode")
|
|
||||||
id=$(echo "$url" | cut -d '/' -f 4)
|
|
||||||
|
|
||||||
if [ -f "$TP_DIR/ingress/$id.patch" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
server=$(echo "$url" | cut -d '/' -f 3)
|
|
||||||
|
|
||||||
if ! http "$HOMESERVER/media/v3/download/$server/$id" > "$TP_DIR/ingress/$id.patch"; then
|
|
||||||
rm "$TP_DIR/ingress/$id.patch"
|
|
||||||
echo "Failed to fetch mxc://$server/$id."
|
|
||||||
echo "Will try again next time."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
count=$(cat "$TP_DIR/count.txt")
|
|
||||||
count=$((count + 1))
|
|
||||||
cp "$TP_DIR/ingress/$id.patch" "$TP_DIR/p/$count.patch"
|
|
||||||
(
|
|
||||||
cd "$TP_DIR/queued"
|
|
||||||
ln -s "../p/$count.patch" "$count.patch"
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "$count" >"$TP_DIR/count.txt"
|
|
||||||
|
|
||||||
matrix_send "Queued <code>$file</code> as <a href=\"https://telodendria.io/patches/p/$count.patch\">#$count</a>" >/dev/null
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
"queue")
|
|
||||||
find "$TP_DIR/queued" -name '*.patch' | while IFS= read -r patch; do
|
|
||||||
n=$(basename "$patch" .patch)
|
|
||||||
echo "Patch #$n:"
|
|
||||||
head -n3 "$patch"
|
|
||||||
echo
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
"view")
|
|
||||||
if [ -f "$TP_DIR/queued/$2.patch" ]; then
|
|
||||||
less "$TP_DIR/queued/$2.patch"
|
|
||||||
else
|
|
||||||
echo "Patch #$2 doesn't exist in the queue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"apply")
|
|
||||||
if [ -f "$TP_DIR/queued/$2.patch" ]; then
|
|
||||||
patch <"$TP_DIR/queued/$2.patch"
|
|
||||||
else
|
|
||||||
echo "Patch #$2 doesn't exist in the queue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"reverse")
|
|
||||||
if [ -f "$TP_DIR/queued/$2.patch" ]; then
|
|
||||||
patch -R <"$TP_DIR/queued/$2.patch"
|
|
||||||
else
|
|
||||||
echo "Patch #$2 doesn't exist in the queue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"accept" | "reject")
|
|
||||||
if [ -f "$TP_DIR/queued/$2.patch" ]; then
|
|
||||||
mv "$TP_DIR/queued/$2.patch" "$TP_DIR/${1}ed/$2.patch"
|
|
||||||
msg="Patch <a href=\"https://telodendria.io/patches/p/$2.patch\">#$2</a> was marked as ${1}ed."
|
|
||||||
msgFile="/tmp/patchmsg-$(date +%s).txt"
|
|
||||||
$EDITOR "$msgFile"
|
|
||||||
if [ -f "$msgFile" ]; then
|
|
||||||
msg="$msg<br><blockquote>$(cat $msgFile)<br>—$DISPLAY_NAME ($MXID)</blockquote>"
|
|
||||||
fi
|
|
||||||
matrix_send "$msg"
|
|
||||||
else
|
|
||||||
echo "Patch #$2 doesn't exist in the queue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "No action specified."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
Loading…
Reference in a new issue