From f68336b96e0d843511bb1bd3fdac8bba2fe4573a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 23 Mar 2023 13:36:52 +0100 Subject: teal: Move into prosody namespace --- GNUmakefile | 2 +- teal-src/core/storagemanager.d.tl | 74 ------ teal-src/core/usermanager.d.tl | 46 ---- teal-src/module.d.tl | 2 +- teal-src/net/http.d.tl | 86 ------- teal-src/net/http/codes.d.tl | 2 - teal-src/net/http/errors.d.tl | 22 -- teal-src/net/http/files.d.tl | 14 -- teal-src/net/http/parser.d.tl | 58 ----- teal-src/net/http/server.d.tl | 6 - teal-src/net/server.d.tl | 65 ----- teal-src/plugins/mod_cron.tl | 106 --------- teal-src/plugins/muc/muc.lib.d.tl | 178 -------------- teal-src/prosody/core/storagemanager.d.tl | 74 ++++++ teal-src/prosody/core/usermanager.d.tl | 46 ++++ teal-src/prosody/net/http.d.tl | 86 +++++++ teal-src/prosody/net/http/codes.d.tl | 2 + teal-src/prosody/net/http/errors.d.tl | 22 ++ teal-src/prosody/net/http/files.d.tl | 14 ++ teal-src/prosody/net/http/parser.d.tl | 58 +++++ teal-src/prosody/net/http/server.d.tl | 6 + teal-src/prosody/net/server.d.tl | 65 +++++ teal-src/prosody/plugins/mod_cron.tl | 106 +++++++++ teal-src/prosody/plugins/muc/muc.lib.d.tl | 178 ++++++++++++++ teal-src/prosody/util/array.d.tl | 9 + teal-src/prosody/util/async.d.tl | 42 ++++ teal-src/prosody/util/bitcompat.d.tl | 8 + teal-src/prosody/util/compat.d.tl | 4 + teal-src/prosody/util/crand.d.tl | 6 + teal-src/prosody/util/crypto.d.tl | 29 +++ teal-src/prosody/util/dataforms.d.tl | 54 +++++ teal-src/prosody/util/datamapper.tl | 379 ++++++++++++++++++++++++++++++ teal-src/prosody/util/datetime.d.tl | 9 + teal-src/prosody/util/encodings.d.tl | 27 +++ teal-src/prosody/util/error.d.tl | 78 ++++++ teal-src/prosody/util/format.d.tl | 4 + teal-src/prosody/util/hashes.d.tl | 31 +++ teal-src/prosody/util/hex.d.tl | 8 + teal-src/prosody/util/http.d.tl | 9 + teal-src/prosody/util/human/io.d.tl | 28 +++ teal-src/prosody/util/human/units.d.tl | 8 + teal-src/prosody/util/id.d.tl | 9 + teal-src/prosody/util/interpolation.d.tl | 6 + teal-src/prosody/util/ip.d.tl | 20 ++ teal-src/prosody/util/jid.d.tl | 15 ++ teal-src/prosody/util/json.d.tl | 18 ++ teal-src/prosody/util/jsonpointer.tl | 46 ++++ teal-src/prosody/util/jsonschema.tl | 376 +++++++++++++++++++++++++++++ teal-src/prosody/util/jwt.d.tl | 38 +++ teal-src/prosody/util/logger.d.tl | 18 ++ teal-src/prosody/util/mathcompat.tl | 15 ++ teal-src/prosody/util/net.d.tl | 13 + teal-src/prosody/util/poll.d.tl | 31 +++ teal-src/prosody/util/pposix.d.tl | 108 +++++++++ teal-src/prosody/util/promise.d.tl | 22 ++ teal-src/prosody/util/queue.d.tl | 21 ++ teal-src/prosody/util/random.d.tl | 4 + teal-src/prosody/util/ringbuffer.d.tl | 20 ++ teal-src/prosody/util/roles.d.tl | 32 +++ teal-src/prosody/util/serialization.d.tl | 33 +++ teal-src/prosody/util/set.d.tl | 21 ++ teal-src/prosody/util/signal.d.tl | 41 ++++ teal-src/prosody/util/smqueue.tl | 99 ++++++++ teal-src/prosody/util/stanza.d.tl | 145 ++++++++++++ teal-src/prosody/util/strbitop.d.tl | 6 + teal-src/prosody/util/struct.d.tl | 6 + teal-src/prosody/util/table.d.tl | 7 + teal-src/prosody/util/termcolours.d.tl | 7 + teal-src/prosody/util/time.d.tl | 6 + teal-src/prosody/util/timer.d.tl | 8 + teal-src/prosody/util/uuid.d.tl | 8 + teal-src/prosody/util/xtemplate.tl | 101 ++++++++ teal-src/util/array.d.tl | 9 - teal-src/util/async.d.tl | 42 ---- teal-src/util/bitcompat.d.tl | 8 - teal-src/util/compat.d.tl | 4 - teal-src/util/crand.d.tl | 6 - teal-src/util/crypto.d.tl | 29 --- teal-src/util/dataforms.d.tl | 54 ----- teal-src/util/datamapper.tl | 379 ------------------------------ teal-src/util/datetime.d.tl | 9 - teal-src/util/encodings.d.tl | 27 --- teal-src/util/error.d.tl | 78 ------ teal-src/util/format.d.tl | 4 - teal-src/util/hashes.d.tl | 31 --- teal-src/util/hex.d.tl | 8 - teal-src/util/http.d.tl | 9 - teal-src/util/human/io.d.tl | 28 --- teal-src/util/human/units.d.tl | 8 - teal-src/util/id.d.tl | 9 - teal-src/util/interpolation.d.tl | 6 - teal-src/util/ip.d.tl | 20 -- teal-src/util/jid.d.tl | 15 -- teal-src/util/json.d.tl | 18 -- teal-src/util/jsonpointer.tl | 46 ---- teal-src/util/jsonschema.tl | 376 ----------------------------- teal-src/util/jwt.d.tl | 38 --- teal-src/util/logger.d.tl | 18 -- teal-src/util/mathcompat.tl | 15 -- teal-src/util/net.d.tl | 13 - teal-src/util/poll.d.tl | 31 --- teal-src/util/pposix.d.tl | 108 --------- teal-src/util/promise.d.tl | 22 -- teal-src/util/queue.d.tl | 21 -- teal-src/util/random.d.tl | 4 - teal-src/util/ringbuffer.d.tl | 20 -- teal-src/util/roles.d.tl | 32 --- teal-src/util/serialization.d.tl | 33 --- teal-src/util/set.d.tl | 21 -- teal-src/util/signal.d.tl | 41 ---- teal-src/util/smqueue.tl | 99 -------- teal-src/util/stanza.d.tl | 145 ------------ teal-src/util/strbitop.d.tl | 6 - teal-src/util/struct.d.tl | 6 - teal-src/util/table.d.tl | 7 - teal-src/util/termcolours.d.tl | 7 - teal-src/util/time.d.tl | 6 - teal-src/util/timer.d.tl | 8 - teal-src/util/uuid.d.tl | 8 - teal-src/util/xtemplate.tl | 101 -------- 120 files changed, 2692 insertions(+), 2692 deletions(-) delete mode 100644 teal-src/core/storagemanager.d.tl delete mode 100644 teal-src/core/usermanager.d.tl delete mode 100644 teal-src/net/http.d.tl delete mode 100644 teal-src/net/http/codes.d.tl delete mode 100644 teal-src/net/http/errors.d.tl delete mode 100644 teal-src/net/http/files.d.tl delete mode 100644 teal-src/net/http/parser.d.tl delete mode 100644 teal-src/net/http/server.d.tl delete mode 100644 teal-src/net/server.d.tl delete mode 100644 teal-src/plugins/mod_cron.tl delete mode 100644 teal-src/plugins/muc/muc.lib.d.tl create mode 100644 teal-src/prosody/core/storagemanager.d.tl create mode 100644 teal-src/prosody/core/usermanager.d.tl create mode 100644 teal-src/prosody/net/http.d.tl create mode 100644 teal-src/prosody/net/http/codes.d.tl create mode 100644 teal-src/prosody/net/http/errors.d.tl create mode 100644 teal-src/prosody/net/http/files.d.tl create mode 100644 teal-src/prosody/net/http/parser.d.tl create mode 100644 teal-src/prosody/net/http/server.d.tl create mode 100644 teal-src/prosody/net/server.d.tl create mode 100644 teal-src/prosody/plugins/mod_cron.tl create mode 100644 teal-src/prosody/plugins/muc/muc.lib.d.tl create mode 100644 teal-src/prosody/util/array.d.tl create mode 100644 teal-src/prosody/util/async.d.tl create mode 100644 teal-src/prosody/util/bitcompat.d.tl create mode 100644 teal-src/prosody/util/compat.d.tl create mode 100644 teal-src/prosody/util/crand.d.tl create mode 100644 teal-src/prosody/util/crypto.d.tl create mode 100644 teal-src/prosody/util/dataforms.d.tl create mode 100644 teal-src/prosody/util/datamapper.tl create mode 100644 teal-src/prosody/util/datetime.d.tl create mode 100644 teal-src/prosody/util/encodings.d.tl create mode 100644 teal-src/prosody/util/error.d.tl create mode 100644 teal-src/prosody/util/format.d.tl create mode 100644 teal-src/prosody/util/hashes.d.tl create mode 100644 teal-src/prosody/util/hex.d.tl create mode 100644 teal-src/prosody/util/http.d.tl create mode 100644 teal-src/prosody/util/human/io.d.tl create mode 100644 teal-src/prosody/util/human/units.d.tl create mode 100644 teal-src/prosody/util/id.d.tl create mode 100644 teal-src/prosody/util/interpolation.d.tl create mode 100644 teal-src/prosody/util/ip.d.tl create mode 100644 teal-src/prosody/util/jid.d.tl create mode 100644 teal-src/prosody/util/json.d.tl create mode 100644 teal-src/prosody/util/jsonpointer.tl create mode 100644 teal-src/prosody/util/jsonschema.tl create mode 100644 teal-src/prosody/util/jwt.d.tl create mode 100644 teal-src/prosody/util/logger.d.tl create mode 100644 teal-src/prosody/util/mathcompat.tl create mode 100644 teal-src/prosody/util/net.d.tl create mode 100644 teal-src/prosody/util/poll.d.tl create mode 100644 teal-src/prosody/util/pposix.d.tl create mode 100644 teal-src/prosody/util/promise.d.tl create mode 100644 teal-src/prosody/util/queue.d.tl create mode 100644 teal-src/prosody/util/random.d.tl create mode 100644 teal-src/prosody/util/ringbuffer.d.tl create mode 100644 teal-src/prosody/util/roles.d.tl create mode 100644 teal-src/prosody/util/serialization.d.tl create mode 100644 teal-src/prosody/util/set.d.tl create mode 100644 teal-src/prosody/util/signal.d.tl create mode 100644 teal-src/prosody/util/smqueue.tl create mode 100644 teal-src/prosody/util/stanza.d.tl create mode 100644 teal-src/prosody/util/strbitop.d.tl create mode 100644 teal-src/prosody/util/struct.d.tl create mode 100644 teal-src/prosody/util/table.d.tl create mode 100644 teal-src/prosody/util/termcolours.d.tl create mode 100644 teal-src/prosody/util/time.d.tl create mode 100644 teal-src/prosody/util/timer.d.tl create mode 100644 teal-src/prosody/util/uuid.d.tl create mode 100644 teal-src/prosody/util/xtemplate.tl delete mode 100644 teal-src/util/array.d.tl delete mode 100644 teal-src/util/async.d.tl delete mode 100644 teal-src/util/bitcompat.d.tl delete mode 100644 teal-src/util/compat.d.tl delete mode 100644 teal-src/util/crand.d.tl delete mode 100644 teal-src/util/crypto.d.tl delete mode 100644 teal-src/util/dataforms.d.tl delete mode 100644 teal-src/util/datamapper.tl delete mode 100644 teal-src/util/datetime.d.tl delete mode 100644 teal-src/util/encodings.d.tl delete mode 100644 teal-src/util/error.d.tl delete mode 100644 teal-src/util/format.d.tl delete mode 100644 teal-src/util/hashes.d.tl delete mode 100644 teal-src/util/hex.d.tl delete mode 100644 teal-src/util/http.d.tl delete mode 100644 teal-src/util/human/io.d.tl delete mode 100644 teal-src/util/human/units.d.tl delete mode 100644 teal-src/util/id.d.tl delete mode 100644 teal-src/util/interpolation.d.tl delete mode 100644 teal-src/util/ip.d.tl delete mode 100644 teal-src/util/jid.d.tl delete mode 100644 teal-src/util/json.d.tl delete mode 100644 teal-src/util/jsonpointer.tl delete mode 100644 teal-src/util/jsonschema.tl delete mode 100644 teal-src/util/jwt.d.tl delete mode 100644 teal-src/util/logger.d.tl delete mode 100644 teal-src/util/mathcompat.tl delete mode 100644 teal-src/util/net.d.tl delete mode 100644 teal-src/util/poll.d.tl delete mode 100644 teal-src/util/pposix.d.tl delete mode 100644 teal-src/util/promise.d.tl delete mode 100644 teal-src/util/queue.d.tl delete mode 100644 teal-src/util/random.d.tl delete mode 100644 teal-src/util/ringbuffer.d.tl delete mode 100644 teal-src/util/roles.d.tl delete mode 100644 teal-src/util/serialization.d.tl delete mode 100644 teal-src/util/set.d.tl delete mode 100644 teal-src/util/signal.d.tl delete mode 100644 teal-src/util/smqueue.tl delete mode 100644 teal-src/util/stanza.d.tl delete mode 100644 teal-src/util/strbitop.d.tl delete mode 100644 teal-src/util/struct.d.tl delete mode 100644 teal-src/util/table.d.tl delete mode 100644 teal-src/util/termcolours.d.tl delete mode 100644 teal-src/util/time.d.tl delete mode 100644 teal-src/util/timer.d.tl delete mode 100644 teal-src/util/uuid.d.tl delete mode 100644 teal-src/util/xtemplate.tl diff --git a/GNUmakefile b/GNUmakefile index b13f7a47..ec51c893 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -135,7 +135,7 @@ lint: @echo $$(sed -n '/^\tlocal exclude_files/,/^}/p;' .luacheckrc | sed '1d;$d' | wc -l) files ignored shellcheck configure -vpath %.tl teal-src/ +vpath %.tl teal-src/prosody %.lua: %.tl tl -I teal-src/ --gen-compat off --gen-target 5.1 gen $^ -o $@ -lua-format -i $@ diff --git a/teal-src/core/storagemanager.d.tl b/teal-src/core/storagemanager.d.tl deleted file mode 100644 index 3c8253b1..00000000 --- a/teal-src/core/storagemanager.d.tl +++ /dev/null @@ -1,74 +0,0 @@ --- Storage local record API Description --- --- This is written as a TypedLua description - --- Key-Value stores (the default) - -local stanza = require"util.stanza".stanza_t - -local record keyval_store - get : function ( keyval_store, string ) : any , string - set : function ( keyval_store, string, any ) : boolean, string -end - --- Map stores (key-key-value stores) - -local record map_store - get : function ( map_store, string, any ) : any, string - set : function ( map_store, string, any, any ) : boolean, string - set_keys : function ( map_store, string, { any : any }) : boolean, string - remove : table -end - --- Archive stores - -local record archive_query - start : number -- timestamp - ["end"]: number -- timestamp - with : string - after : string -- archive id - before : string -- archive id - total : boolean -end - -local record archive_store - -- Optional set of capabilities - caps : { - -- Optional total count of matching items returned as second return value from :find() - string : any - } - - -- Add to the archive - append : function ( archive_store, string, string, any, number, string ) : string, string - - -- Iterate over archive - type iterator = function () : string, any, number, string - find : function ( archive_store, string, archive_query ) : iterator, integer - - -- Removal of items. API like find. Optional - delete : function ( archive_store, string, archive_query ) : boolean | number, string - - -- Array of dates which do have messages (Optional) - dates : function ( archive_store, string ) : { string }, string - - -- Map of counts per "with" field - summary : function ( archive_store, string, archive_query ) : { string : integer }, string - - -- Map-store API - get : function ( archive_store, string, string ) : stanza, number, string - get : function ( archive_store, string, string ) : nil, string - set : function ( archive_store, string, string, stanza, number, string ) : boolean, string -end - --- This represents moduleapi -local record coremodule - -- If the first string is omitted then the name of the module is used - -- The second string is one of "keyval" (default), "map" or "archive" - open_store : function (archive_store, string, string) : keyval_store, string - open_store : function (archive_store, string, string) : map_store, string - open_store : function (archive_store, string, string) : archive_store, string - - -- Other module methods omitted -end - -return coremodule diff --git a/teal-src/core/usermanager.d.tl b/teal-src/core/usermanager.d.tl deleted file mode 100644 index a546a53c..00000000 --- a/teal-src/core/usermanager.d.tl +++ /dev/null @@ -1,46 +0,0 @@ -local Role = require "util.roles".Role; - -local record usermanager - record AuthProvider - -- TODO - end - record AccountInfo - created : number - password_updated : any - enabled : boolean - end - - -- Users - test_password : function (username : string, host : string, password : string) : boolean - get_password : function (username : string, host : string) : string, string - set_password : function (username : string, host : string, password : string) : boolean, string - get_account_info : function (username : string, host : string) : AccountInfo - user_exists : function (username : string, host : string) : boolean - create_user : function (username : string, password : string, host : string) : boolean, string - delete_user : function (username : string, host : string) : boolean, string - user_is_enabled : function (username : string, host : string) : boolean, string - enable_user : function (username : string, host : string) : boolean, string - disable_user : function (username : string, host : string) : boolean, string - users : function (host : string) : function () : string - - -- Roles - get_user_role : function (username : string, host : string) : Role - set_user_role : function (username : string, host : string, role_name : string) : boolean, string - user_can_assume_role : function (username : string, host : string, role_name : string) : boolean - add_user_secondary_role : function (username : string, host: string, role_name : string) : boolean, string - remove_user_secondary_role : function (username : string, host: string, role_name : string) : boolean, string - get_user_secondary_roles : function (username : string, host : string) : { string : Role } - get_users_with_role : function (role : string, host : string) : { string } - get_jid_role : function (jid : string, host : string) : Role - set_jid_role : function (jid : string, host : string, role_name : string) : boolean - get_jids_with_role : function (role : string, host : string) : { string } - get_role_by_name : function (role_name : string) : Role - - -- Etc - get_provider : function (host : string) : AuthProvider - get_sasl_handler : function (host : string, session : table) : table - initialize_host : function (host : string) - new_null_provider : function () : AuthProvider -end - -return usermanager diff --git a/teal-src/module.d.tl b/teal-src/module.d.tl index 24eb9558..62c36b29 100644 --- a/teal-src/module.d.tl +++ b/teal-src/module.d.tl @@ -1,4 +1,4 @@ -local st = require"util.stanza" +local st = require "prosody.util.stanza" global record moduleapi get_name : function (moduleapi) : string diff --git a/teal-src/net/http.d.tl b/teal-src/net/http.d.tl deleted file mode 100644 index 9135ec12..00000000 --- a/teal-src/net/http.d.tl +++ /dev/null @@ -1,86 +0,0 @@ -local Promise = require "util.promise".Promise; - -local record sslctx -- from LuaSec -end - -local record lib - - enum http_method - "GET" - "HEAD" - "POST" - "PUT" - "OPTIONS" - "DELETE" - -- etc? - end - - record http_client_options - sslctx : sslctx - end - - record http_options - id : string - onlystatus : boolean - body : string - method : http_method - headers : { string : string } - insecure : boolean - suppress_errors : boolean - streaming_handler : function - suppress_url : boolean - sslctx : sslctx - end - - record http_request - host : string - port : string - enum scheme - "http" - "https" - end - scheme : scheme - url : string - userinfo : string - path : string - - method : http_method - headers : { string : string } - - insecure : boolean - suppress_errors : boolean - streaming_handler : function - http : http_client - time : integer - id : string - callback : http_callback - end - - record http_response - end - - type http_callback = function (string, number, http_response, http_request) - - record http_client - options : http_client_options - request : function (http_client, string, http_options, http_callback) - end - - request : function (string, http_options, http_callback) : Promise, string - default : http_client - new : function (http_client_options) : http_client - events : table - -- COMPAT - urlencode : function (string) : string - urldecode : function (string) : string - formencode : function ({ string : string }) : string - formdecode : function (string) : { string : string } - destroy_request : function (http_request) - - enum available_features - "sni" - end - features : { available_features : boolean } -end - -return lib diff --git a/teal-src/net/http/codes.d.tl b/teal-src/net/http/codes.d.tl deleted file mode 100644 index 65d004fc..00000000 --- a/teal-src/net/http/codes.d.tl +++ /dev/null @@ -1,2 +0,0 @@ -local type response_codes = { integer : string } -return response_codes diff --git a/teal-src/net/http/errors.d.tl b/teal-src/net/http/errors.d.tl deleted file mode 100644 index a9b6ea6c..00000000 --- a/teal-src/net/http/errors.d.tl +++ /dev/null @@ -1,22 +0,0 @@ -local record http_errors - enum known_conditions - "cancelled" - "connection-closed" - "certificate-chain-invalid" - "certificate-verify-failed" - "connection failed" - "invalid-url" - "unable to resolve service" - end - type registry_keys = known_conditions | integer - record error - type : string - condition : string - code : integer - text : string - end - registry : { registry_keys : error } - new : function (integer, known_conditions, table) - new : function (integer, string, table) -end -return http_errors diff --git a/teal-src/net/http/files.d.tl b/teal-src/net/http/files.d.tl deleted file mode 100644 index d0ba5c1c..00000000 --- a/teal-src/net/http/files.d.tl +++ /dev/null @@ -1,14 +0,0 @@ -local record serve_options - path : string - mime_map : { string : string } - cache_size : integer - cache_max_file_size : integer - index_files : { string } - directory_index : boolean -end - -local record http_files - serve : function(serve_options|string) : function -end - -return http_files diff --git a/teal-src/net/http/parser.d.tl b/teal-src/net/http/parser.d.tl deleted file mode 100644 index 1cd6ccf4..00000000 --- a/teal-src/net/http/parser.d.tl +++ /dev/null @@ -1,58 +0,0 @@ -local record httpstream - feed : function(httpstream, string) -end - -local type sink_cb = function () - -local record httppacket - enum http_method - "HEAD" - "GET" - "POST" - "PUT" - "DELETE" - "OPTIONS" - -- etc - end - method : http_method - record url_details - path : string - query : string - end - url : url_details - path : string - enum http_version - "1.0" - "1.1" - end - httpversion : http_version - headers : { string : string } - body : string | boolean - body_sink : sink_cb - chunked : boolean - partial : boolean -end - -local enum error_conditions - "cancelled" - "connection-closed" - "certificate-chain-invalid" - "certificate-verify-failed" - "connection failed" - "invalid-url" - "unable to resolve service" -end - -local type success_cb = function (httppacket) -local type error_cb = function (error_conditions) - -local enum stream_mode - "client" - "server" -end - -local record lib - new : function (success_cb, error_cb, stream_mode) : httpstream -end - -return lib diff --git a/teal-src/net/http/server.d.tl b/teal-src/net/http/server.d.tl deleted file mode 100644 index 5a83af7e..00000000 --- a/teal-src/net/http/server.d.tl +++ /dev/null @@ -1,6 +0,0 @@ - -local record http_server - -- TODO -end - -return http_server diff --git a/teal-src/net/server.d.tl b/teal-src/net/server.d.tl deleted file mode 100644 index bb61f677..00000000 --- a/teal-src/net/server.d.tl +++ /dev/null @@ -1,65 +0,0 @@ -local record server - record LuaSocketTCP - end - record LuaSecCTX - end - - record extra_settings - end - - record interface - end - enum socket_type - "tcp" - "tcp6" - "tcp4" - end - - record listeners - onconnect : function (interface) - ondetach : function (interface) - onattach : function (interface, string) - onincoming : function (interface, string, string) - ondrain : function (interface) - onreadtimeout : function (interface) - onstarttls : function (interface) - onstatus : function (interface, string) - ondisconnect : function (interface, string) - end - - get_backend : function () : string - - type port = string | integer - enum read_mode - "*a" - "*l" - end - type read_size = read_mode | integer - addserver : function (string, port, listeners, read_size, LuaSecCTX) : interface - addclient : function (string, port, listeners, read_size, LuaSecCTX, socket_type, extra_settings) : interface - record listen_config - read_size : read_size - tls_ctx : LuaSecCTX - tls_direct : boolean - sni_hosts : { string : LuaSecCTX } - end - listen : function (string, port, listeners, listen_config) : interface - enum quitting - "quitting" - end - loop : function () : quitting - closeall : function () - setquitting : function (boolean | quitting) - - wrapclient : function (LuaSocketTCP, string, port, listeners, read_size, LuaSecCTX, extra_settings) : interface - wrapserver : function (LuaSocketTCP, string, port, listeners, listen_config) : interface - watchfd : function (integer | LuaSocketTCP, function (interface), function (interface)) : interface - link : function () - - record config - end - set_config : function (config) - -end - -return server diff --git a/teal-src/plugins/mod_cron.tl b/teal-src/plugins/mod_cron.tl deleted file mode 100644 index 7fa2a36b..00000000 --- a/teal-src/plugins/mod_cron.tl +++ /dev/null @@ -1,106 +0,0 @@ -module:set_global(); - -local async = require "util.async"; -local datetime = require "util.datetime"; - -local record map_store - -- TODO move to somewhere sensible - get : function (map_store, string, K) : V - set : function (map_store, string, K, V) -end - -local enum frequency - "hourly" - "daily" - "weekly" -end - -local record task_spec - id : string -- unique id - name : string -- name or short description - when : frequency - last : integer - run : function (task_spec, integer) - save : function (task_spec, integer) -end - -local record task_event - source : module - item : task_spec -end - -local periods : { frequency : integer } = { hourly = 3600, daily = 86400, weekly = 7*86400 } - -local active_hosts : { string : boolean } = { } - -function module.add_host(host_module : moduleapi) - - local last_run_times = host_module:open_store("cron", "map") as map_store; - active_hosts[host_module.host] = true; - - local function save_task(task : task_spec, started_at : integer) - last_run_times:set(nil, task.id, started_at); - end - - local function task_added(event : task_event) : boolean - local task = event.item; - if task.name == nil then - task.name = task.when; - end - if task.id == nil then - task.id = event.source.name .. "/" .. task.name:gsub("%W", "_"):lower(); - end - if task.last == nil then - task.last = last_run_times:get(nil, task.id); - end - task.save = save_task; - module:log("debug", "%s task %s added, last run %s", task.when, task.id, - task.last and datetime.datetime(task.last) or "never"); - if task.last == nil then - -- initialize new tasks so e.g. daily tasks run at ~midnight UTC for now - local now = os.time(); - task.last = now - now % periods[task.when]; - end - return true; - end - - local function task_removed(event : task_event) : boolean - local task = event.item; - host_module:log("debug", "Task %s removed", task.id); - return true; - end - - host_module:handle_items("task", task_added, task_removed, true); - - function host_module.unload() - active_hosts[host_module.host]=nil; - end -end - -local function should_run(when : frequency, last : integer) : boolean - return not last or last + periods[when]*0.995 <= os.time(); -end - -local function run_task(task : task_spec) - local started_at = os.time(); - task:run(started_at); - task.last = started_at; - task:save(started_at); -end - -local task_runner : async.runner_t = async.runner(run_task); -scheduled = module:add_timer(1, function() : integer - module:log("info", "Running periodic tasks"); - local delay = 3600; - for host in pairs(active_hosts) do - module:log("debug", "Running periodic tasks for host %s", host); - for _, task in ipairs(module:context(host):get_host_items("task") as { task_spec } ) do - module:log("debug", "Considering %s task %s (%s)", task.when, task.id, task.run); - if should_run(task.when, task.last) then task_runner:run(task); end - end - end - module:log("debug", "Wait %ds", delay); - return delay; -end); - --- TODO measure load, pick a good time to do stuff diff --git a/teal-src/plugins/muc/muc.lib.d.tl b/teal-src/plugins/muc/muc.lib.d.tl deleted file mode 100644 index 1e967d7b..00000000 --- a/teal-src/plugins/muc/muc.lib.d.tl +++ /dev/null @@ -1,178 +0,0 @@ -local Stanza = require "util.stanza".stanza_t - -local record Room - jid : string - - enum Affiliation - "outcast" - "none" - "member" - "admin" - "owner" - end - - enum Role - "none" - "visitor" - "participant" - "moderator" - end - - record Occupant - bare_jid : string - nick : string - sessions : { string : Stanza } - role : Role - jid : string - - choose_new_primary : function (Occupant) : string - set_session : function (Occupant, string, Stanza, boolean) - remove_session : function (Occupant, string) - each_session : function (Occupant) -- TODO Iterator - - end - - -- Private properties - _jid_nick : { string : string } - _occupants : { string : Occupant } - _data : { string : any } - _affiliations : { string : Affiliation } - _affiliation_data : { string : { string : any } } - - -- Occupant methods - get_occupant_jid : function (Room, real_jid : string) : string - new_occupant : function (Room, bare_real_jid : string, nick : string) : Occupant - get_occupant_by_nick : function (Room, nick : string) : Occupant - type OccupantIterator = function ({string:Occupant}, occupant_jid : string) : string, Occupant - each_occupant : function (Room, read_only : boolean) : OccupantIterator, {string:Occupant}, nil - has_occupant : function (Room) : boolean - get_occupant_by_real_jid : function (Room, real_jid : string) : Occupant - save_occupant :function (Room, Occupant) : Occupant - - -- Affiliation methods - type AffiliationIterator = function (any, jid : string) : string, Affiliation - get_affiliation : function (Room, jid : string) : Affiliation - each_affiliation : function (Room, Affiliation) : AffiliationIterator, nil, nil - set_affiliation : function (Room, jid : string, Affiliation, reason : string, data : { string : any }) : boolean, string, string, string -- ok + error tripplet - get_affiliation_data : function (Room, jid : string, key : string) : any - set_affiliation_data : function (Room, jid : string, key : string, value : any) : boolean - get_registered_nick : function (Room, jid : string) : string - get_registered_jid : function (Room, nick : string) : string - - -- Role methods - get_default_role : function (Room, Affiliation) : Role, integer - get_role : function (Room, nick : string) : Role - may_set_role : function (Room, actor : string, Occupant, Role) : boolean - set_role : function (Room, actor : string, occupant_jid : string, Role, reason : string) : boolean, string, string, string - - -- Routing input, generally handled by mod_muc and hooked up to Prosody routing events - handle_first_presence : function (Room, table, Stanza) : boolean - handle_normal_presence : function (Room, table, Stanza) : boolean - handle_presence_to_room : function (Room, table, Stanza) : boolean - handle_presence_to_occupant : function (Room, table, Stanza) : boolean - handle_message_to_room : function (Room, table, Stanza) : boolean - handle_message_to_occupant : function (Room, table, Stanza) : boolean - handle_groupchat_to_room : function (Room, table, Stanza) : boolean - handle_iq_to_occupant : function (Room, table, Stanza) : boolean - handle_disco_info_get_query : function (Room, table, Stanza) : boolean - handle_disco_items_get_query : function (Room, table, Stanza) : boolean - handle_admin_query_set_command : function (Room, table, Stanza) : boolean - handle_admin_query_get_command : function (Room, table, Stanza) : boolean - handle_owner_query_get_to_room : function (Room, table, Stanza) : boolean - handle_owner_query_set_to_room : function (Room, table, Stanza) : boolean - handle_mediated_invite : function (Room, table, Stanza) : boolean - handle_mediated_decline : function (Room, table, Stanza) : boolean - handle_role_request : function (Room, table, Stanza) : boolean - handle_register_iq : function (Room, table, Stanza) : boolean - handle_kickable : function (Room, table, Stanza) : boolean - - -- Routing output - broadcast : function (Room, Stanza, function (nick : string, Occupant) : boolean) - broadcast_message : function (Room, Stanza) : boolean - route_stanza : function (Room, Stanza) - route_to_occupant : function (Room, Occupant, Stanza) - - -- Sending things to someone joining - publicise_occupant_status : function (Room, Occupant, x : Stanza, nick : string, actor : string, reason : string, prev_role : Role, force_unavailable : boolean, recipient : Occupant) - send_occupant_list : function (Room, to : string, filter : function (occupant_jid : string, Occupant) : boolean) - send_history : function (Room, Stanza) - send_subject : function (Room, to : string, time : number) - - respond_to_probe : function (Room, table, Stanza, Occupant) - - -- Constructors for various answer stanzas - get_disco_info : function (Room, Stanza) : Stanza - get_disco_items : function (Room, Stanza) : Stanza - - build_item_list : function (Room, Occupant, Stanza, is_anonymous : boolean, nick : string, actor_nick : string, actor_jid : string, reason : string) : Stanza - build_unavailable_presence : function (Room, from_muc_jid : string, to_jid : string) : Stanza - - -- Form handling - send_form : function (Room, table, Stanza) - get_form_layout : function (Room, actor : string) : table - process_form : function (Room, table, Stanza) : boolean - - -- Properties and configuration - get_name : function (Room) : string - set_name : function (Room, string) : boolean - get_description : function (Room) : string - set_description : function (Room, string) : boolean - get_language : function (Room) : string - set_language : function (Room, string) : boolean - get_hidden : function (Room) : boolean - set_hidden : function (Room, boolean) - get_public : function (Room) : boolean - set_public : function (Room, boolean) - get_password : function (Room) : string - set_password : function (Room, string) : boolean - get_members_only : function (Room) : boolean - set_members_only : function (Room, boolean) : boolean - get_allow_member_invites : function (Room) : boolean - set_allow_member_invites : function (Room, boolean) : boolean - get_moderated : function (Room) : boolean - set_moderated : function (Room, boolean) : boolean - get_persistent : function (Room) : boolean - set_persistent : function (Room, boolean) : boolean - get_changesubject : function (Room) : boolean - set_changesubject : function (Room, boolean) : boolean - get_subject : function (Room) : string - set_subject : function (Room, string) : boolean - get_historylength : function (Room) : integer - set_historylength : function (Room, integer) : boolean - get_presence_broadcast : function (Room) : { Role : boolean } - set_presence_broadcast : function (Room, { Role : boolean }) : boolean - - is_anonymous_for : function (Room, jid : string) : boolean - get_salt : function (Room) : string - get_occupant_id : function (Room, Occupant) - - -- Room teardown - clear : function (Room, x : Stanza) - destroy : function (Room, newjid : string, reason : string, password : string) : boolean - - -- Room state persistence - record FrozenRoom - _jid : string - _data : { string : any } - _affiliation_data : { string : { string : any } } - -- { string : Affiliation } - end - - record StateEntry - bare_jid : string - role : Role - jid : string - end - - save : function (Room, forced : boolean, savestate : boolean) : boolean - freeze : function (Room, live : boolean) : FrozenRoom, { string : StateEntry } -end - -local record lib - new_room : function (jid : string, config : { string : any }) : Room - restore_room : function (Room.FrozenRoom, { string : Room.StateEntry }) : Room - - room_mt : metatable -end - -return lib diff --git a/teal-src/prosody/core/storagemanager.d.tl b/teal-src/prosody/core/storagemanager.d.tl new file mode 100644 index 00000000..bd82357c --- /dev/null +++ b/teal-src/prosody/core/storagemanager.d.tl @@ -0,0 +1,74 @@ +-- Storage local record API Description +-- +-- This is written as a TypedLua description + +-- Key-Value stores (the default) + +local stanza = require"prosody.util.stanza".stanza_t + +local record keyval_store + get : function ( keyval_store, string ) : any , string + set : function ( keyval_store, string, any ) : boolean, string +end + +-- Map stores (key-key-value stores) + +local record map_store + get : function ( map_store, string, any ) : any, string + set : function ( map_store, string, any, any ) : boolean, string + set_keys : function ( map_store, string, { any : any }) : boolean, string + remove : table +end + +-- Archive stores + +local record archive_query + start : number -- timestamp + ["end"]: number -- timestamp + with : string + after : string -- archive id + before : string -- archive id + total : boolean +end + +local record archive_store + -- Optional set of capabilities + caps : { + -- Optional total count of matching items returned as second return value from :find() + string : any + } + + -- Add to the archive + append : function ( archive_store, string, string, any, number, string ) : string, string + + -- Iterate over archive + type iterator = function () : string, any, number, string + find : function ( archive_store, string, archive_query ) : iterator, integer + + -- Removal of items. API like find. Optional + delete : function ( archive_store, string, archive_query ) : boolean | number, string + + -- Array of dates which do have messages (Optional) + dates : function ( archive_store, string ) : { string }, string + + -- Map of counts per "with" field + summary : function ( archive_store, string, archive_query ) : { string : integer }, string + + -- Map-store API + get : function ( archive_store, string, string ) : stanza, number, string + get : function ( archive_store, string, string ) : nil, string + set : function ( archive_store, string, string, stanza, number, string ) : boolean, string +end + +-- This represents moduleapi +local record coremodule + -- If the first string is omitted then the name of the module is used + -- The second string is one of "keyval" (default), "map" or "archive" + open_store : function (archive_store, string, string) : keyval_store, string + open_store : function (archive_store, string, string) : map_store, string + open_store : function (archive_store, string, string) : archive_store, string + + -- Other module methods omitted +end + +return coremodule diff --git a/teal-src/prosody/core/usermanager.d.tl b/teal-src/prosody/core/usermanager.d.tl new file mode 100644 index 00000000..fc055004 --- /dev/null +++ b/teal-src/prosody/core/usermanager.d.tl @@ -0,0 +1,46 @@ +local Role = require "prosody.util.roles".Role; + +local record usermanager + record AuthProvider + -- TODO + end + record AccountInfo + created : number + password_updated : any + enabled : boolean + end + + -- Users + test_password : function (username : string, host : string, password : string) : boolean + get_password : function (username : string, host : string) : string, string + set_password : function (username : string, host : string, password : string) : boolean, string + get_account_info : function (username : string, host : string) : AccountInfo + user_exists : function (username : string, host : string) : boolean + create_user : function (username : string, password : string, host : string) : boolean, string + delete_user : function (username : string, host : string) : boolean, string + user_is_enabled : function (username : string, host : string) : boolean, string + enable_user : function (username : string, host : string) : boolean, string + disable_user : function (username : string, host : string) : boolean, string + users : function (host : string) : function () : string + + -- Roles + get_user_role : function (username : string, host : string) : Role + set_user_role : function (username : string, host : string, role_name : string) : boolean, string + user_can_assume_role : function (username : string, host : string, role_name : string) : boolean + add_user_secondary_role : function (username : string, host: string, role_name : string) : boolean, string + remove_user_secondary_role : function (username : string, host: string, role_name : string) : boolean, string + get_user_secondary_roles : function (username : string, host : string) : { string : Role } + get_users_with_role : function (role : string, host : string) : { string } + get_jid_role : function (jid : string, host : string) : Role + set_jid_role : function (jid : string, host : string, role_name : string) : boolean + get_jids_with_role : function (role : string, host : string) : { string } + get_role_by_name : function (role_name : string) : Role + + -- Etc + get_provider : function (host : string) : AuthProvider + get_sasl_handler : function (host : string, session : table) : table + initialize_host : function (host : string) + new_null_provider : function () : AuthProvider +end + +return usermanager diff --git a/teal-src/prosody/net/http.d.tl b/teal-src/prosody/net/http.d.tl new file mode 100644 index 00000000..08542e45 --- /dev/null +++ b/teal-src/prosody/net/http.d.tl @@ -0,0 +1,86 @@ +local Promise = require "prosody.util.promise".Promise; + +local record sslctx -- from LuaSec +end + +local record lib + + enum http_method + "GET" + "HEAD" + "POST" + "PUT" + "OPTIONS" + "DELETE" + -- etc? + end + + record http_client_options + sslctx : sslctx + end + + record http_options + id : string + onlystatus : boolean + body : string + method : http_method + headers : { string : string } + insecure : boolean + suppress_errors : boolean + streaming_handler : function + suppress_url : boolean + sslctx : sslctx + end + + record http_request + host : string + port : string + enum scheme + "http" + "https" + end + scheme : scheme + url : string + userinfo : string + path : string + + method : http_method + headers : { string : string } + + insecure : boolean + suppress_errors : boolean + streaming_handler : function + http : http_client + time : integer + id : string + callback : http_callback + end + + record http_response + end + + type http_callback = function (string, number, http_response, http_request) + + record http_client + options : http_client_options + request : function (http_client, string, http_options, http_callback) + end + + request : function (string, http_options, http_callback) : Promise, string + default : http_client + new : function (http_client_options) : http_client + events : table + -- COMPAT + urlencode : function (string) : string + urldecode : function (string) : string + formencode : function ({ string : string }) : string + formdecode : function (string) : { string : string } + destroy_request : function (http_request) + + enum available_features + "sni" + end + features : { available_features : boolean } +end + +return lib diff --git a/teal-src/prosody/net/http/codes.d.tl b/teal-src/prosody/net/http/codes.d.tl new file mode 100644 index 00000000..65d004fc --- /dev/null +++ b/teal-src/prosody/net/http/codes.d.tl @@ -0,0 +1,2 @@ +local type response_codes = { integer : string } +return response_codes diff --git a/teal-src/prosody/net/http/errors.d.tl b/teal-src/prosody/net/http/errors.d.tl new file mode 100644 index 00000000..a9b6ea6c --- /dev/null +++ b/teal-src/prosody/net/http/errors.d.tl @@ -0,0 +1,22 @@ +local record http_errors + enum known_conditions + "cancelled" + "connection-closed" + "certificate-chain-invalid" + "certificate-verify-failed" + "connection failed" + "invalid-url" + "unable to resolve service" + end + type registry_keys = known_conditions | integer + record error + type : string + condition : string + code : integer + text : string + end + registry : { registry_keys : error } + new : function (integer, known_conditions, table) + new : function (integer, string, table) +end +return http_errors diff --git a/teal-src/prosody/net/http/files.d.tl b/teal-src/prosody/net/http/files.d.tl new file mode 100644 index 00000000..d0ba5c1c --- /dev/null +++ b/teal-src/prosody/net/http/files.d.tl @@ -0,0 +1,14 @@ +local record serve_options + path : string + mime_map : { string : string } + cache_size : integer + cache_max_file_size : integer + index_files : { string } + directory_index : boolean +end + +local record http_files + serve : function(serve_options|string) : function +end + +return http_files diff --git a/teal-src/prosody/net/http/parser.d.tl b/teal-src/prosody/net/http/parser.d.tl new file mode 100644 index 00000000..1cd6ccf4 --- /dev/null +++ b/teal-src/prosody/net/http/parser.d.tl @@ -0,0 +1,58 @@ +local record httpstream + feed : function(httpstream, string) +end + +local type sink_cb = function () + +local record httppacket + enum http_method + "HEAD" + "GET" + "POST" + "PUT" + "DELETE" + "OPTIONS" + -- etc + end + method : http_method + record url_details + path : string + query : string + end + url : url_details + path : string + enum http_version + "1.0" + "1.1" + end + httpversion : http_version + headers : { string : string } + body : string | boolean + body_sink : sink_cb + chunked : boolean + partial : boolean +end + +local enum error_conditions + "cancelled" + "connection-closed" + "certificate-chain-invalid" + "certificate-verify-failed" + "connection failed" + "invalid-url" + "unable to resolve service" +end + +local type success_cb = function (httppacket) +local type error_cb = function (error_conditions) + +local enum stream_mode + "client" + "server" +end + +local record lib + new : function (success_cb, error_cb, stream_mode) : httpstream +end + +return lib diff --git a/teal-src/prosody/net/http/server.d.tl b/teal-src/prosody/net/http/server.d.tl new file mode 100644 index 00000000..5a83af7e --- /dev/null +++ b/teal-src/prosody/net/http/server.d.tl @@ -0,0 +1,6 @@ + +local record http_server + -- TODO +end + +return http_server diff --git a/teal-src/prosody/net/server.d.tl b/teal-src/prosody/net/server.d.tl new file mode 100644 index 00000000..bb61f677 --- /dev/null +++ b/teal-src/prosody/net/server.d.tl @@ -0,0 +1,65 @@ +local record server + record LuaSocketTCP + end + record LuaSecCTX + end + + record extra_settings + end + + record interface + end + enum socket_type + "tcp" + "tcp6" + "tcp4" + end + + record listeners + onconnect : function (interface) + ondetach : function (interface) + onattach : function (interface, string) + onincoming : function (interface, string, string) + ondrain : function (interface) + onreadtimeout : function (interface) + onstarttls : function (interface) + onstatus : function (interface, string) + ondisconnect : function (interface, string) + end + + get_backend : function () : string + + type port = string | integer + enum read_mode + "*a" + "*l" + end + type read_size = read_mode | integer + addserver : function (string, port, listeners, read_size, LuaSecCTX) : interface + addclient : function (string, port, listeners, read_size, LuaSecCTX, socket_type, extra_settings) : interface + record listen_config + read_size : read_size + tls_ctx : LuaSecCTX + tls_direct : boolean + sni_hosts : { string : LuaSecCTX } + end + listen : function (string, port, listeners, listen_config) : interface + enum quitting + "quitting" + end + loop : function () : quitting + closeall : function () + setquitting : function (boolean | quitting) + + wrapclient : function (LuaSocketTCP, string, port, listeners, read_size, LuaSecCTX, extra_settings) : interface + wrapserver : function (LuaSocketTCP, string, port, listeners, listen_config) : interface + watchfd : function (integer | LuaSocketTCP, function (interface), function (interface)) : interface + link : function () + + record config + end + set_config : function (config) + +end + +return server diff --git a/teal-src/prosody/plugins/mod_cron.tl b/teal-src/prosody/plugins/mod_cron.tl new file mode 100644 index 00000000..b71b5f74 --- /dev/null +++ b/teal-src/prosody/plugins/mod_cron.tl @@ -0,0 +1,106 @@ +module:set_global(); + +local async = require "prosody.util.async"; +local datetime = require "prosody.util.datetime"; + +local record map_store + -- TODO move to somewhere sensible + get : function (map_store, string, K) : V + set : function (map_store, string, K, V) +end + +local enum frequency + "hourly" + "daily" + "weekly" +end + +local record task_spec + id : string -- unique id + name : string -- name or short description + when : frequency + last : integer + run : function (task_spec, integer) + save : function (task_spec, integer) +end + +local record task_event + source : module + item : task_spec +end + +local periods : { frequency : integer } = { hourly = 3600, daily = 86400, weekly = 7*86400 } + +local active_hosts : { string : boolean } = { } + +function module.add_host(host_module : moduleapi) + + local last_run_times = host_module:open_store("cron", "map") as map_store; + active_hosts[host_module.host] = true; + + local function save_task(task : task_spec, started_at : integer) + last_run_times:set(nil, task.id, started_at); + end + + local function task_added(event : task_event) : boolean + local task = event.item; + if task.name == nil then + task.name = task.when; + end + if task.id == nil then + task.id = event.source.name .. "/" .. task.name:gsub("%W", "_"):lower(); + end + if task.last == nil then + task.last = last_run_times:get(nil, task.id); + end + task.save = save_task; + module:log("debug", "%s task %s added, last run %s", task.when, task.id, + task.last and datetime.datetime(task.last) or "never"); + if task.last == nil then + -- initialize new tasks so e.g. daily tasks run at ~midnight UTC for now + local now = os.time(); + task.last = now - now % periods[task.when]; + end + return true; + end + + local function task_removed(event : task_event) : boolean + local task = event.item; + host_module:log("debug", "Task %s removed", task.id); + return true; + end + + host_module:handle_items("task", task_added, task_removed, true); + + function host_module.unload() + active_hosts[host_module.host]=nil; + end +end + +local function should_run(when : frequency, last : integer) : boolean + return not last or last + periods[when]*0.995 <= os.time(); +end + +local function run_task(task : task_spec) + local started_at = os.time(); + task:run(started_at); + task.last = started_at; + task:save(started_at); +end + +local task_runner : async.runner_t = async.runner(run_task); +scheduled = module:add_timer(1, function() : integer + module:log("info", "Running periodic tasks"); + local delay = 3600; + for host in pairs(active_hosts) do + module:log("debug", "Running periodic tasks for host %s", host); + for _, task in ipairs(module:context(host):get_host_items("task") as { task_spec } ) do + module:log("debug", "Considering %s task %s (%s)", task.when, task.id, task.run); + if should_run(task.when, task.last) then task_runner:run(task); end + end + end + module:log("debug", "Wait %ds", delay); + return delay; +end); + +-- TODO measure load, pick a good time to do stuff diff --git a/teal-src/prosody/plugins/muc/muc.lib.d.tl b/teal-src/prosody/plugins/muc/muc.lib.d.tl new file mode 100644 index 00000000..6e9663a1 --- /dev/null +++ b/teal-src/prosody/plugins/muc/muc.lib.d.tl @@ -0,0 +1,178 @@ +local Stanza = require "prosody.util.stanza".stanza_t + +local record Room + jid : string + + enum Affiliation + "outcast" + "none" + "member" + "admin" + "owner" + end + + enum Role + "none" + "visitor" + "participant" + "moderator" + end + + record Occupant + bare_jid : string + nick : string + sessions : { string : Stanza } + role : Role + jid : string + + choose_new_primary : function (Occupant) : string + set_session : function (Occupant, string, Stanza, boolean) + remove_session : function (Occupant, string) + each_session : function (Occupant) -- TODO Iterator + + end + + -- Private properties + _jid_nick : { string : string } + _occupants : { string : Occupant } + _data : { string : any } + _affiliations : { string : Affiliation } + _affiliation_data : { string : { string : any } } + + -- Occupant methods + get_occupant_jid : function (Room, real_jid : string) : string + new_occupant : function (Room, bare_real_jid : string, nick : string) : Occupant + get_occupant_by_nick : function (Room, nick : string) : Occupant + type OccupantIterator = function ({string:Occupant}, occupant_jid : string) : string, Occupant + each_occupant : function (Room, read_only : boolean) : OccupantIterator, {string:Occupant}, nil + has_occupant : function (Room) : boolean + get_occupant_by_real_jid : function (Room, real_jid : string) : Occupant + save_occupant :function (Room, Occupant) : Occupant + + -- Affiliation methods + type AffiliationIterator = function (any, jid : string) : string, Affiliation + get_affiliation : function (Room, jid : string) : Affiliation + each_affiliation : function (Room, Affiliation) : AffiliationIterator, nil, nil + set_affiliation : function (Room, jid : string, Affiliation, reason : string, data : { string : any }) : boolean, string, string, string -- ok + error tripplet + get_affiliation_data : function (Room, jid : string, key : string) : any + set_affiliation_data : function (Room, jid : string, key : string, value : any) : boolean + get_registered_nick : function (Room, jid : string) : string + get_registered_jid : function (Room, nick : string) : string + + -- Role methods + get_default_role : function (Room, Affiliation) : Role, integer + get_role : function (Room, nick : string) : Role + may_set_role : function (Room, actor : string, Occupant, Role) : boolean + set_role : function (Room, actor : string, occupant_jid : string, Role, reason : string) : boolean, string, string, string + + -- Routing input, generally handled by mod_muc and hooked up to Prosody routing events + handle_first_presence : function (Room, table, Stanza) : boolean + handle_normal_presence : function (Room, table, Stanza) : boolean + handle_presence_to_room : function (Room, table, Stanza) : boolean + handle_presence_to_occupant : function (Room, table, Stanza) : boolean + handle_message_to_room : function (Room, table, Stanza) : boolean + handle_message_to_occupant : function (Room, table, Stanza) : boolean + handle_groupchat_to_room : function (Room, table, Stanza) : boolean + handle_iq_to_occupant : function (Room, table, Stanza) : boolean + handle_disco_info_get_query : function (Room, table, Stanza) : boolean + handle_disco_items_get_query : function (Room, table, Stanza) : boolean + handle_admin_query_set_command : function (Room, table, Stanza) : boolean + handle_admin_query_get_command : function (Room, table, Stanza) : boolean + handle_owner_query_get_to_room : function (Room, table, Stanza) : boolean + handle_owner_query_set_to_room : function (Room, table, Stanza) : boolean + handle_mediated_invite : function (Room, table, Stanza) : boolean + handle_mediated_decline : function (Room, table, Stanza) : boolean + handle_role_request : function (Room, table, Stanza) : boolean + handle_register_iq : function (Room, table, Stanza) : boolean + handle_kickable : function (Room, table, Stanza) : boolean + + -- Routing output + broadcast : function (Room, Stanza, function (nick : string, Occupant) : boolean) + broadcast_message : function (Room, Stanza) : boolean + route_stanza : function (Room, Stanza) + route_to_occupant : function (Room, Occupant, Stanza) + + -- Sending things to someone joining + publicise_occupant_status : function (Room, Occupant, x : Stanza, nick : string, actor : string, reason : string, prev_role : Role, force_unavailable : boolean, recipient : Occupant) + send_occupant_list : function (Room, to : string, filter : function (occupant_jid : string, Occupant) : boolean) + send_history : function (Room, Stanza) + send_subject : function (Room, to : string, time : number) + + respond_to_probe : function (Room, table, Stanza, Occupant) + + -- Constructors for various answer stanzas + get_disco_info : function (Room, Stanza) : Stanza + get_disco_items : function (Room, Stanza) : Stanza + + build_item_list : function (Room, Occupant, Stanza, is_anonymous : boolean, nick : string, actor_nick : string, actor_jid : string, reason : string) : Stanza + build_unavailable_presence : function (Room, from_muc_jid : string, to_jid : string) : Stanza + + -- Form handling + send_form : function (Room, table, Stanza) + get_form_layout : function (Room, actor : string) : table + process_form : function (Room, table, Stanza) : boolean + + -- Properties and configuration + get_name : function (Room) : string + set_name : function (Room, string) : boolean + get_description : function (Room) : string + set_description : function (Room, string) : boolean + get_language : function (Room) : string + set_language : function (Room, string) : boolean + get_hidden : function (Room) : boolean + set_hidden : function (Room, boolean) + get_public : function (Room) : boolean + set_public : function (Room, boolean) + get_password : function (Room) : string + set_password : function (Room, string) : boolean + get_members_only : function (Room) : boolean + set_members_only : function (Room, boolean) : boolean + get_allow_member_invites : function (Room) : boolean + set_allow_member_invites : function (Room, boolean) : boolean + get_moderated : function (Room) : boolean + set_moderated : function (Room, boolean) : boolean + get_persistent : function (Room) : boolean + set_persistent : function (Room, boolean) : boolean + get_changesubject : function (Room) : boolean + set_changesubject : function (Room, boolean) : boolean + get_subject : function (Room) : string + set_subject : function (Room, string) : boolean + get_historylength : function (Room) : integer + set_historylength : function (Room, integer) : boolean + get_presence_broadcast : function (Room) : { Role : boolean } + set_presence_broadcast : function (Room, { Role : boolean }) : boolean + + is_anonymous_for : function (Room, jid : string) : boolean + get_salt : function (Room) : string + get_occupant_id : function (Room, Occupant) + + -- Room teardown + clear : function (Room, x : Stanza) + destroy : function (Room, newjid : string, reason : string, password : string) : boolean + + -- Room state persistence + record FrozenRoom + _jid : string + _data : { string : any } + _affiliation_data : { string : { string : any } } + -- { string : Affiliation } + end + + record StateEntry + bare_jid : string + role : Role + jid : string + end + + save : function (Room, forced : boolean, savestate : boolean) : boolean + freeze : function (Room, live : boolean) : FrozenRoom, { string : StateEntry } +end + +local record lib + new_room : function (jid : string, config : { string : any }) : Room + restore_room : function (Room.FrozenRoom, { string : Room.StateEntry }) : Room + + room_mt : metatable +end + +return lib diff --git a/teal-src/prosody/util/array.d.tl b/teal-src/prosody/util/array.d.tl new file mode 100644 index 00000000..70bf2624 --- /dev/null +++ b/teal-src/prosody/util/array.d.tl @@ -0,0 +1,9 @@ +local record array_t + { T } +end + +local record lib + metamethod __call : function () : array_t +end + +return lib diff --git a/teal-src/prosody/util/async.d.tl b/teal-src/prosody/util/async.d.tl new file mode 100644 index 00000000..a2e41cd6 --- /dev/null +++ b/teal-src/prosody/util/async.d.tl @@ -0,0 +1,42 @@ +local record lib + ready : function () : boolean + waiter : function (num : integer, allow_many : boolean) : function (), function () + guarder : function () : function (id : function ()) : function () | nil + record runner_t + func : function (T) + thread : thread + enum state_e + -- from Lua manual + "running" + "suspended" + "normal" + "dead" + + -- from util.async + "ready" + "error" + end + state : state_e + notified_state : state_e + queue : { T } + type watcher_t = function (runner_t, ... : any) + type watchers_t = { state_e : watcher_t } + data : any + id : string + + run : function (runner_t, T) : boolean, state_e, integer + enqueue : function (runner_t, T) : runner_t + log : function (runner_t, string, string, ... : any) + onready : function (runner_t, function) : runner_t + onready : function (runner_t, function) : runner_t + onwaiting : function (runner_t, function) : runner_t + onerror : function (runner_t, function) : runner_t + end + runner : function (function (T), runner_t.watchers_t, any) : runner_t + wait_for : function (any) : any, any + sleep : function (t:number) + + -- set_nexttick = function(new_next_tick) next_tick = new_next_tick; end; + -- set_schedule_function = function (new_schedule_function) schedule_task = new_schedule_function; end; +end +return lib diff --git a/teal-src/prosody/util/bitcompat.d.tl b/teal-src/prosody/util/bitcompat.d.tl new file mode 100644 index 00000000..18adf725 --- /dev/null +++ b/teal-src/prosody/util/bitcompat.d.tl @@ -0,0 +1,8 @@ +local record lib + band : function (integer, integer, ... : integer) : integer + bor : function (integer, integer, ... : integer) : integer + bxor : function (integer, integer, ... : integer) : integer + lshift : function (integer, integer) : integer + rshift : function (integer, integer) : integer +end +return lib diff --git a/teal-src/prosody/util/compat.d.tl b/teal-src/prosody/util/compat.d.tl new file mode 100644 index 00000000..da9c6083 --- /dev/null +++ b/teal-src/prosody/util/compat.d.tl @@ -0,0 +1,4 @@ +local record lib + xpcall : function (function, function, ...:any):boolean, any +end +return lib diff --git a/teal-src/prosody/util/crand.d.tl b/teal-src/prosody/util/crand.d.tl new file mode 100644 index 00000000..b40cb67e --- /dev/null +++ b/teal-src/prosody/util/crand.d.tl @@ -0,0 +1,6 @@ +local record lib + bytes : function (n : integer) : string + enum sourceid "OpenSSL" "arc4random()" "Linux" end + _source : sourceid +end +return lib diff --git a/teal-src/prosody/util/crypto.d.tl b/teal-src/prosody/util/crypto.d.tl new file mode 100644 index 00000000..cf0b0d1b --- /dev/null +++ b/teal-src/prosody/util/crypto.d.tl @@ -0,0 +1,29 @@ +local record lib + record key + private_pem : function (key) : string + public_pem : function (key) : string + get_type : function (key) : string + end + + generate_ed25519_keypair : function () : key + ed25519_sign : function (key, string) : string + ed25519_verify : function (key, string, string) : boolean + + ecdsa_sha256_sign : function (key, string) : string + ecdsa_sha256_verify : function (key, string, string) : boolean + parse_ecdsa_signature : function (string) : string, string + build_ecdsa_signature : function (string, string) : string + + import_private_pem : function (string) : key + import_public_pem : function (string) : key + + aes_128_gcm_encrypt : function (key, string, string) : string + aes_128_gcm_decrypt : function (key, string, string) : string + aes_256_gcm_encrypt : function (key, string, string) : string + aes_256_gcm_decrypt : function (key, string, string) : string + + + version : string + _LIBCRYPTO_VERSION : string +end +return lib diff --git a/teal-src/prosody/util/dataforms.d.tl b/teal-src/prosody/util/dataforms.d.tl new file mode 100644 index 00000000..3dad2776 --- /dev/null +++ b/teal-src/prosody/util/dataforms.d.tl @@ -0,0 +1,54 @@ +local stanza_t = require "prosody.util.stanza".stanza_t + +local record lib + record dataform + title : string + instructions : string + + record form_field + + enum field_type + "boolean" + "fixed" + "hidden" + "jid-multi" + "jid-single" + "list-multi" + "list-single" + "text-multi" + "text-private" + "text-single" + end + + type : field_type + var : string -- protocol name + name : string -- internal name + + label : string + desc : string + + datatype : string + range_min : number + range_max : number + + value : any -- depends on field_type + options : table + end + + { form_field } + + enum form_type + "form" + "submit" + "cancel" + "result" + end + + form : function ( dataform, { string : any }, form_type ) : stanza_t + data : function ( dataform, stanza_t ) : { string : any } + end + + new : function ( dataform ) : dataform +end + +return lib diff --git a/teal-src/prosody/util/datamapper.tl b/teal-src/prosody/util/datamapper.tl new file mode 100644 index 00000000..89d5e29b --- /dev/null +++ b/teal-src/prosody/util/datamapper.tl @@ -0,0 +1,379 @@ +-- Copyright (C) 2021 Kim Alvefur +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +-- Based on +-- https://json-schema.org/draft/2020-12/json-schema-core.html +-- https://json-schema.org/draft/2020-12/json-schema-validation.html +-- http://spec.openapis.org/oas/v3.0.1#xmlObject +-- https://github.com/OAI/OpenAPI-Specification/issues/630 (text:true) +-- +-- XML Object Extensions: +-- text to refer to the text content at the same time as attributes +-- x_name_is_value for enum fields where the is the value +-- x_single_attribute for +-- +-- TODO pointers +-- TODO cleanup / refactor +-- TODO s/number/integer/ once we have appropriate math.type() compat +-- + +if not math.type then require "prosody.util.mathcompat" end + +local st = require "prosody.util.stanza"; +local json = require "prosody.util.json" +local pointer = require "prosody.util.jsonpointer"; + +local json_type_name = json.json_type_name; +local json_schema_object = require "prosody.util.jsonschema" +local type schema_t = boolean | json_schema_object + +local function toboolean ( s : string ) : boolean + if s == "true" or s == "1" then + return true + elseif s == "false" or s == "0" then + return false + elseif s then + return true + end +end + +local function totype(t : json_type_name, s : string) : any + if not s then return nil end + if t == "string" then + return s; + elseif t == "boolean" then + return toboolean(s) + elseif t == "number" or t == "integer" then + return tonumber(s) + end +end + +local enum value_goes + "in_tag_name" + "in_text" + "in_text_tag" + "in_attribute" + "in_single_attribute" + "in_children" + "in_wrapper" +end + +local function resolve_schema(schema : schema_t, root : json_schema_object) : schema_t + if schema is json_schema_object then + if schema["$ref"] and schema["$ref"]:sub(1, 1) == "#" then + return pointer.resolve(root as table, schema["$ref"]:sub(2)) as schema_t; + end + end + return schema; +end + +local function guess_schema_type(schema : json_schema_object) : json_type_name + local schema_types = schema.type + if schema_types is json_type_name then + return schema_types + elseif schema_types ~= nil then + error "schema has unsupported 'type' property" + elseif schema.properties then + return "object" + elseif schema.items then + return "array" + end + return "string" -- default assumption +end + +local function unpack_propschema( propschema : schema_t, propname : string, current_ns : string ) + : json_type_name, value_goes, string, string, string, string, { any } + local proptype : json_type_name = "string" + local value_where : value_goes = propname and "in_text_tag" or "in_text" + local name = propname + local namespace : string + local prefix : string + local single_attribute : string + local enums : { any } + + if propschema is json_schema_object then + proptype = guess_schema_type(propschema); + elseif propschema is string then -- Teal says this can never be a string, but it could before so best be sure + error("schema as string is not supported: "..propschema.." {"..current_ns.."}"..propname) + end + + if proptype == "object" or proptype == "array" then + value_where = "in_children" + end + + if propschema is json_schema_object then + local xml = propschema.xml + if xml then + if xml.name then + name = xml.name + end + if xml.namespace and xml.namespace ~= current_ns then + namespace = xml.namespace + end + if xml.prefix then + prefix = xml.prefix + end + if proptype == "array" and xml.wrapped then + value_where = "in_wrapper" + elseif xml.attribute then + value_where = "in_attribute" + elseif xml.text then + value_where = "in_text" + elseif xml.x_name_is_value then + value_where = "in_tag_name" + elseif xml.x_single_attribute then + single_attribute = xml.x_single_attribute + value_where = "in_single_attribute" + end + end + if propschema["const"] then + enums = { propschema["const"] } + elseif propschema["enum"] then + enums = propschema["enum"] + end + end + + return proptype, value_where, name, namespace, prefix, single_attribute, enums +end + +local parse_object : function (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { string : any } +local parse_array : function (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { any } + +local function extract_value (s : st.stanza_t, value_where : value_goes, proptype : json.json_type_name, name : string, namespace : string, prefix : string, single_attribute : string, enums : { any }) : string + if value_where == "in_tag_name" then + local c : st.stanza_t + if proptype == "boolean" then + c = s:get_child(name, namespace); + elseif enums and proptype == "string" then + -- XXX O(n²) ? + -- Probably better to flip the table and loop over :childtags(nil, ns), should be 2xO(n) + -- BUT works first, optimize later + for i = 1, #enums do + c = s:get_child(enums[i] as string, namespace); + if c then break end + end + else + c = s:get_child(nil, namespace); + end + if c then + return c.name; + end + elseif value_where == "in_attribute" then + local attr = name + if prefix then + attr = prefix .. ':' .. name + elseif namespace and namespace ~= s.attr.xmlns then + attr = namespace .. "\1" .. name + end + return s.attr[attr] + + elseif value_where == "in_text" then + return s:get_text() + + elseif value_where == "in_single_attribute" then + local c = s:get_child(name, namespace) + return c and c.attr[single_attribute] + elseif value_where == "in_text_tag" then + return s:get_child_text(name, namespace) + end +end + +function parse_object (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { string : any } + local out : { string : any } = {} + schema = resolve_schema(schema, root) + if schema is json_schema_object and schema.properties then + for prop, propschema in pairs(schema.properties) do + propschema = resolve_schema(propschema, root) + + local proptype, value_where, name, namespace, prefix, single_attribute, enums = unpack_propschema(propschema, prop, s.attr.xmlns) + + if value_where == "in_children" and propschema is json_schema_object then + if proptype == "object" then + local c = s:get_child(name, namespace) + if c then + out[prop] = parse_object(propschema, c, root); + end + elseif proptype == "array" then + local a = parse_array(propschema, s, root); + if a and a[1] ~= nil then + out[prop] = a; + end + else + error "unreachable" + end + elseif value_where == "in_wrapper" and propschema is json_schema_object and proptype == "array" then + local wrapper = s:get_child(name, namespace); + if wrapper then + out[prop] = parse_array(propschema, wrapper, root); + end + else + local value : string = extract_value (s, value_where, proptype, name, namespace, prefix, single_attribute, enums) + + out[prop] = totype(proptype, value) + end + end + end + + return out +end + +function parse_array (schema : json_schema_object, s : st.stanza_t, root : json_schema_object) : { any } + local itemschema : schema_t = resolve_schema(schema.items, root); + local proptype, value_where, child_name, namespace, prefix, single_attribute, enums = unpack_propschema(itemschema, nil, s.attr.xmlns) + local attr_name : string + if value_where == "in_single_attribute" then -- FIXME this shouldn't be needed + value_where = "in_attribute"; + attr_name = single_attribute; + end + local out : { any } = {} + + if proptype == "object" then + if itemschema is json_schema_object then + for c in s:childtags(child_name, namespace) do + table.insert(out, parse_object(itemschema, c, root)); + end + else + error "array items must be schema object" + end + elseif proptype == "array" then + if itemschema is json_schema_object then + for c in s:childtags(child_name, namespace) do + table.insert(out, parse_array(itemschema, c, root)); + end + end + else + for c in s:childtags(child_name, namespace) do + local value : string = extract_value (c, value_where, proptype, attr_name or child_name, namespace, prefix, single_attribute, enums) + + table.insert(out, totype(proptype, value)); + end + end + return out; +end + +local function parse (schema : json_schema_object, s : st.stanza_t) : table + local s_type = guess_schema_type(schema) + if s_type == "object" then + return parse_object(schema, s, schema) + elseif s_type == "array" then + return parse_array(schema, s, schema) + else + error "top-level scalars unsupported" + end +end + +local function toxmlstring(proptype : json_type_name, v : any) : string + if proptype == "string" and v is string then + return v + elseif proptype == "number" and v is number then + return string.format("%g", v) + elseif proptype == "integer" and v is number then -- TODO is integer + return string.format("%d", v) + elseif proptype == "boolean" then + return v and "1" or "0" + end +end + +local unparse : function (json_schema_object, table, string, string, st.stanza_t, json_schema_object) : st.stanza_t + +local function unparse_property(out : st.stanza_t, v : any, proptype : json_type_name, propschema : schema_t, value_where : value_goes, name : string, namespace : string, current_ns : string, prefix : string, single_attribute : string, root : json_schema_object) + + if value_where == "in_attribute" then + local attr = name + if prefix then + attr = prefix .. ':' .. name + elseif namespace and namespace ~= current_ns then + attr = namespace .. "\1" .. name + end + + out.attr[attr] = toxmlstring(proptype, v) + elseif value_where == "in_text" then + out:text(toxmlstring(proptype, v)) + elseif value_where == "in_single_attribute" then + assert(single_attribute) + local propattr : { string : string } = {} + + if namespace and namespace ~= current_ns then + propattr.xmlns = namespace + end + + propattr[single_attribute] = toxmlstring(proptype, v) + out:tag(name, propattr):up(); + + else + local propattr : { string : string } + if namespace ~= current_ns then + propattr = { xmlns = namespace } + end + if value_where == "in_tag_name" then + if proptype == "string" and v is string then + out:tag(v, propattr):up(); + elseif proptype == "boolean" and v == true then + out:tag(name, propattr):up(); + end + elseif proptype == "object" and propschema is json_schema_object and v is table then + local c = unparse(propschema, v, name, namespace, nil, root); + if c then + out:add_direct_child(c); + end + elseif proptype == "array" and propschema is json_schema_object and v is table then + if value_where == "in_wrapper" then + local c = unparse(propschema, v, name, namespace, nil, root); + if c then + out:add_direct_child(c); + end + else + unparse(propschema, v, name, namespace, out, root); + end + else + out:text_tag(name, toxmlstring(proptype, v), propattr) + end + end +end + +function unparse ( schema : json_schema_object, t : table, current_name : string, current_ns : string, ctx : st.stanza_t, root : json_schema_object ) : st.stanza_t + + if root == nil then root = schema end + + if schema.xml then + if schema.xml.name then + current_name = schema.xml.name + end + if schema.xml.namespace then + current_ns = schema.xml.namespace + end + -- TODO prefix? + end + + local out = ctx or st.stanza(current_name, { xmlns = current_ns }) + + local s_type = guess_schema_type(schema) + if s_type == "object" then + + for prop, propschema in pairs(schema.properties) do + propschema = resolve_schema(propschema, root) + local v = t[prop] + + if v ~= nil then + local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(propschema, prop, current_ns) + unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) + end + end + return out; + + elseif s_type == "array" then + local itemschema = resolve_schema(schema.items, root) + local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(itemschema, current_name, current_ns) + for _, item in ipairs(t as { string }) do + unparse_property(out, item, proptype, itemschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) + end + return out; + end +end + +return { + parse = parse, + unparse = unparse, +} diff --git a/teal-src/prosody/util/datetime.d.tl b/teal-src/prosody/util/datetime.d.tl new file mode 100644 index 00000000..9f770a73 --- /dev/null +++ b/teal-src/prosody/util/datetime.d.tl @@ -0,0 +1,9 @@ +local record lib + date : function (t : number) : string + datetime : function (t : number) : string + time : function (t : number) : string + legacy : function (t : number) : string + parse : function (t : string) : number +end + +return lib diff --git a/teal-src/prosody/util/encodings.d.tl b/teal-src/prosody/util/encodings.d.tl new file mode 100644 index 00000000..58aefa5e --- /dev/null +++ b/teal-src/prosody/util/encodings.d.tl @@ -0,0 +1,27 @@ +-- TODO many actually return Maybe(String) +local record lib + record base64 + encode : function (s : string) : string + decode : function (s : string) : string + end + record stringprep + nameprep : function (s : string, strict : boolean) : string + nodeprep : function (s : string, strict : boolean) : string + resourceprep : function (s : string, strict : boolean) : string + saslprep : function (s : string, strict : boolean) : string + end + record idna + to_ascii : function (s : string) : string + to_unicode : function (s : string) : string + end + record utf8 + valid : function (s : string) : boolean + length : function (s : string) : integer + end + record confusable + skeleton : function (s : string) : string + end + version : string +end +return lib + diff --git a/teal-src/prosody/util/error.d.tl b/teal-src/prosody/util/error.d.tl new file mode 100644 index 00000000..4c3a7196 --- /dev/null +++ b/teal-src/prosody/util/error.d.tl @@ -0,0 +1,78 @@ +local enum error_type + "auth" + "cancel" + "continue" + "modify" + "wait" +end + +local enum error_condition + "bad-request" + "conflict" + "feature-not-implemented" + "forbidden" + "gone" + "internal-server-error" + "item-not-found" + "jid-malformed" + "not-acceptable" + "not-allowed" + "not-authorized" + "policy-violation" + "recipient-unavailable" + "redirect" + "registration-required" + "remote-server-not-found" + "remote-server-timeout" + "resource-constraint" + "service-unavailable" + "subscription-required" + "undefined-condition" + "unexpected-request" +end + +local record protoerror + type : error_type + condition : error_condition + text : string + code : integer +end + +local record Error + type : error_type + condition : error_condition + text : string + code : integer + context : { any : any } + source : string +end + +local type compact_registry_item = { string, string, string, string } +local type compact_registry = { compact_registry_item } +local type registry = { string : protoerror } +local type context = { string : any } + +local record error_registry_wrapper + source : string + registry : registry + new : function (string, context) : Error + coerce : function (any, string) : any, Error + wrap : function (Error) : Error + wrap : function (string, context) : Error + is_error : function (any) : boolean +end + +local record lib + record configure_opt + auto_inject_traceback : boolean + end + new : function (protoerror, context, { string : protoerror }, string) : Error + init : function (string, string, registry | compact_registry) : error_registry_wrapper + init : function (string, registry | compact_registry) : error_registry_wrapper + is_error : function (any) : boolean + coerce : function (any, string) : any, Error + from_stanza : function (table, context, string) : Error + configure : function +end + +return lib diff --git a/teal-src/prosody/util/format.d.tl b/teal-src/prosody/util/format.d.tl new file mode 100644 index 00000000..1ff77c97 --- /dev/null +++ b/teal-src/prosody/util/format.d.tl @@ -0,0 +1,4 @@ +local record lib + format : function (string, ... : any) : string +end +return lib diff --git a/teal-src/prosody/util/hashes.d.tl b/teal-src/prosody/util/hashes.d.tl new file mode 100644 index 00000000..5c249627 --- /dev/null +++ b/teal-src/prosody/util/hashes.d.tl @@ -0,0 +1,31 @@ +local type hash = function (msg : string, hex : boolean) : string +local type hmac = function (key : string, msg : string, hex : boolean) : string +local type kdf = function (pass : string, salt : string, i : integer) : string + +local record lib + sha1 : hash + sha256 : hash + sha224 : hash + sha384 : hash + sha512 : hash + md5 : hash + sha3_256 : hash + sha3_512 : hash + blake2s256 : hash + blake2b512 : hash + hmac_sha1 : hmac + hmac_sha256 : hmac + hmac_sha224 : hmac + hmac_sha384 :hmac + hmac_sha512 : hmac + hmac_md5 : hmac + hmac_sha3_256 : hmac + hmac_sha3_512 : hmac + scram_Hi_sha1 : kdf + pbkdf2_hmac_sha1 : kdf + pbkdf2_hmac_sha256 : kdf + equals : function (string, string) : boolean + version : string + _LIBCRYPTO_VERSION : string +end +return lib diff --git a/teal-src/prosody/util/hex.d.tl b/teal-src/prosody/util/hex.d.tl new file mode 100644 index 00000000..9d84540b --- /dev/null +++ b/teal-src/prosody/util/hex.d.tl @@ -0,0 +1,8 @@ +local type s2s = function (s : string) : string +local record lib + to : s2s + from : s2s + encode : s2s + decode : s2s +end +return lib diff --git a/teal-src/prosody/util/http.d.tl b/teal-src/prosody/util/http.d.tl new file mode 100644 index 00000000..ecbe35c3 --- /dev/null +++ b/teal-src/prosody/util/http.d.tl @@ -0,0 +1,9 @@ +local record lib + urlencode : function (s : string) : string + urldecode : function (s : string) : string + formencode : function (f : { string : string }) : string + formdecode : function (s : string) : { string : string } + contains_token : function (field : string, token : string) : boolean + normalize_path : function (path : string) : string +end +return lib diff --git a/teal-src/prosody/util/human/io.d.tl b/teal-src/prosody/util/human/io.d.tl new file mode 100644 index 00000000..e4f64cd1 --- /dev/null +++ b/teal-src/prosody/util/human/io.d.tl @@ -0,0 +1,28 @@ +local record lib + getchar : function (n : integer) : string + getline : function () : string + getpass : function () : string + show_yesno : function (prompt : string) : boolean + read_password : function () : string + show_prompt : function (prompt : string) : boolean + printf : function (fmt : string, ... : any) + padleft : function (s : string, width : integer) : string + padright : function (s : string, width : integer) : string + + -- {K:V} vs T ? + record tablerow + width : integer | string -- generate an 1..100 % enum? + title : string + mapper : function (V, {K:V}) : string + key : K + enum alignments + "left" + "right" + end + align : alignments + end + type getrow = function ({ K : V }) : string + table : function ({ tablerow }, width : integer) : getrow +end + +return lib diff --git a/teal-src/prosody/util/human/units.d.tl b/teal-src/prosody/util/human/units.d.tl new file mode 100644 index 00000000..3db17c3a --- /dev/null +++ b/teal-src/prosody/util/human/units.d.tl @@ -0,0 +1,8 @@ +local lib = record + enum logbase + "b" -- 1024 + end + adjust : function (number, string) : number, string + format : function (number, string, logbase) : string +end +return lib diff --git a/teal-src/prosody/util/id.d.tl b/teal-src/prosody/util/id.d.tl new file mode 100644 index 00000000..4b6c93b7 --- /dev/null +++ b/teal-src/prosody/util/id.d.tl @@ -0,0 +1,9 @@ +local record lib + short : function () : string + medium : function () : string + long : function () : string + custom : function (integer) : function () : string + +end +return lib + diff --git a/teal-src/prosody/util/interpolation.d.tl b/teal-src/prosody/util/interpolation.d.tl new file mode 100644 index 00000000..fb653edf --- /dev/null +++ b/teal-src/prosody/util/interpolation.d.tl @@ -0,0 +1,6 @@ +local type renderer = function (string, { string : any }) : string +local type filter = function (string, any) : string +local record lib + new : function (string, string, funcs : { string : filter }) : renderer +end +return lib diff --git a/teal-src/prosody/util/ip.d.tl b/teal-src/prosody/util/ip.d.tl new file mode 100644 index 00000000..79e901c6 --- /dev/null +++ b/teal-src/prosody/util/ip.d.tl @@ -0,0 +1,20 @@ +local record iplib + enum protocol + "IPv6" + "IPv4" + end + record ip_t + addr : string + packed : string + proto : protocol + zone : string + end + + new_ip : function (string, protocol) : ip_t + commonPrefixLength : function (ip_t, ip_t) : integer + parse_cidr : function (string) : ip_t, integer + match : function (ip_t, ip_t, integer) : boolean + is_ip : function (any) : boolean + truncate : function (ip_t, integer) : ip_t +end +return iplib diff --git a/teal-src/prosody/util/jid.d.tl b/teal-src/prosody/util/jid.d.tl new file mode 100644 index 00000000..897318d9 --- /dev/null +++ b/teal-src/prosody/util/jid.d.tl @@ -0,0 +1,15 @@ +local record lib + split : function (string) : string, string, string + bare : function (string) : string + prepped_split : function (string, boolean) : string, string, string + join : function (string, string, string) : string + prep : function (string, boolean) : string + compare : function (string, string) : boolean + node : function (string) : string + host : function (string) : string + resource : function (string) : string + escape : function (string) : string + unescape : function (string) : string +end + +return lib diff --git a/teal-src/prosody/util/json.d.tl b/teal-src/prosody/util/json.d.tl new file mode 100644 index 00000000..a1c25004 --- /dev/null +++ b/teal-src/prosody/util/json.d.tl @@ -0,0 +1,18 @@ +local record lib + encode : function (any) : string + decode : function (string) : any, string + + enum json_type_name + "null" + "boolean" + "object" + "array" + "number" + "string" + "integer" + end + + type null_type = (nil) + null : null_type +end +return lib diff --git a/teal-src/prosody/util/jsonpointer.tl b/teal-src/prosody/util/jsonpointer.tl new file mode 100644 index 00000000..c21e1fbf --- /dev/null +++ b/teal-src/prosody/util/jsonpointer.tl @@ -0,0 +1,46 @@ + +local enum ptr_error + "invalid-table" + "invalid-path" +end + +local function unescape_token(escaped_token : string) : string + local unescaped = escaped_token:gsub("~1", "/"):gsub("~0", "~") + return unescaped +end + +local function resolve_json_pointer(ref : table, path : string) : any, ptr_error + local ptr_len = #path+1 + for part, pos in path:gmatch("/([^/]*)()") do + local token = unescape_token(part) + if not ref is table then + return nil + end + local idx = next(ref) + local new_ref : any + + if idx is string then + new_ref = ref[token] + elseif idx is integer then + local i = tonumber(token) + if token == "-" then i = #ref + 1 end + new_ref = ref[i+1] + else + return nil, "invalid-table" + end + + if pos as integer == ptr_len then + return new_ref + elseif new_ref is table then + ref = new_ref + elseif not ref is table then + return nil, "invalid-path" + end + + end + return ref +end + +return { + resolve = resolve_json_pointer, +} diff --git a/teal-src/prosody/util/jsonschema.tl b/teal-src/prosody/util/jsonschema.tl new file mode 100644 index 00000000..8e5d69bc --- /dev/null +++ b/teal-src/prosody/util/jsonschema.tl @@ -0,0 +1,376 @@ +-- Copyright (C) 2021 Kim Alvefur +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +-- Based on +-- https://json-schema.org/draft/2020-12/json-schema-core.html +-- https://json-schema.org/draft/2020-12/json-schema-validation.html +-- + +if not math.type then require "prosody.util.mathcompat" end + +local json = require "prosody.util.json" +local null = json.null; + +local pointer = require "prosody.util.jsonpointer" + +local type json_type_name = json.json_type_name + +-- json_type_name here is non-standard +local type schema_t = boolean | json_schema_object + +local record json_schema_object + type json_type_name = json.json_type_name + type schema_object = json_schema_object + + type : json_type_name | { json_type_name } + enum : { any } + const : any + + allOf : { schema_t } + anyOf : { schema_t } + oneOf : { schema_t } + + ["not"] : schema_t + ["if"] : schema_t + ["then"] : schema_t + ["else"] : schema_t + + ["$ref"] : string + + -- numbers + multipleOf : number + maximum : number + exclusiveMaximum : number + minimum : number + exclusiveMinimum : number + + -- strings + maxLength : integer + minLength : integer + pattern : string -- NYI + format : string + + -- arrays + prefixItems : { schema_t } + items : schema_t + contains : schema_t + maxItems : integer + minItems : integer + uniqueItems : boolean + maxContains : integer -- NYI + minContains : integer -- NYI + + -- objects + properties : { string : schema_t } + maxProperties : integer -- NYI + minProperties : integer -- NYI + required : { string } + dependentRequired : { string : { string } } + additionalProperties: schema_t + patternProperties: schema_t -- NYI + propertyNames : schema_t + + -- xml + record xml_t + name : string + namespace : string + prefix : string + attribute : boolean + wrapped : boolean + + -- nonstantard, maybe in the future + text : boolean + x_name_is_value : boolean + x_single_attribute : string + end + + xml : xml_t + + -- descriptive + title : string + description : string + deprecated : boolean + readOnly : boolean + writeOnly : boolean + + -- methods + validate : function ( schema_t, any, json_schema_object ) : boolean +end + +-- TODO validator function per schema property + +local function simple_validate(schema : json_type_name | { json_type_name }, data : any) : boolean + if schema == nil then + return true + elseif schema == "object" and data is table then + return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "string") + elseif schema == "array" and data is table then + return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "number") + elseif schema == "integer" then + return math.type(data) == schema + elseif schema == "null" then + return data == null + elseif schema is { json_type_name } then + for _, one in ipairs(schema as { json_type_name }) do + if simple_validate(one, data) then + return true + end + end + return false + else + return type(data) == schema + end +end + +local complex_validate : function ( json_schema_object, any, json_schema_object ) : boolean + +local function validate (schema : schema_t, data : any, root : json_schema_object) : boolean + if schema is boolean then + return schema + else + return complex_validate(schema, data, root) + end +end + +function complex_validate (schema : json_schema_object, data : any, root : json_schema_object) : boolean + + if root == nil then + root = schema + end + + if schema["$ref"] and schema["$ref"]:sub(1,1) == "#" then + local referenced = pointer.resolve(root as table, schema["$ref"]:sub(2)) as schema_t + if referenced ~= nil and referenced ~= root and referenced ~= schema then + if not validate(referenced, data, root) then + return false; + end + end + end + + if not simple_validate(schema.type, data) then + return false; + end + + if schema.type == "object" then + if data is table then + -- just check that there the keys are all strings + for k in pairs(data) do + if not k is string then + return false + end + end + end + end + + if schema.type == "array" then + if data is table then + -- just check that there the keys are all numbers + for i in pairs(data) do + if not i is integer then + return false + end + end + end + end + + if schema["enum"] ~= nil then + local match = false + for _, v in ipairs(schema["enum"]) do + if v == data then + -- FIXME supposed to do deep-compare + match = true + break + end + end + if not match then + return false + end + end + + -- XXX this is measured in byte, while JSON measures in ... bork + -- TODO use utf8.len? + if data is string then + if schema.maxLength and #data > schema.maxLength then + return false + end + if schema.minLength and #data < schema.minLength then + return false + end + end + + if data is number then + if schema.multipleOf and (data == 0 or data % schema.multipleOf ~= 0) then + return false + end + + if schema.maximum and not ( data <= schema.maximum ) then + return false + end + + if schema.exclusiveMaximum and not ( data < schema.exclusiveMaximum ) then + return false + end + + if schema.minimum and not ( data >= schema.minimum ) then + return false + end + + if schema.exclusiveMinimum and not ( data > schema.exclusiveMinimum ) then + return false + end + end + + if schema.allOf then + for _, sub in ipairs(schema.allOf) do + if not validate(sub, data, root) then + return false + end + end + end + + if schema.oneOf then + local valid = 0 + for _, sub in ipairs(schema.oneOf) do + if validate(sub, data, root) then + valid = valid + 1 + end + end + if valid ~= 1 then + return false + end + end + + if schema.anyOf then + local match = false + for _, sub in ipairs(schema.anyOf) do + if validate(sub, data, root) then + match = true + break + end + end + if not match then + return false + end + end + + if schema["not"] then + if validate(schema["not"], data, root) then + return false + end + end + + if schema["if"] ~= nil then + if validate(schema["if"], data, root) then + if schema["then"] then + return validate(schema["then"], data, root) + end + else + if schema["else"] then + return validate(schema["else"], data, root) + end + end + end + + if schema.const ~= nil and schema.const ~= data then + return false + end + + if data is table then + + if schema.maxItems and #data > schema.maxItems then + return false + end + + if schema.minItems and #data < schema.minItems then + return false + end + + if schema.required then + for _, k in ipairs(schema.required) do + if data[k] == nil then + return false + end + end + end + + if schema.propertyNames ~= nil then + for k in pairs(data) do + if not validate(schema.propertyNames, k, root) then + return false + end + end + end + + if schema.properties then + for k, sub in pairs(schema.properties) do + if data[k] ~= nil and not validate(sub, data[k], root) then + return false + end + end + end + + if schema.additionalProperties ~= nil then + for k, v in pairs(data) do + if schema.properties == nil or schema.properties[k as string] == nil then + if not validate(schema.additionalProperties, v, root) then + return false + end + end + end + end + + if schema.uniqueItems then + -- only works for scalars, would need to deep-compare for objects/arrays/tables + local values : { any : boolean } = {} + for _, v in pairs(data) do + if values[v] then + return false + end + values[v] = true + end + end + + local p = 0 + if schema.prefixItems ~= nil then + for i, s in ipairs(schema.prefixItems) do + if data[i] == nil then + break + elseif validate(s, data[i], root) then + p = i + else + return false + end + end + end + + if schema.items ~= nil then + for i = p+1, #data do + if not validate(schema.items, data[i], root) then + return false + end + end + end + + if schema.contains ~= nil then + local found = false + for i = 1, #data do + if validate(schema.contains, data[i], root) then + found = true + break + end + end + if not found then + return false + end + end + end + + return true; +end + + +json_schema_object.validate = validate; + +return json_schema_object; diff --git a/teal-src/prosody/util/jwt.d.tl b/teal-src/prosody/util/jwt.d.tl new file mode 100644 index 00000000..b3d0cd9e --- /dev/null +++ b/teal-src/prosody/util/jwt.d.tl @@ -0,0 +1,38 @@ +local crypto = require "prosody.util.crypto" +local record jwtlib + enum algorithm + "HS256" + "HS384" + "HS512" + "ES256" + "ES512" + "RS256" + "RS384" + "RS512" + "PS256" + "PS384" + "PS512" + end + type payload = { string : any } + type signer_t = function (payload : payload) : string + type verifier_t = function (token : string) : payload + enum key_type + "rsaEncryption" + "id-ecPublicKey" + end + record algorithm_t + sign : signer_t + verify : verifier_t + load_key : function (key : string) : crypto.key + end + init : function (algorithm, private_key : string, public_key : string, table) : signer_t, verifier_t + new_signer : function (algorithm, string, table) : signer_t + new_verifier : function (algorithm, string, table) : verifier_t + _algorithms : { + algorithm : algorithm_t + } + -- Deprecated + sign : function (private_key : string, payload) : string + verify : function (string) : payload +end +return jwtlib diff --git a/teal-src/prosody/util/logger.d.tl b/teal-src/prosody/util/logger.d.tl new file mode 100644 index 00000000..db29adfd --- /dev/null +++ b/teal-src/prosody/util/logger.d.tl @@ -0,0 +1,18 @@ +local record util + enum loglevel + "debug" + "info" + "warn" + "error" + end + type logger = function ( loglevel, string, ...:any ) + type sink = function ( string, loglevel, string, ...:any ) + type simple_sink = function ( string, loglevel, string ) + init : function ( string ) : logger + make_logger : function ( string, loglevel ) : function ( string, ...:any ) + reset : function () + add_level_sink : function ( loglevel, sink ) + add_simple_sink : function ( simple_sink, { loglevel } ) +end + +return util diff --git a/teal-src/prosody/util/mathcompat.tl b/teal-src/prosody/util/mathcompat.tl new file mode 100644 index 00000000..1e3f9bab --- /dev/null +++ b/teal-src/prosody/util/mathcompat.tl @@ -0,0 +1,15 @@ +if not math.type then + local enum number_subtype + "float" "integer" + end + local function math_type(t:any) : number_subtype + if t is number then + if t % 1 == 0 and t ~= t+1 and t ~= t-1 then + return "integer" + else + return "float" + end + end + end + _G.math.type = math_type +end diff --git a/teal-src/prosody/util/net.d.tl b/teal-src/prosody/util/net.d.tl new file mode 100644 index 00000000..1040fcef --- /dev/null +++ b/teal-src/prosody/util/net.d.tl @@ -0,0 +1,13 @@ + +local enum type_strings + "both" + "ipv4" + "ipv6" +end + +local record lib + local_addresses : function (type_strings, boolean) : { string } + pton : function (string):string + ntop : function (string):string +end +return lib diff --git a/teal-src/prosody/util/poll.d.tl b/teal-src/prosody/util/poll.d.tl new file mode 100644 index 00000000..8df56d57 --- /dev/null +++ b/teal-src/prosody/util/poll.d.tl @@ -0,0 +1,31 @@ +local record state + enum waiterr + "timeout" + "signal" + end + add : function (state, integer, boolean, boolean) : boolean + add : function (state, integer, boolean, boolean) : nil, string, integer + set : function (state, integer, boolean, boolean) : boolean + set : function (state, integer, boolean, boolean) : nil, string, integer + del : function (state, integer) : boolean + del : function (state, integer) : nil, string, integer + wait : function (state, integer) : integer, boolean, boolean + wait : function (state, integer) : nil, string, integer + wait : function (state, integer) : nil, waiterr + getfd : function (state) : integer +end + +local record lib + new : function () : state + EEXIST : integer + EMFILE : integer + ENOENT : integer + enum api_backend + "epoll" + "poll" + "select" + end + api : api_backend +end + +return lib diff --git a/teal-src/prosody/util/pposix.d.tl b/teal-src/prosody/util/pposix.d.tl new file mode 100644 index 00000000..68f49730 --- /dev/null +++ b/teal-src/prosody/util/pposix.d.tl @@ -0,0 +1,108 @@ +local record pposix + enum syslog_facility + "auth" + "authpriv" + "cron" + "daemon" + "ftp" + "kern" + "local0" + "local1" + "local2" + "local3" + "local4" + "local5" + "local6" + "local7" + "lpr" + "mail" + "syslog" + "user" + "uucp" + end + + enum syslog_level + "debug" + "info" + "notice" + "warn" + "error" + end + + enum ulimit_resource + "CORE" + "CPU" + "DATA" + "FSIZE" + "NOFILE" + "STACK" + "MEMLOCK" + "NPROC" + "RSS" + "NICE" + end + + enum ulimit_unlimited + "unlimited" + end + + type ulimit_limit = integer | ulimit_unlimited + + record utsname + sysname : string + nodename : string + release : string + version : string + machine : string + domainname : string + end + + record memoryinfo + allocated : integer + allocated_mmap : integer + used : integer + unused : integer + returnable : integer + end + + abort : function () + + daemonize : function () : boolean, string + + syslog_open : function (ident : string, facility : syslog_facility) + syslog_close : function () + syslog_log : function (level : syslog_level, src : string, msg : string) + syslog_setminlevel : function (level : syslog_level) + + getpid : function () : integer + getuid : function () : integer + getgid : function () : integer + + setuid : function (uid : integer | string) : boolean, string -- string|integer + setgid : function (uid : integer | string) : boolean, string + initgroups : function (user : string, gid : integer) : boolean, string + + umask : function (umask : string) : string + + mkdir : function (dir : string) : boolean, string + + setrlimit : function (resource : ulimit_resource, soft : ulimit_limit, hard : ulimit_limit) : boolean, string + getrlimit : function (resource : ulimit_resource) : boolean, ulimit_limit, ulimit_limit + getrlimit : function (resource : ulimit_resource) : boolean, string + + uname : function () : utsname + + setenv : function (key : string, value : string) : boolean + + meminfo : function () : memoryinfo + + atomic_append : function (f : FILE, s : string) : boolean, string, integer + + isatty : function(FILE) : boolean + + ENOENT : integer + _NAME : string + _VESRION : string +end + +return pposix diff --git a/teal-src/prosody/util/promise.d.tl b/teal-src/prosody/util/promise.d.tl new file mode 100644 index 00000000..d895a828 --- /dev/null +++ b/teal-src/prosody/util/promise.d.tl @@ -0,0 +1,22 @@ + +local record lib + type resolve_func = function (any) + type promise_body = function (resolve_func, resolve_func) + + record Promise + type on_resolved = function (A) : any + type on_rejected = function (B) : any + next : function (Promise, on_resolved, on_rejected) : Promise + end + + new : function (promise_body) : Promise + resolve : function (any) : Promise + reject : function (any) : Promise + all : function ({ Promise }) : Promise + all_settled : function ({ Promise }) : Promise + race : function ({ Promise }) : Promise + try : function + is_promise : function(any) : boolean +end + +return lib diff --git a/teal-src/prosody/util/queue.d.tl b/teal-src/prosody/util/queue.d.tl new file mode 100644 index 00000000..cb8458e7 --- /dev/null +++ b/teal-src/prosody/util/queue.d.tl @@ -0,0 +1,21 @@ +local record lib + record queue + size : integer + count : function (queue) : integer + enum push_errors + "queue full" + end + + push : function (queue, T) : boolean, push_errors + pop : function (queue) : T + peek : function (queue) : T + replace : function (queue, T) : boolean, push_errors + type iterator = function (T, integer) : integer, T + items : function (queue) : iterator, T, integer + type consume_iter = function (queue) : T + consume : function (queue) : consume_iter + end + + new : function (size:integer, allow_wrapping:boolean) : queue +end +return lib; diff --git a/teal-src/prosody/util/random.d.tl b/teal-src/prosody/util/random.d.tl new file mode 100644 index 00000000..83ff2fcc --- /dev/null +++ b/teal-src/prosody/util/random.d.tl @@ -0,0 +1,4 @@ +local record lib + bytes : function (n:integer):string +end +return lib diff --git a/teal-src/prosody/util/ringbuffer.d.tl b/teal-src/prosody/util/ringbuffer.d.tl new file mode 100644 index 00000000..e4726d68 --- /dev/null +++ b/teal-src/prosody/util/ringbuffer.d.tl @@ -0,0 +1,20 @@ +local record lib + record ringbuffer + find : function (ringbuffer, string) : integer + discard : function (ringbuffer, integer) : boolean + read : function (ringbuffer, integer, boolean) : string + readuntil : function (ringbuffer, string) : string + write : function (ringbuffer, string) : integer + size : function (ringbuffer) : integer + length : function (ringbuffer) : integer + sub : function (ringbuffer, integer, integer) : string + byte : function (ringbuffer, integer, integer) : integer... + free : function (ringbuffer) : integer + end + + new : function (integer) : ringbuffer +end + +return lib + + diff --git a/teal-src/prosody/util/roles.d.tl b/teal-src/prosody/util/roles.d.tl new file mode 100644 index 00000000..fef4f88a --- /dev/null +++ b/teal-src/prosody/util/roles.d.tl @@ -0,0 +1,32 @@ +local record util_roles + + type context = any + + record Role + id : string + name : string + description : string + default : boolean + priority : number -- or integer? + permissions : { string : boolean } + + may : function (Role, string, context) + clone : function (Role, role_config) + set_permission : function (Role, string, boolean, boolean) + end + + is_role : function (any) : boolean + + record role_config + name : string + description : string + default : boolean + priority : number -- or integer? + inherits : { Role } + permissions : { string : boolean } + end + + new : function (role_config, Role) : Role +end + +return util_roles diff --git a/teal-src/prosody/util/serialization.d.tl b/teal-src/prosody/util/serialization.d.tl new file mode 100644 index 00000000..27f100c0 --- /dev/null +++ b/teal-src/prosody/util/serialization.d.tl @@ -0,0 +1,33 @@ +local record _M + enum preset + "debug" + "oneline" + "compact" + end + type fallback = function (any, string) : string + record config + preset : preset + fallback : fallback + fatal : boolean + keywords : { string : boolean } + indentwith : string + itemstart : string + itemsep : string + itemlast : string + tstart : string + tend : string + kstart : string + kend : string + equals : string + unquoted : boolean | string + hex : string + freeze : boolean + maxdepth : integer + multirefs : boolean + table_pairs : function + end + type serializer = function (any) : string + new : function (config|preset) : serializer + serialize : function (any, config|preset) : string +end +return _M diff --git a/teal-src/prosody/util/set.d.tl b/teal-src/prosody/util/set.d.tl new file mode 100644 index 00000000..1631eec4 --- /dev/null +++ b/teal-src/prosody/util/set.d.tl @@ -0,0 +1,21 @@ +local record lib + record Set + add : function (Set, T) + contains : function (Set, T) : boolean + contains_set : function (Set, Set) : boolean + items : function (Set) : function (Set, T) : T + add_list : function (Set, { T }) + include : function (Set, Set) + exclude : function (Set, Set) + empty : function (Set) : boolean + end + + new : function ({ T }) : Set + is_set : function (any) : boolean + union : function (Set, Set) : Set + difference : function (Set, Set) : Set + intersection : function (Set, Set) : Set + xor : function (Set, Set) : Set +end + +return lib diff --git a/teal-src/prosody/util/signal.d.tl b/teal-src/prosody/util/signal.d.tl new file mode 100644 index 00000000..290cf08f --- /dev/null +++ b/teal-src/prosody/util/signal.d.tl @@ -0,0 +1,41 @@ +local record lib + enum Signal + "SIGABRT" + "SIGALRM" + "SIGBUS" + "SIGCHLD" + "SIGCLD" + "SIGCONT" + "SIGFPE" + "SIGHUP" + "SIGILL" + "SIGINT" + "SIGIO" + "SIGIOT" + "SIGKILL" + "SIGPIPE" + "SIGPOLL" + "SIGPROF" + "SIGQUIT" + "SIGSEGV" + "SIGSTKFLT" + "SIGSTOP" + "SIGSYS" + "SIGTERM" + "SIGTRAP" + "SIGTTIN" + "SIGTTOU" + "SIGURG" + "SIGUSR1" + "SIGUSR2" + "SIGVTALRM" + "SIGWINCH" + "SIGXCPU" + "SIGXFSZ" + end + signal : function (integer | Signal, function, boolean) : boolean + raise : function (integer | Signal) + kill : function (integer, integer | Signal) + -- enum : integer +end +return lib diff --git a/teal-src/prosody/util/smqueue.tl b/teal-src/prosody/util/smqueue.tl new file mode 100644 index 00000000..821aee57 --- /dev/null +++ b/teal-src/prosody/util/smqueue.tl @@ -0,0 +1,99 @@ +local queue = require "prosody.util.queue"; + +local record lib + -- T would typically be util.stanza + record smqueue + _queue : queue.queue + _head : integer + _tail : integer + + enum ack_errors + "tail" + "head" + "pop" + end + push : function (smqueue, T) + ack : function (smqueue, integer) : { T }, ack_errors + resumable : function (smqueue) : boolean + resume : function (smqueue) : queue.queue.iterator, any, integer + type consume_iter = function (smqueue) : T + consume : function (smqueue) : consume_iter + + table : function (smqueue) : { T } + end + new : function (integer) : smqueue +end + +local type smqueue = lib.smqueue; + +function smqueue:push(v) + self._head = self._head + 1; + -- Wraps instead of errors + assert(self._queue:push(v)); +end + +function smqueue:ack(h : integer) : { any }, smqueue.ack_errors + if h < self._tail then + return nil, "tail"; + elseif h > self._head then + return nil, "head"; + end + -- TODO optimize? cache table fields + local acked = {}; + self._tail = h; + local expect = self._head - self._tail; + while expect < self._queue:count() do + local v = self._queue:pop(); + if not v then return nil, "pop"; end + table.insert(acked, v); + end + return acked; +end + +function smqueue:count_unacked() : integer + return self._head - self._tail; +end + +function smqueue:count_acked() : integer + return self._tail; +end + +function smqueue:resumable() : boolean + return self._queue:count() >= (self._head - self._tail); +end + +function smqueue:resume() : queue.queue.iterator, any, integer + return self._queue:items(); +end + +function smqueue:consume() : queue.queue.consume_iter + return self._queue:consume() +end + +-- Compatibility layer, plain ol' table +function smqueue:table() : { any } + local t : { any } = {}; + for i, v in self:resume() do + t[i] = v; + end + return t; +end + +local function freeze(q : smqueue) : { string:integer } + return { head = q._head, tail = q._tail } +end + +local queue_mt = { + -- + __name = "smqueue"; + __index = smqueue; + __len = smqueue.count_unacked; + __freeze = freeze; +} + +function lib.new(size : integer) : queue.queue + assert(size>0); + return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true) }, queue_mt); +end + +return lib; diff --git a/teal-src/prosody/util/stanza.d.tl b/teal-src/prosody/util/stanza.d.tl new file mode 100644 index 00000000..e1ab2105 --- /dev/null +++ b/teal-src/prosody/util/stanza.d.tl @@ -0,0 +1,145 @@ +local record lib + + type children_iter = function ( stanza_t ) : stanza_t + type childtags_iter = function () : stanza_t + type maptags_cb = function ( stanza_t ) : stanza_t + + + enum stanza_error_type + "auth" + "cancel" + "continue" + "modify" + "wait" + end + enum stanza_error_condition + "bad-request" + "conflict" + "feature-not-implemented" + "forbidden" + "gone" + "internal-server-error" + "item-not-found" + "jid-malformed" + "not-acceptable" + "not-allowed" + "not-authorized" + "policy-violation" + "recipient-unavailable" + "redirect" + "registration-required" + "remote-server-not-found" + "remote-server-timeout" + "resource-constraint" + "service-unavailable" + "subscription-required" + "undefined-condition" + "unexpected-request" + end + + record stanza_t + name : string + attr : { string : string } + { stanza_t | string } + tags : { stanza_t } + + query : function ( stanza_t, string ) : stanza_t + body : function ( stanza_t, string, { string : string } ) : stanza_t + text_tag : function ( stanza_t, string, string, { string : string } ) : stanza_t + tag : function ( stanza_t, string, { string : string } ) : stanza_t + text : function ( stanza_t, string ) : stanza_t + up : function ( stanza_t ) : stanza_t + at_top : function ( stanza_t ) : boolean + reset : function ( stanza_t ) : stanza_t + add_direct_child : function ( stanza_t, stanza_t ) + add_child : function ( stanza_t, stanza_t ) + remove_children : function ( stanza_t, string, string ) : stanza_t + + get_child : function ( stanza_t, string, string ) : stanza_t + get_text : function ( stanza_t ) : string + get_child_text : function ( stanza_t, string, string ) : string + get_child_attr : function ( stanza_t, string, string ) : string + get_child_with_attr : function ( stanza_t, string, string, string, function (string) : boolean ) : string + child_with_name : function ( stanza_t, string, string ) : stanza_t + child_with_ns : function ( stanza_t, string, string ) : stanza_t + children : function ( stanza_t ) : children_iter, stanza_t, integer + childtags : function ( stanza_t, string, string ) : childtags_iter + maptags : function ( stanza_t, maptags_cb ) : stanza_t + find : function ( stanza_t, string ) : stanza_t | string + + top_tag : function ( stanza_t ) : string + pretty_print : function ( stanza_t ) : string + pretty_top_tag : function ( stanza_t ) : string + + -- FIXME Represent util.error support + get_error : function ( stanza_t ) : stanza_error_type, stanza_error_condition, string, stanza_t + add_error : function ( stanza_t, stanza_error_type, stanza_error_condition, string, string ) + indent : function ( stanza_t, integer, string ) : stanza_t + end + + record serialized_stanza_t + name : string + attr : { string : string } + { serialized_stanza_t | string } + end + + record message_attr + ["xml:lang"] : string + from : string + id : string + to : string + type : message_type + enum message_type + "chat" + "error" + "groupchat" + "headline" + "normal" + end + end + + record presence_attr + ["xml:lang"] : string + from : string + id : string + to : string + type : presence_type + enum presence_type + "error" + "probe" + "subscribe" + "subscribed" + "unsubscribe" + "unsubscribed" + end + end + + record iq_attr + ["xml:lang"] : string + from : string + id : string + to : string + type : iq_type + enum iq_type + "error" + "get" + "result" + "set" + end + end + + stanza : function ( string, { string : string } ) : stanza_t + is_stanza : function ( any ) : boolean + preserialize : function ( stanza_t ) : serialized_stanza_t + deserialize : function ( serialized_stanza_t ) : stanza_t + clone : function ( stanza_t, boolean ) : stanza_t + message : function ( message_attr, string ) : stanza_t + iq : function ( iq_attr ) : stanza_t + reply : function ( stanza_t ) : stanza_t + error_reply : function ( stanza_t, stanza_error_type, stanza_error_condition, string, string ) : stanza_t + presence : function ( presence_attr ) : stanza_t + xml_escape : function ( string ) : string + pretty_print : function ( string ) : string +end + +return lib diff --git a/teal-src/prosody/util/strbitop.d.tl b/teal-src/prosody/util/strbitop.d.tl new file mode 100644 index 00000000..010efdb8 --- /dev/null +++ b/teal-src/prosody/util/strbitop.d.tl @@ -0,0 +1,6 @@ +local record mod + sand : function (string, string) : string + sor : function (string, string) : string + sxor : function (string, string) : string +end +return mod diff --git a/teal-src/prosody/util/struct.d.tl b/teal-src/prosody/util/struct.d.tl new file mode 100644 index 00000000..201aaa23 --- /dev/null +++ b/teal-src/prosody/util/struct.d.tl @@ -0,0 +1,6 @@ +local record lib + pack : function (string, ...:any) : string + unpack : function(string, string, integer) : any... + size : function(string) : integer +end +return lib diff --git a/teal-src/prosody/util/table.d.tl b/teal-src/prosody/util/table.d.tl new file mode 100644 index 00000000..67e5d0f0 --- /dev/null +++ b/teal-src/prosody/util/table.d.tl @@ -0,0 +1,7 @@ +local record lib + create : function (narr:integer, nrec:integer):table + pack : function (...:any):{any} + move : function (table, integer, integer, integer, table) : table +end +return lib + diff --git a/teal-src/prosody/util/termcolours.d.tl b/teal-src/prosody/util/termcolours.d.tl new file mode 100644 index 00000000..226259aa --- /dev/null +++ b/teal-src/prosody/util/termcolours.d.tl @@ -0,0 +1,7 @@ +local record lib + getstring : function (string, string) : string + getstyle : function (...:string) : string + setstyle : function (string) : string + tohtml : function (string) : string +end +return lib diff --git a/teal-src/prosody/util/time.d.tl b/teal-src/prosody/util/time.d.tl new file mode 100644 index 00000000..e159706b --- /dev/null +++ b/teal-src/prosody/util/time.d.tl @@ -0,0 +1,6 @@ + +local record lib + now : function () : number + monotonic : function () : number +end +return lib diff --git a/teal-src/prosody/util/timer.d.tl b/teal-src/prosody/util/timer.d.tl new file mode 100644 index 00000000..a6394cf3 --- /dev/null +++ b/teal-src/prosody/util/timer.d.tl @@ -0,0 +1,8 @@ +local record util_timer + record task end + type timer_callback = function (number) : number + add_task : function ( number, timer_callback, any ) : task + stop : function ( task ) + reschedule : function ( task, number ) : task +end +return util_timer diff --git a/teal-src/prosody/util/uuid.d.tl b/teal-src/prosody/util/uuid.d.tl new file mode 100644 index 00000000..284a4e4c --- /dev/null +++ b/teal-src/prosody/util/uuid.d.tl @@ -0,0 +1,8 @@ +local record lib + get_nibbles : function (number) : string + generate : function () : string + + seed : function (string) +end +return lib + diff --git a/teal-src/prosody/util/xtemplate.tl b/teal-src/prosody/util/xtemplate.tl new file mode 100644 index 00000000..7f3b513a --- /dev/null +++ b/teal-src/prosody/util/xtemplate.tl @@ -0,0 +1,101 @@ +-- render(template, stanza) --> string +-- {path} --> stanza:find(path) +-- {{ns}name/child|each({ns}name){sub-template}} + +--[[ +template ::= "{" path ("|" name ("(" args ")")? (template)? )* "}" +path ::= defined by util.stanza +name ::= %w+ +args ::= anything with balanced ( ) pairs +]] + +local s_gsub = string.gsub; +local s_match = string.match; +local s_sub = string.sub; +local t_concat = table.concat; + +local st = require "prosody.util.stanza"; + +local type escape_t = function (string) : string +local type filter_t = function (string, string | st.stanza_t, string) : string | st.stanza_t, boolean +local type filter_coll = { string : filter_t } + +local function render(template : string, root : st.stanza_t, escape : escape_t, filters : filter_coll) : string + escape = escape or st.xml_escape; + + return (s_gsub(template, "%b{}", function(block : string) : string + local inner = s_sub(block, 2, -2); + local path, pipe, pos = s_match(inner, "^([^|]+)(|?)()"); + if not path is string then return end + local value : string | st.stanza_t + if path == "." then + value = root; + elseif path == "#" then + value = root:get_text(); + else + value = root:find(path); + end + local is_escaped = false; + + while pipe == "|" do + local func, args, tmpl, p = s_match(inner, "^(%w+)(%b())(%b{})()", pos as integer); + if not func then func, args, p = s_match(inner, "^(%w+)(%b())()", pos as integer); end + if not func then func, tmpl, p = s_match(inner, "^(%w+)(%b{})()", pos as integer); end + if not func then func, p = s_match(inner, "^(%w+)()", pos as integer); end + if not func then break end + if tmpl then tmpl = s_sub(tmpl, 2, -2); end + if args then args = s_sub(args, 2, -2); end + + if func == "each" and tmpl and st.is_stanza(value) then + if not args then value, args = root, path; end + local ns, name = s_match(args, "^(%b{})(.*)$"); + if ns then ns = s_sub(ns, 2, -2); else name, ns = args, nil; end + if ns == "" then ns = nil; end + if name == "" then name = nil; end + local out, i = {}, 1; + for c in (value as st.stanza_t):childtags(name, ns) do + out[i], i = render(tmpl, c, escape, filters), i + 1; + end + value = t_concat(out); + is_escaped = true; + elseif func == "and" and tmpl then + local condition = value; + if args then condition = root:find(args); end + if condition then + value = render(tmpl, root, escape, filters); + is_escaped = true; + end + elseif func == "or" and tmpl then + local condition = value; + if args then condition = root:find(args); end + if not condition then + value = render(tmpl, root, escape, filters); + is_escaped = true; + end + elseif filters and filters[func] then + local f = filters[func]; + if args == nil then + value, is_escaped = f(value, tmpl); + else + value, is_escaped = f(args, value, tmpl); + end + else + error("No such filter function: " .. func); + end + pipe, pos = s_match(inner, "^(|?)()", p as integer); + end + + if value is string then + if not is_escaped then value = escape(value); end + return value; + elseif st.is_stanza(value) then + value = value:get_text(); + if value then + return escape(value); + end + end + return ""; + end)); +end + +return { render = render }; diff --git a/teal-src/util/array.d.tl b/teal-src/util/array.d.tl deleted file mode 100644 index 70bf2624..00000000 --- a/teal-src/util/array.d.tl +++ /dev/null @@ -1,9 +0,0 @@ -local record array_t - { T } -end - -local record lib - metamethod __call : function () : array_t -end - -return lib diff --git a/teal-src/util/async.d.tl b/teal-src/util/async.d.tl deleted file mode 100644 index a2e41cd6..00000000 --- a/teal-src/util/async.d.tl +++ /dev/null @@ -1,42 +0,0 @@ -local record lib - ready : function () : boolean - waiter : function (num : integer, allow_many : boolean) : function (), function () - guarder : function () : function (id : function ()) : function () | nil - record runner_t - func : function (T) - thread : thread - enum state_e - -- from Lua manual - "running" - "suspended" - "normal" - "dead" - - -- from util.async - "ready" - "error" - end - state : state_e - notified_state : state_e - queue : { T } - type watcher_t = function (runner_t, ... : any) - type watchers_t = { state_e : watcher_t } - data : any - id : string - - run : function (runner_t, T) : boolean, state_e, integer - enqueue : function (runner_t, T) : runner_t - log : function (runner_t, string, string, ... : any) - onready : function (runner_t, function) : runner_t - onready : function (runner_t, function) : runner_t - onwaiting : function (runner_t, function) : runner_t - onerror : function (runner_t, function) : runner_t - end - runner : function (function (T), runner_t.watchers_t, any) : runner_t - wait_for : function (any) : any, any - sleep : function (t:number) - - -- set_nexttick = function(new_next_tick) next_tick = new_next_tick; end; - -- set_schedule_function = function (new_schedule_function) schedule_task = new_schedule_function; end; -end -return lib diff --git a/teal-src/util/bitcompat.d.tl b/teal-src/util/bitcompat.d.tl deleted file mode 100644 index 18adf725..00000000 --- a/teal-src/util/bitcompat.d.tl +++ /dev/null @@ -1,8 +0,0 @@ -local record lib - band : function (integer, integer, ... : integer) : integer - bor : function (integer, integer, ... : integer) : integer - bxor : function (integer, integer, ... : integer) : integer - lshift : function (integer, integer) : integer - rshift : function (integer, integer) : integer -end -return lib diff --git a/teal-src/util/compat.d.tl b/teal-src/util/compat.d.tl deleted file mode 100644 index da9c6083..00000000 --- a/teal-src/util/compat.d.tl +++ /dev/null @@ -1,4 +0,0 @@ -local record lib - xpcall : function (function, function, ...:any):boolean, any -end -return lib diff --git a/teal-src/util/crand.d.tl b/teal-src/util/crand.d.tl deleted file mode 100644 index b40cb67e..00000000 --- a/teal-src/util/crand.d.tl +++ /dev/null @@ -1,6 +0,0 @@ -local record lib - bytes : function (n : integer) : string - enum sourceid "OpenSSL" "arc4random()" "Linux" end - _source : sourceid -end -return lib diff --git a/teal-src/util/crypto.d.tl b/teal-src/util/crypto.d.tl deleted file mode 100644 index cf0b0d1b..00000000 --- a/teal-src/util/crypto.d.tl +++ /dev/null @@ -1,29 +0,0 @@ -local record lib - record key - private_pem : function (key) : string - public_pem : function (key) : string - get_type : function (key) : string - end - - generate_ed25519_keypair : function () : key - ed25519_sign : function (key, string) : string - ed25519_verify : function (key, string, string) : boolean - - ecdsa_sha256_sign : function (key, string) : string - ecdsa_sha256_verify : function (key, string, string) : boolean - parse_ecdsa_signature : function (string) : string, string - build_ecdsa_signature : function (string, string) : string - - import_private_pem : function (string) : key - import_public_pem : function (string) : key - - aes_128_gcm_encrypt : function (key, string, string) : string - aes_128_gcm_decrypt : function (key, string, string) : string - aes_256_gcm_encrypt : function (key, string, string) : string - aes_256_gcm_decrypt : function (key, string, string) : string - - - version : string - _LIBCRYPTO_VERSION : string -end -return lib diff --git a/teal-src/util/dataforms.d.tl b/teal-src/util/dataforms.d.tl deleted file mode 100644 index 0eddf98e..00000000 --- a/teal-src/util/dataforms.d.tl +++ /dev/null @@ -1,54 +0,0 @@ -local stanza_t = require "util.stanza".stanza_t - -local record lib - record dataform - title : string - instructions : string - - record form_field - - enum field_type - "boolean" - "fixed" - "hidden" - "jid-multi" - "jid-single" - "list-multi" - "list-single" - "text-multi" - "text-private" - "text-single" - end - - type : field_type - var : string -- protocol name - name : string -- internal name - - label : string - desc : string - - datatype : string - range_min : number - range_max : number - - value : any -- depends on field_type - options : table - end - - { form_field } - - enum form_type - "form" - "submit" - "cancel" - "result" - end - - form : function ( dataform, { string : any }, form_type ) : stanza_t - data : function ( dataform, stanza_t ) : { string : any } - end - - new : function ( dataform ) : dataform -end - -return lib diff --git a/teal-src/util/datamapper.tl b/teal-src/util/datamapper.tl deleted file mode 100644 index 4ff3a02c..00000000 --- a/teal-src/util/datamapper.tl +++ /dev/null @@ -1,379 +0,0 @@ --- Copyright (C) 2021 Kim Alvefur --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- --- Based on --- https://json-schema.org/draft/2020-12/json-schema-core.html --- https://json-schema.org/draft/2020-12/json-schema-validation.html --- http://spec.openapis.org/oas/v3.0.1#xmlObject --- https://github.com/OAI/OpenAPI-Specification/issues/630 (text:true) --- --- XML Object Extensions: --- text to refer to the text content at the same time as attributes --- x_name_is_value for enum fields where the is the value --- x_single_attribute for --- --- TODO pointers --- TODO cleanup / refactor --- TODO s/number/integer/ once we have appropriate math.type() compat --- - -if not math.type then require "util.mathcompat" end - -local st = require "util.stanza"; -local json = require"util.json" -local pointer = require"util.jsonpointer"; - -local json_type_name = json.json_type_name; -local json_schema_object = require "util.jsonschema" -local type schema_t = boolean | json_schema_object - -local function toboolean ( s : string ) : boolean - if s == "true" or s == "1" then - return true - elseif s == "false" or s == "0" then - return false - elseif s then - return true - end -end - -local function totype(t : json_type_name, s : string) : any - if not s then return nil end - if t == "string" then - return s; - elseif t == "boolean" then - return toboolean(s) - elseif t == "number" or t == "integer" then - return tonumber(s) - end -end - -local enum value_goes - "in_tag_name" - "in_text" - "in_text_tag" - "in_attribute" - "in_single_attribute" - "in_children" - "in_wrapper" -end - -local function resolve_schema(schema : schema_t, root : json_schema_object) : schema_t - if schema is json_schema_object then - if schema["$ref"] and schema["$ref"]:sub(1, 1) == "#" then - return pointer.resolve(root as table, schema["$ref"]:sub(2)) as schema_t; - end - end - return schema; -end - -local function guess_schema_type(schema : json_schema_object) : json_type_name - local schema_types = schema.type - if schema_types is json_type_name then - return schema_types - elseif schema_types ~= nil then - error "schema has unsupported 'type' property" - elseif schema.properties then - return "object" - elseif schema.items then - return "array" - end - return "string" -- default assumption -end - -local function unpack_propschema( propschema : schema_t, propname : string, current_ns : string ) - : json_type_name, value_goes, string, string, string, string, { any } - local proptype : json_type_name = "string" - local value_where : value_goes = propname and "in_text_tag" or "in_text" - local name = propname - local namespace : string - local prefix : string - local single_attribute : string - local enums : { any } - - if propschema is json_schema_object then - proptype = guess_schema_type(propschema); - elseif propschema is string then -- Teal says this can never be a string, but it could before so best be sure - error("schema as string is not supported: "..propschema.." {"..current_ns.."}"..propname) - end - - if proptype == "object" or proptype == "array" then - value_where = "in_children" - end - - if propschema is json_schema_object then - local xml = propschema.xml - if xml then - if xml.name then - name = xml.name - end - if xml.namespace and xml.namespace ~= current_ns then - namespace = xml.namespace - end - if xml.prefix then - prefix = xml.prefix - end - if proptype == "array" and xml.wrapped then - value_where = "in_wrapper" - elseif xml.attribute then - value_where = "in_attribute" - elseif xml.text then - value_where = "in_text" - elseif xml.x_name_is_value then - value_where = "in_tag_name" - elseif xml.x_single_attribute then - single_attribute = xml.x_single_attribute - value_where = "in_single_attribute" - end - end - if propschema["const"] then - enums = { propschema["const"] } - elseif propschema["enum"] then - enums = propschema["enum"] - end - end - - return proptype, value_where, name, namespace, prefix, single_attribute, enums -end - -local parse_object : function (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { string : any } -local parse_array : function (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { any } - -local function extract_value (s : st.stanza_t, value_where : value_goes, proptype : json.json_type_name, name : string, namespace : string, prefix : string, single_attribute : string, enums : { any }) : string - if value_where == "in_tag_name" then - local c : st.stanza_t - if proptype == "boolean" then - c = s:get_child(name, namespace); - elseif enums and proptype == "string" then - -- XXX O(n²) ? - -- Probably better to flip the table and loop over :childtags(nil, ns), should be 2xO(n) - -- BUT works first, optimize later - for i = 1, #enums do - c = s:get_child(enums[i] as string, namespace); - if c then break end - end - else - c = s:get_child(nil, namespace); - end - if c then - return c.name; - end - elseif value_where == "in_attribute" then - local attr = name - if prefix then - attr = prefix .. ':' .. name - elseif namespace and namespace ~= s.attr.xmlns then - attr = namespace .. "\1" .. name - end - return s.attr[attr] - - elseif value_where == "in_text" then - return s:get_text() - - elseif value_where == "in_single_attribute" then - local c = s:get_child(name, namespace) - return c and c.attr[single_attribute] - elseif value_where == "in_text_tag" then - return s:get_child_text(name, namespace) - end -end - -function parse_object (schema : schema_t, s : st.stanza_t, root : json_schema_object) : { string : any } - local out : { string : any } = {} - schema = resolve_schema(schema, root) - if schema is json_schema_object and schema.properties then - for prop, propschema in pairs(schema.properties) do - propschema = resolve_schema(propschema, root) - - local proptype, value_where, name, namespace, prefix, single_attribute, enums = unpack_propschema(propschema, prop, s.attr.xmlns) - - if value_where == "in_children" and propschema is json_schema_object then - if proptype == "object" then - local c = s:get_child(name, namespace) - if c then - out[prop] = parse_object(propschema, c, root); - end - elseif proptype == "array" then - local a = parse_array(propschema, s, root); - if a and a[1] ~= nil then - out[prop] = a; - end - else - error "unreachable" - end - elseif value_where == "in_wrapper" and propschema is json_schema_object and proptype == "array" then - local wrapper = s:get_child(name, namespace); - if wrapper then - out[prop] = parse_array(propschema, wrapper, root); - end - else - local value : string = extract_value (s, value_where, proptype, name, namespace, prefix, single_attribute, enums) - - out[prop] = totype(proptype, value) - end - end - end - - return out -end - -function parse_array (schema : json_schema_object, s : st.stanza_t, root : json_schema_object) : { any } - local itemschema : schema_t = resolve_schema(schema.items, root); - local proptype, value_where, child_name, namespace, prefix, single_attribute, enums = unpack_propschema(itemschema, nil, s.attr.xmlns) - local attr_name : string - if value_where == "in_single_attribute" then -- FIXME this shouldn't be needed - value_where = "in_attribute"; - attr_name = single_attribute; - end - local out : { any } = {} - - if proptype == "object" then - if itemschema is json_schema_object then - for c in s:childtags(child_name, namespace) do - table.insert(out, parse_object(itemschema, c, root)); - end - else - error "array items must be schema object" - end - elseif proptype == "array" then - if itemschema is json_schema_object then - for c in s:childtags(child_name, namespace) do - table.insert(out, parse_array(itemschema, c, root)); - end - end - else - for c in s:childtags(child_name, namespace) do - local value : string = extract_value (c, value_where, proptype, attr_name or child_name, namespace, prefix, single_attribute, enums) - - table.insert(out, totype(proptype, value)); - end - end - return out; -end - -local function parse (schema : json_schema_object, s : st.stanza_t) : table - local s_type = guess_schema_type(schema) - if s_type == "object" then - return parse_object(schema, s, schema) - elseif s_type == "array" then - return parse_array(schema, s, schema) - else - error "top-level scalars unsupported" - end -end - -local function toxmlstring(proptype : json_type_name, v : any) : string - if proptype == "string" and v is string then - return v - elseif proptype == "number" and v is number then - return string.format("%g", v) - elseif proptype == "integer" and v is number then -- TODO is integer - return string.format("%d", v) - elseif proptype == "boolean" then - return v and "1" or "0" - end -end - -local unparse : function (json_schema_object, table, string, string, st.stanza_t, json_schema_object) : st.stanza_t - -local function unparse_property(out : st.stanza_t, v : any, proptype : json_type_name, propschema : schema_t, value_where : value_goes, name : string, namespace : string, current_ns : string, prefix : string, single_attribute : string, root : json_schema_object) - - if value_where == "in_attribute" then - local attr = name - if prefix then - attr = prefix .. ':' .. name - elseif namespace and namespace ~= current_ns then - attr = namespace .. "\1" .. name - end - - out.attr[attr] = toxmlstring(proptype, v) - elseif value_where == "in_text" then - out:text(toxmlstring(proptype, v)) - elseif value_where == "in_single_attribute" then - assert(single_attribute) - local propattr : { string : string } = {} - - if namespace and namespace ~= current_ns then - propattr.xmlns = namespace - end - - propattr[single_attribute] = toxmlstring(proptype, v) - out:tag(name, propattr):up(); - - else - local propattr : { string : string } - if namespace ~= current_ns then - propattr = { xmlns = namespace } - end - if value_where == "in_tag_name" then - if proptype == "string" and v is string then - out:tag(v, propattr):up(); - elseif proptype == "boolean" and v == true then - out:tag(name, propattr):up(); - end - elseif proptype == "object" and propschema is json_schema_object and v is table then - local c = unparse(propschema, v, name, namespace, nil, root); - if c then - out:add_direct_child(c); - end - elseif proptype == "array" and propschema is json_schema_object and v is table then - if value_where == "in_wrapper" then - local c = unparse(propschema, v, name, namespace, nil, root); - if c then - out:add_direct_child(c); - end - else - unparse(propschema, v, name, namespace, out, root); - end - else - out:text_tag(name, toxmlstring(proptype, v), propattr) - end - end -end - -function unparse ( schema : json_schema_object, t : table, current_name : string, current_ns : string, ctx : st.stanza_t, root : json_schema_object ) : st.stanza_t - - if root == nil then root = schema end - - if schema.xml then - if schema.xml.name then - current_name = schema.xml.name - end - if schema.xml.namespace then - current_ns = schema.xml.namespace - end - -- TODO prefix? - end - - local out = ctx or st.stanza(current_name, { xmlns = current_ns }) - - local s_type = guess_schema_type(schema) - if s_type == "object" then - - for prop, propschema in pairs(schema.properties) do - propschema = resolve_schema(propschema, root) - local v = t[prop] - - if v ~= nil then - local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(propschema, prop, current_ns) - unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) - end - end - return out; - - elseif s_type == "array" then - local itemschema = resolve_schema(schema.items, root) - local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(itemschema, current_name, current_ns) - for _, item in ipairs(t as { string }) do - unparse_property(out, item, proptype, itemschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) - end - return out; - end -end - -return { - parse = parse, - unparse = unparse, -} diff --git a/teal-src/util/datetime.d.tl b/teal-src/util/datetime.d.tl deleted file mode 100644 index 9f770a73..00000000 --- a/teal-src/util/datetime.d.tl +++ /dev/null @@ -1,9 +0,0 @@ -local record lib - date : function (t : number) : string - datetime : function (t : number) : string - time : function (t : number) : string - legacy : function (t : number) : string - parse : function (t : string) : number -end - -return lib diff --git a/teal-src/util/encodings.d.tl b/teal-src/util/encodings.d.tl deleted file mode 100644 index 58aefa5e..00000000 --- a/teal-src/util/encodings.d.tl +++ /dev/null @@ -1,27 +0,0 @@ --- TODO many actually return Maybe(String) -local record lib - record base64 - encode : function (s : string) : string - decode : function (s : string) : string - end - record stringprep - nameprep : function (s : string, strict : boolean) : string - nodeprep : function (s : string, strict : boolean) : string - resourceprep : function (s : string, strict : boolean) : string - saslprep : function (s : string, strict : boolean) : string - end - record idna - to_ascii : function (s : string) : string - to_unicode : function (s : string) : string - end - record utf8 - valid : function (s : string) : boolean - length : function (s : string) : integer - end - record confusable - skeleton : function (s : string) : string - end - version : string -end -return lib - diff --git a/teal-src/util/error.d.tl b/teal-src/util/error.d.tl deleted file mode 100644 index 4c3a7196..00000000 --- a/teal-src/util/error.d.tl +++ /dev/null @@ -1,78 +0,0 @@ -local enum error_type - "auth" - "cancel" - "continue" - "modify" - "wait" -end - -local enum error_condition - "bad-request" - "conflict" - "feature-not-implemented" - "forbidden" - "gone" - "internal-server-error" - "item-not-found" - "jid-malformed" - "not-acceptable" - "not-allowed" - "not-authorized" - "policy-violation" - "recipient-unavailable" - "redirect" - "registration-required" - "remote-server-not-found" - "remote-server-timeout" - "resource-constraint" - "service-unavailable" - "subscription-required" - "undefined-condition" - "unexpected-request" -end - -local record protoerror - type : error_type - condition : error_condition - text : string - code : integer -end - -local record Error - type : error_type - condition : error_condition - text : string - code : integer - context : { any : any } - source : string -end - -local type compact_registry_item = { string, string, string, string } -local type compact_registry = { compact_registry_item } -local type registry = { string : protoerror } -local type context = { string : any } - -local record error_registry_wrapper - source : string - registry : registry - new : function (string, context) : Error - coerce : function (any, string) : any, Error - wrap : function (Error) : Error - wrap : function (string, context) : Error - is_error : function (any) : boolean -end - -local record lib - record configure_opt - auto_inject_traceback : boolean - end - new : function (protoerror, context, { string : protoerror }, string) : Error - init : function (string, string, registry | compact_registry) : error_registry_wrapper - init : function (string, registry | compact_registry) : error_registry_wrapper - is_error : function (any) : boolean - coerce : function (any, string) : any, Error - from_stanza : function (table, context, string) : Error - configure : function -end - -return lib diff --git a/teal-src/util/format.d.tl b/teal-src/util/format.d.tl deleted file mode 100644 index 1ff77c97..00000000 --- a/teal-src/util/format.d.tl +++ /dev/null @@ -1,4 +0,0 @@ -local record lib - format : function (string, ... : any) : string -end -return lib diff --git a/teal-src/util/hashes.d.tl b/teal-src/util/hashes.d.tl deleted file mode 100644 index 5c249627..00000000 --- a/teal-src/util/hashes.d.tl +++ /dev/null @@ -1,31 +0,0 @@ -local type hash = function (msg : string, hex : boolean) : string -local type hmac = function (key : string, msg : string, hex : boolean) : string -local type kdf = function (pass : string, salt : string, i : integer) : string - -local record lib - sha1 : hash - sha256 : hash - sha224 : hash - sha384 : hash - sha512 : hash - md5 : hash - sha3_256 : hash - sha3_512 : hash - blake2s256 : hash - blake2b512 : hash - hmac_sha1 : hmac - hmac_sha256 : hmac - hmac_sha224 : hmac - hmac_sha384 :hmac - hmac_sha512 : hmac - hmac_md5 : hmac - hmac_sha3_256 : hmac - hmac_sha3_512 : hmac - scram_Hi_sha1 : kdf - pbkdf2_hmac_sha1 : kdf - pbkdf2_hmac_sha256 : kdf - equals : function (string, string) : boolean - version : string - _LIBCRYPTO_VERSION : string -end -return lib diff --git a/teal-src/util/hex.d.tl b/teal-src/util/hex.d.tl deleted file mode 100644 index 9d84540b..00000000 --- a/teal-src/util/hex.d.tl +++ /dev/null @@ -1,8 +0,0 @@ -local type s2s = function (s : string) : string -local record lib - to : s2s - from : s2s - encode : s2s - decode : s2s -end -return lib diff --git a/teal-src/util/http.d.tl b/teal-src/util/http.d.tl deleted file mode 100644 index ecbe35c3..00000000 --- a/teal-src/util/http.d.tl +++ /dev/null @@ -1,9 +0,0 @@ -local record lib - urlencode : function (s : string) : string - urldecode : function (s : string) : string - formencode : function (f : { string : string }) : string - formdecode : function (s : string) : { string : string } - contains_token : function (field : string, token : string) : boolean - normalize_path : function (path : string) : string -end -return lib diff --git a/teal-src/util/human/io.d.tl b/teal-src/util/human/io.d.tl deleted file mode 100644 index e4f64cd1..00000000 --- a/teal-src/util/human/io.d.tl +++ /dev/null @@ -1,28 +0,0 @@ -local record lib - getchar : function (n : integer) : string - getline : function () : string - getpass : function () : string - show_yesno : function (prompt : string) : boolean - read_password : function () : string - show_prompt : function (prompt : string) : boolean - printf : function (fmt : string, ... : any) - padleft : function (s : string, width : integer) : string - padright : function (s : string, width : integer) : string - - -- {K:V} vs T ? - record tablerow - width : integer | string -- generate an 1..100 % enum? - title : string - mapper : function (V, {K:V}) : string - key : K - enum alignments - "left" - "right" - end - align : alignments - end - type getrow = function ({ K : V }) : string - table : function ({ tablerow }, width : integer) : getrow -end - -return lib diff --git a/teal-src/util/human/units.d.tl b/teal-src/util/human/units.d.tl deleted file mode 100644 index 3db17c3a..00000000 --- a/teal-src/util/human/units.d.tl +++ /dev/null @@ -1,8 +0,0 @@ -local lib = record - enum logbase - "b" -- 1024 - end - adjust : function (number, string) : number, string - format : function (number, string, logbase) : string -end -return lib diff --git a/teal-src/util/id.d.tl b/teal-src/util/id.d.tl deleted file mode 100644 index 4b6c93b7..00000000 --- a/teal-src/util/id.d.tl +++ /dev/null @@ -1,9 +0,0 @@ -local record lib - short : function () : string - medium : function () : string - long : function () : string - custom : function (integer) : function () : string - -end -return lib - diff --git a/teal-src/util/interpolation.d.tl b/teal-src/util/interpolation.d.tl deleted file mode 100644 index fb653edf..00000000 --- a/teal-src/util/interpolation.d.tl +++ /dev/null @@ -1,6 +0,0 @@ -local type renderer = function (string, { string : any }) : string -local type filter = function (string, any) : string -local record lib - new : function (string, string, funcs : { string : filter }) : renderer -end -return lib diff --git a/teal-src/util/ip.d.tl b/teal-src/util/ip.d.tl deleted file mode 100644 index 79e901c6..00000000 --- a/teal-src/util/ip.d.tl +++ /dev/null @@ -1,20 +0,0 @@ -local record iplib - enum protocol - "IPv6" - "IPv4" - end - record ip_t - addr : string - packed : string - proto : protocol - zone : string - end - - new_ip : function (string, protocol) : ip_t - commonPrefixLength : function (ip_t, ip_t) : integer - parse_cidr : function (string) : ip_t, integer - match : function (ip_t, ip_t, integer) : boolean - is_ip : function (any) : boolean - truncate : function (ip_t, integer) : ip_t -end -return iplib diff --git a/teal-src/util/jid.d.tl b/teal-src/util/jid.d.tl deleted file mode 100644 index 897318d9..00000000 --- a/teal-src/util/jid.d.tl +++ /dev/null @@ -1,15 +0,0 @@ -local record lib - split : function (string) : string, string, string - bare : function (string) : string - prepped_split : function (string, boolean) : string, string, string - join : function (string, string, string) : string - prep : function (string, boolean) : string - compare : function (string, string) : boolean - node : function (string) : string - host : function (string) : string - resource : function (string) : string - escape : function (string) : string - unescape : function (string) : string -end - -return lib diff --git a/teal-src/util/json.d.tl b/teal-src/util/json.d.tl deleted file mode 100644 index a1c25004..00000000 --- a/teal-src/util/json.d.tl +++ /dev/null @@ -1,18 +0,0 @@ -local record lib - encode : function (any) : string - decode : function (string) : any, string - - enum json_type_name - "null" - "boolean" - "object" - "array" - "number" - "string" - "integer" - end - - type null_type = (nil) - null : null_type -end -return lib diff --git a/teal-src/util/jsonpointer.tl b/teal-src/util/jsonpointer.tl deleted file mode 100644 index c21e1fbf..00000000 --- a/teal-src/util/jsonpointer.tl +++ /dev/null @@ -1,46 +0,0 @@ - -local enum ptr_error - "invalid-table" - "invalid-path" -end - -local function unescape_token(escaped_token : string) : string - local unescaped = escaped_token:gsub("~1", "/"):gsub("~0", "~") - return unescaped -end - -local function resolve_json_pointer(ref : table, path : string) : any, ptr_error - local ptr_len = #path+1 - for part, pos in path:gmatch("/([^/]*)()") do - local token = unescape_token(part) - if not ref is table then - return nil - end - local idx = next(ref) - local new_ref : any - - if idx is string then - new_ref = ref[token] - elseif idx is integer then - local i = tonumber(token) - if token == "-" then i = #ref + 1 end - new_ref = ref[i+1] - else - return nil, "invalid-table" - end - - if pos as integer == ptr_len then - return new_ref - elseif new_ref is table then - ref = new_ref - elseif not ref is table then - return nil, "invalid-path" - end - - end - return ref -end - -return { - resolve = resolve_json_pointer, -} diff --git a/teal-src/util/jsonschema.tl b/teal-src/util/jsonschema.tl deleted file mode 100644 index 14b04370..00000000 --- a/teal-src/util/jsonschema.tl +++ /dev/null @@ -1,376 +0,0 @@ --- Copyright (C) 2021 Kim Alvefur --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- --- Based on --- https://json-schema.org/draft/2020-12/json-schema-core.html --- https://json-schema.org/draft/2020-12/json-schema-validation.html --- - -if not math.type then require "util.mathcompat" end - -local json = require"util.json" -local null = json.null; - -local pointer = require "util.jsonpointer" - -local type json_type_name = json.json_type_name - --- json_type_name here is non-standard -local type schema_t = boolean | json_schema_object - -local record json_schema_object - type json_type_name = json.json_type_name - type schema_object = json_schema_object - - type : json_type_name | { json_type_name } - enum : { any } - const : any - - allOf : { schema_t } - anyOf : { schema_t } - oneOf : { schema_t } - - ["not"] : schema_t - ["if"] : schema_t - ["then"] : schema_t - ["else"] : schema_t - - ["$ref"] : string - - -- numbers - multipleOf : number - maximum : number - exclusiveMaximum : number - minimum : number - exclusiveMinimum : number - - -- strings - maxLength : integer - minLength : integer - pattern : string -- NYI - format : string - - -- arrays - prefixItems : { schema_t } - items : schema_t - contains : schema_t - maxItems : integer - minItems : integer - uniqueItems : boolean - maxContains : integer -- NYI - minContains : integer -- NYI - - -- objects - properties : { string : schema_t } - maxProperties : integer -- NYI - minProperties : integer -- NYI - required : { string } - dependentRequired : { string : { string } } - additionalProperties: schema_t - patternProperties: schema_t -- NYI - propertyNames : schema_t - - -- xml - record xml_t - name : string - namespace : string - prefix : string - attribute : boolean - wrapped : boolean - - -- nonstantard, maybe in the future - text : boolean - x_name_is_value : boolean - x_single_attribute : string - end - - xml : xml_t - - -- descriptive - title : string - description : string - deprecated : boolean - readOnly : boolean - writeOnly : boolean - - -- methods - validate : function ( schema_t, any, json_schema_object ) : boolean -end - --- TODO validator function per schema property - -local function simple_validate(schema : json_type_name | { json_type_name }, data : any) : boolean - if schema == nil then - return true - elseif schema == "object" and data is table then - return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "string") - elseif schema == "array" and data is table then - return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "number") - elseif schema == "integer" then - return math.type(data) == schema - elseif schema == "null" then - return data == null - elseif schema is { json_type_name } then - for _, one in ipairs(schema as { json_type_name }) do - if simple_validate(one, data) then - return true - end - end - return false - else - return type(data) == schema - end -end - -local complex_validate : function ( json_schema_object, any, json_schema_object ) : boolean - -local function validate (schema : schema_t, data : any, root : json_schema_object) : boolean - if schema is boolean then - return schema - else - return complex_validate(schema, data, root) - end -end - -function complex_validate (schema : json_schema_object, data : any, root : json_schema_object) : boolean - - if root == nil then - root = schema - end - - if schema["$ref"] and schema["$ref"]:sub(1,1) == "#" then - local referenced = pointer.resolve(root as table, schema["$ref"]:sub(2)) as schema_t - if referenced ~= nil and referenced ~= root and referenced ~= schema then - if not validate(referenced, data, root) then - return false; - end - end - end - - if not simple_validate(schema.type, data) then - return false; - end - - if schema.type == "object" then - if data is table then - -- just check that there the keys are all strings - for k in pairs(data) do - if not k is string then - return false - end - end - end - end - - if schema.type == "array" then - if data is table then - -- just check that there the keys are all numbers - for i in pairs(data) do - if not i is integer then - return false - end - end - end - end - - if schema["enum"] ~= nil then - local match = false - for _, v in ipairs(schema["enum"]) do - if v == data then - -- FIXME supposed to do deep-compare - match = true - break - end - end - if not match then - return false - end - end - - -- XXX this is measured in byte, while JSON measures in ... bork - -- TODO use utf8.len? - if data is string then - if schema.maxLength and #data > schema.maxLength then - return false - end - if schema.minLength and #data < schema.minLength then - return false - end - end - - if data is number then - if schema.multipleOf and (data == 0 or data % schema.multipleOf ~= 0) then - return false - end - - if schema.maximum and not ( data <= schema.maximum ) then - return false - end - - if schema.exclusiveMaximum and not ( data < schema.exclusiveMaximum ) then - return false - end - - if schema.minimum and not ( data >= schema.minimum ) then - return false - end - - if schema.exclusiveMinimum and not ( data > schema.exclusiveMinimum ) then - return false - end - end - - if schema.allOf then - for _, sub in ipairs(schema.allOf) do - if not validate(sub, data, root) then - return false - end - end - end - - if schema.oneOf then - local valid = 0 - for _, sub in ipairs(schema.oneOf) do - if validate(sub, data, root) then - valid = valid + 1 - end - end - if valid ~= 1 then - return false - end - end - - if schema.anyOf then - local match = false - for _, sub in ipairs(schema.anyOf) do - if validate(sub, data, root) then - match = true - break - end - end - if not match then - return false - end - end - - if schema["not"] then - if validate(schema["not"], data, root) then - return false - end - end - - if schema["if"] ~= nil then - if validate(schema["if"], data, root) then - if schema["then"] then - return validate(schema["then"], data, root) - end - else - if schema["else"] then - return validate(schema["else"], data, root) - end - end - end - - if schema.const ~= nil and schema.const ~= data then - return false - end - - if data is table then - - if schema.maxItems and #data > schema.maxItems then - return false - end - - if schema.minItems and #data < schema.minItems then - return false - end - - if schema.required then - for _, k in ipairs(schema.required) do - if data[k] == nil then - return false - end - end - end - - if schema.propertyNames ~= nil then - for k in pairs(data) do - if not validate(schema.propertyNames, k, root) then - return false - end - end - end - - if schema.properties then - for k, sub in pairs(schema.properties) do - if data[k] ~= nil and not validate(sub, data[k], root) then - return false - end - end - end - - if schema.additionalProperties ~= nil then - for k, v in pairs(data) do - if schema.properties == nil or schema.properties[k as string] == nil then - if not validate(schema.additionalProperties, v, root) then - return false - end - end - end - end - - if schema.uniqueItems then - -- only works for scalars, would need to deep-compare for objects/arrays/tables - local values : { any : boolean } = {} - for _, v in pairs(data) do - if values[v] then - return false - end - values[v] = true - end - end - - local p = 0 - if schema.prefixItems ~= nil then - for i, s in ipairs(schema.prefixItems) do - if data[i] == nil then - break - elseif validate(s, data[i], root) then - p = i - else - return false - end - end - end - - if schema.items ~= nil then - for i = p+1, #data do - if not validate(schema.items, data[i], root) then - return false - end - end - end - - if schema.contains ~= nil then - local found = false - for i = 1, #data do - if validate(schema.contains, data[i], root) then - found = true - break - end - end - if not found then - return false - end - end - end - - return true; -end - - -json_schema_object.validate = validate; - -return json_schema_object; diff --git a/teal-src/util/jwt.d.tl b/teal-src/util/jwt.d.tl deleted file mode 100644 index 929d7419..00000000 --- a/teal-src/util/jwt.d.tl +++ /dev/null @@ -1,38 +0,0 @@ -local crypto = require "util.crypto" -local record jwtlib - enum algorithm - "HS256" - "HS384" - "HS512" - "ES256" - "ES512" - "RS256" - "RS384" - "RS512" - "PS256" - "PS384" - "PS512" - end - type payload = { string : any } - type signer_t = function (payload : payload) : string - type verifier_t = function (token : string) : payload - enum key_type - "rsaEncryption" - "id-ecPublicKey" - end - record algorithm_t - sign : signer_t - verify : verifier_t - load_key : function (key : string) : crypto.key - end - init : function (algorithm, private_key : string, public_key : string, table) : signer_t, verifier_t - new_signer : function (algorithm, string, table) : signer_t - new_verifier : function (algorithm, string, table) : verifier_t - _algorithms : { - algorithm : algorithm_t - } - -- Deprecated - sign : function (private_key : string, payload) : string - verify : function (string) : payload -end -return jwtlib diff --git a/teal-src/util/logger.d.tl b/teal-src/util/logger.d.tl deleted file mode 100644 index db29adfd..00000000 --- a/teal-src/util/logger.d.tl +++ /dev/null @@ -1,18 +0,0 @@ -local record util - enum loglevel - "debug" - "info" - "warn" - "error" - end - type logger = function ( loglevel, string, ...:any ) - type sink = function ( string, loglevel, string, ...:any ) - type simple_sink = function ( string, loglevel, string ) - init : function ( string ) : logger - make_logger : function ( string, loglevel ) : function ( string, ...:any ) - reset : function () - add_level_sink : function ( loglevel, sink ) - add_simple_sink : function ( simple_sink, { loglevel } ) -end - -return util diff --git a/teal-src/util/mathcompat.tl b/teal-src/util/mathcompat.tl deleted file mode 100644 index 1e3f9bab..00000000 --- a/teal-src/util/mathcompat.tl +++ /dev/null @@ -1,15 +0,0 @@ -if not math.type then - local enum number_subtype - "float" "integer" - end - local function math_type(t:any) : number_subtype - if t is number then - if t % 1 == 0 and t ~= t+1 and t ~= t-1 then - return "integer" - else - return "float" - end - end - end - _G.math.type = math_type -end diff --git a/teal-src/util/net.d.tl b/teal-src/util/net.d.tl deleted file mode 100644 index 1040fcef..00000000 --- a/teal-src/util/net.d.tl +++ /dev/null @@ -1,13 +0,0 @@ - -local enum type_strings - "both" - "ipv4" - "ipv6" -end - -local record lib - local_addresses : function (type_strings, boolean) : { string } - pton : function (string):string - ntop : function (string):string -end -return lib diff --git a/teal-src/util/poll.d.tl b/teal-src/util/poll.d.tl deleted file mode 100644 index 8df56d57..00000000 --- a/teal-src/util/poll.d.tl +++ /dev/null @@ -1,31 +0,0 @@ -local record state - enum waiterr - "timeout" - "signal" - end - add : function (state, integer, boolean, boolean) : boolean - add : function (state, integer, boolean, boolean) : nil, string, integer - set : function (state, integer, boolean, boolean) : boolean - set : function (state, integer, boolean, boolean) : nil, string, integer - del : function (state, integer) : boolean - del : function (state, integer) : nil, string, integer - wait : function (state, integer) : integer, boolean, boolean - wait : function (state, integer) : nil, string, integer - wait : function (state, integer) : nil, waiterr - getfd : function (state) : integer -end - -local record lib - new : function () : state - EEXIST : integer - EMFILE : integer - ENOENT : integer - enum api_backend - "epoll" - "poll" - "select" - end - api : api_backend -end - -return lib diff --git a/teal-src/util/pposix.d.tl b/teal-src/util/pposix.d.tl deleted file mode 100644 index 68f49730..00000000 --- a/teal-src/util/pposix.d.tl +++ /dev/null @@ -1,108 +0,0 @@ -local record pposix - enum syslog_facility - "auth" - "authpriv" - "cron" - "daemon" - "ftp" - "kern" - "local0" - "local1" - "local2" - "local3" - "local4" - "local5" - "local6" - "local7" - "lpr" - "mail" - "syslog" - "user" - "uucp" - end - - enum syslog_level - "debug" - "info" - "notice" - "warn" - "error" - end - - enum ulimit_resource - "CORE" - "CPU" - "DATA" - "FSIZE" - "NOFILE" - "STACK" - "MEMLOCK" - "NPROC" - "RSS" - "NICE" - end - - enum ulimit_unlimited - "unlimited" - end - - type ulimit_limit = integer | ulimit_unlimited - - record utsname - sysname : string - nodename : string - release : string - version : string - machine : string - domainname : string - end - - record memoryinfo - allocated : integer - allocated_mmap : integer - used : integer - unused : integer - returnable : integer - end - - abort : function () - - daemonize : function () : boolean, string - - syslog_open : function (ident : string, facility : syslog_facility) - syslog_close : function () - syslog_log : function (level : syslog_level, src : string, msg : string) - syslog_setminlevel : function (level : syslog_level) - - getpid : function () : integer - getuid : function () : integer - getgid : function () : integer - - setuid : function (uid : integer | string) : boolean, string -- string|integer - setgid : function (uid : integer | string) : boolean, string - initgroups : function (user : string, gid : integer) : boolean, string - - umask : function (umask : string) : string - - mkdir : function (dir : string) : boolean, string - - setrlimit : function (resource : ulimit_resource, soft : ulimit_limit, hard : ulimit_limit) : boolean, string - getrlimit : function (resource : ulimit_resource) : boolean, ulimit_limit, ulimit_limit - getrlimit : function (resource : ulimit_resource) : boolean, string - - uname : function () : utsname - - setenv : function (key : string, value : string) : boolean - - meminfo : function () : memoryinfo - - atomic_append : function (f : FILE, s : string) : boolean, string, integer - - isatty : function(FILE) : boolean - - ENOENT : integer - _NAME : string - _VESRION : string -end - -return pposix diff --git a/teal-src/util/promise.d.tl b/teal-src/util/promise.d.tl deleted file mode 100644 index d895a828..00000000 --- a/teal-src/util/promise.d.tl +++ /dev/null @@ -1,22 +0,0 @@ - -local record lib - type resolve_func = function (any) - type promise_body = function (resolve_func, resolve_func) - - record Promise - type on_resolved = function (A) : any - type on_rejected = function (B) : any - next : function (Promise, on_resolved, on_rejected) : Promise - end - - new : function (promise_body) : Promise - resolve : function (any) : Promise - reject : function (any) : Promise - all : function ({ Promise }) : Promise - all_settled : function ({ Promise }) : Promise - race : function ({ Promise }) : Promise - try : function - is_promise : function(any) : boolean -end - -return lib diff --git a/teal-src/util/queue.d.tl b/teal-src/util/queue.d.tl deleted file mode 100644 index cb8458e7..00000000 --- a/teal-src/util/queue.d.tl +++ /dev/null @@ -1,21 +0,0 @@ -local record lib - record queue - size : integer - count : function (queue) : integer - enum push_errors - "queue full" - end - - push : function (queue, T) : boolean, push_errors - pop : function (queue) : T - peek : function (queue) : T - replace : function (queue, T) : boolean, push_errors - type iterator = function (T, integer) : integer, T - items : function (queue) : iterator, T, integer - type consume_iter = function (queue) : T - consume : function (queue) : consume_iter - end - - new : function (size:integer, allow_wrapping:boolean) : queue -end -return lib; diff --git a/teal-src/util/random.d.tl b/teal-src/util/random.d.tl deleted file mode 100644 index 83ff2fcc..00000000 --- a/teal-src/util/random.d.tl +++ /dev/null @@ -1,4 +0,0 @@ -local record lib - bytes : function (n:integer):string -end -return lib diff --git a/teal-src/util/ringbuffer.d.tl b/teal-src/util/ringbuffer.d.tl deleted file mode 100644 index e4726d68..00000000 --- a/teal-src/util/ringbuffer.d.tl +++ /dev/null @@ -1,20 +0,0 @@ -local record lib - record ringbuffer - find : function (ringbuffer, string) : integer - discard : function (ringbuffer, integer) : boolean - read : function (ringbuffer, integer, boolean) : string - readuntil : function (ringbuffer, string) : string - write : function (ringbuffer, string) : integer - size : function (ringbuffer) : integer - length : function (ringbuffer) : integer - sub : function (ringbuffer, integer, integer) : string - byte : function (ringbuffer, integer, integer) : integer... - free : function (ringbuffer) : integer - end - - new : function (integer) : ringbuffer -end - -return lib - - diff --git a/teal-src/util/roles.d.tl b/teal-src/util/roles.d.tl deleted file mode 100644 index fef4f88a..00000000 --- a/teal-src/util/roles.d.tl +++ /dev/null @@ -1,32 +0,0 @@ -local record util_roles - - type context = any - - record Role - id : string - name : string - description : string - default : boolean - priority : number -- or integer? - permissions : { string : boolean } - - may : function (Role, string, context) - clone : function (Role, role_config) - set_permission : function (Role, string, boolean, boolean) - end - - is_role : function (any) : boolean - - record role_config - name : string - description : string - default : boolean - priority : number -- or integer? - inherits : { Role } - permissions : { string : boolean } - end - - new : function (role_config, Role) : Role -end - -return util_roles diff --git a/teal-src/util/serialization.d.tl b/teal-src/util/serialization.d.tl deleted file mode 100644 index 27f100c0..00000000 --- a/teal-src/util/serialization.d.tl +++ /dev/null @@ -1,33 +0,0 @@ -local record _M - enum preset - "debug" - "oneline" - "compact" - end - type fallback = function (any, string) : string - record config - preset : preset - fallback : fallback - fatal : boolean - keywords : { string : boolean } - indentwith : string - itemstart : string - itemsep : string - itemlast : string - tstart : string - tend : string - kstart : string - kend : string - equals : string - unquoted : boolean | string - hex : string - freeze : boolean - maxdepth : integer - multirefs : boolean - table_pairs : function - end - type serializer = function (any) : string - new : function (config|preset) : serializer - serialize : function (any, config|preset) : string -end -return _M diff --git a/teal-src/util/set.d.tl b/teal-src/util/set.d.tl deleted file mode 100644 index 1631eec4..00000000 --- a/teal-src/util/set.d.tl +++ /dev/null @@ -1,21 +0,0 @@ -local record lib - record Set - add : function (Set, T) - contains : function (Set, T) : boolean - contains_set : function (Set, Set) : boolean - items : function (Set) : function (Set, T) : T - add_list : function (Set, { T }) - include : function (Set, Set) - exclude : function (Set, Set) - empty : function (Set) : boolean - end - - new : function ({ T }) : Set - is_set : function (any) : boolean - union : function (Set, Set) : Set - difference : function (Set, Set) : Set - intersection : function (Set, Set) : Set - xor : function (Set, Set) : Set -end - -return lib diff --git a/teal-src/util/signal.d.tl b/teal-src/util/signal.d.tl deleted file mode 100644 index 290cf08f..00000000 --- a/teal-src/util/signal.d.tl +++ /dev/null @@ -1,41 +0,0 @@ -local record lib - enum Signal - "SIGABRT" - "SIGALRM" - "SIGBUS" - "SIGCHLD" - "SIGCLD" - "SIGCONT" - "SIGFPE" - "SIGHUP" - "SIGILL" - "SIGINT" - "SIGIO" - "SIGIOT" - "SIGKILL" - "SIGPIPE" - "SIGPOLL" - "SIGPROF" - "SIGQUIT" - "SIGSEGV" - "SIGSTKFLT" - "SIGSTOP" - "SIGSYS" - "SIGTERM" - "SIGTRAP" - "SIGTTIN" - "SIGTTOU" - "SIGURG" - "SIGUSR1" - "SIGUSR2" - "SIGVTALRM" - "SIGWINCH" - "SIGXCPU" - "SIGXFSZ" - end - signal : function (integer | Signal, function, boolean) : boolean - raise : function (integer | Signal) - kill : function (integer, integer | Signal) - -- enum : integer -end -return lib diff --git a/teal-src/util/smqueue.tl b/teal-src/util/smqueue.tl deleted file mode 100644 index e149dde7..00000000 --- a/teal-src/util/smqueue.tl +++ /dev/null @@ -1,99 +0,0 @@ -local queue = require "util.queue"; - -local record lib - -- T would typically be util.stanza - record smqueue - _queue : queue.queue - _head : integer - _tail : integer - - enum ack_errors - "tail" - "head" - "pop" - end - push : function (smqueue, T) - ack : function (smqueue, integer) : { T }, ack_errors - resumable : function (smqueue) : boolean - resume : function (smqueue) : queue.queue.iterator, any, integer - type consume_iter = function (smqueue) : T - consume : function (smqueue) : consume_iter - - table : function (smqueue) : { T } - end - new : function (integer) : smqueue -end - -local type smqueue = lib.smqueue; - -function smqueue:push(v) - self._head = self._head + 1; - -- Wraps instead of errors - assert(self._queue:push(v)); -end - -function smqueue:ack(h : integer) : { any }, smqueue.ack_errors - if h < self._tail then - return nil, "tail"; - elseif h > self._head then - return nil, "head"; - end - -- TODO optimize? cache table fields - local acked = {}; - self._tail = h; - local expect = self._head - self._tail; - while expect < self._queue:count() do - local v = self._queue:pop(); - if not v then return nil, "pop"; end - table.insert(acked, v); - end - return acked; -end - -function smqueue:count_unacked() : integer - return self._head - self._tail; -end - -function smqueue:count_acked() : integer - return self._tail; -end - -function smqueue:resumable() : boolean - return self._queue:count() >= (self._head - self._tail); -end - -function smqueue:resume() : queue.queue.iterator, any, integer - return self._queue:items(); -end - -function smqueue:consume() : queue.queue.consume_iter - return self._queue:consume() -end - --- Compatibility layer, plain ol' table -function smqueue:table() : { any } - local t : { any } = {}; - for i, v in self:resume() do - t[i] = v; - end - return t; -end - -local function freeze(q : smqueue) : { string:integer } - return { head = q._head, tail = q._tail } -end - -local queue_mt = { - -- - __name = "smqueue"; - __index = smqueue; - __len = smqueue.count_unacked; - __freeze = freeze; -} - -function lib.new(size : integer) : queue.queue - assert(size>0); - return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true) }, queue_mt); -end - -return lib; diff --git a/teal-src/util/stanza.d.tl b/teal-src/util/stanza.d.tl deleted file mode 100644 index e1ab2105..00000000 --- a/teal-src/util/stanza.d.tl +++ /dev/null @@ -1,145 +0,0 @@ -local record lib - - type children_iter = function ( stanza_t ) : stanza_t - type childtags_iter = function () : stanza_t - type maptags_cb = function ( stanza_t ) : stanza_t - - - enum stanza_error_type - "auth" - "cancel" - "continue" - "modify" - "wait" - end - enum stanza_error_condition - "bad-request" - "conflict" - "feature-not-implemented" - "forbidden" - "gone" - "internal-server-error" - "item-not-found" - "jid-malformed" - "not-acceptable" - "not-allowed" - "not-authorized" - "policy-violation" - "recipient-unavailable" - "redirect" - "registration-required" - "remote-server-not-found" - "remote-server-timeout" - "resource-constraint" - "service-unavailable" - "subscription-required" - "undefined-condition" - "unexpected-request" - end - - record stanza_t - name : string - attr : { string : string } - { stanza_t | string } - tags : { stanza_t } - - query : function ( stanza_t, string ) : stanza_t - body : function ( stanza_t, string, { string : string } ) : stanza_t - text_tag : function ( stanza_t, string, string, { string : string } ) : stanza_t - tag : function ( stanza_t, string, { string : string } ) : stanza_t - text : function ( stanza_t, string ) : stanza_t - up : function ( stanza_t ) : stanza_t - at_top : function ( stanza_t ) : boolean - reset : function ( stanza_t ) : stanza_t - add_direct_child : function ( stanza_t, stanza_t ) - add_child : function ( stanza_t, stanza_t ) - remove_children : function ( stanza_t, string, string ) : stanza_t - - get_child : function ( stanza_t, string, string ) : stanza_t - get_text : function ( stanza_t ) : string - get_child_text : function ( stanza_t, string, string ) : string - get_child_attr : function ( stanza_t, string, string ) : string - get_child_with_attr : function ( stanza_t, string, string, string, function (string) : boolean ) : string - child_with_name : function ( stanza_t, string, string ) : stanza_t - child_with_ns : function ( stanza_t, string, string ) : stanza_t - children : function ( stanza_t ) : children_iter, stanza_t, integer - childtags : function ( stanza_t, string, string ) : childtags_iter - maptags : function ( stanza_t, maptags_cb ) : stanza_t - find : function ( stanza_t, string ) : stanza_t | string - - top_tag : function ( stanza_t ) : string - pretty_print : function ( stanza_t ) : string - pretty_top_tag : function ( stanza_t ) : string - - -- FIXME Represent util.error support - get_error : function ( stanza_t ) : stanza_error_type, stanza_error_condition, string, stanza_t - add_error : function ( stanza_t, stanza_error_type, stanza_error_condition, string, string ) - indent : function ( stanza_t, integer, string ) : stanza_t - end - - record serialized_stanza_t - name : string - attr : { string : string } - { serialized_stanza_t | string } - end - - record message_attr - ["xml:lang"] : string - from : string - id : string - to : string - type : message_type - enum message_type - "chat" - "error" - "groupchat" - "headline" - "normal" - end - end - - record presence_attr - ["xml:lang"] : string - from : string - id : string - to : string - type : presence_type - enum presence_type - "error" - "probe" - "subscribe" - "subscribed" - "unsubscribe" - "unsubscribed" - end - end - - record iq_attr - ["xml:lang"] : string - from : string - id : string - to : string - type : iq_type - enum iq_type - "error" - "get" - "result" - "set" - end - end - - stanza : function ( string, { string : string } ) : stanza_t - is_stanza : function ( any ) : boolean - preserialize : function ( stanza_t ) : serialized_stanza_t - deserialize : function ( serialized_stanza_t ) : stanza_t - clone : function ( stanza_t, boolean ) : stanza_t - message : function ( message_attr, string ) : stanza_t - iq : function ( iq_attr ) : stanza_t - reply : function ( stanza_t ) : stanza_t - error_reply : function ( stanza_t, stanza_error_type, stanza_error_condition, string, string ) : stanza_t - presence : function ( presence_attr ) : stanza_t - xml_escape : function ( string ) : string - pretty_print : function ( string ) : string -end - -return lib diff --git a/teal-src/util/strbitop.d.tl b/teal-src/util/strbitop.d.tl deleted file mode 100644 index 010efdb8..00000000 --- a/teal-src/util/strbitop.d.tl +++ /dev/null @@ -1,6 +0,0 @@ -local record mod - sand : function (string, string) : string - sor : function (string, string) : string - sxor : function (string, string) : string -end -return mod diff --git a/teal-src/util/struct.d.tl b/teal-src/util/struct.d.tl deleted file mode 100644 index 201aaa23..00000000 --- a/teal-src/util/struct.d.tl +++ /dev/null @@ -1,6 +0,0 @@ -local record lib - pack : function (string, ...:any) : string - unpack : function(string, string, integer) : any... - size : function(string) : integer -end -return lib diff --git a/teal-src/util/table.d.tl b/teal-src/util/table.d.tl deleted file mode 100644 index 67e5d0f0..00000000 --- a/teal-src/util/table.d.tl +++ /dev/null @@ -1,7 +0,0 @@ -local record lib - create : function (narr:integer, nrec:integer):table - pack : function (...:any):{any} - move : function (table, integer, integer, integer, table) : table -end -return lib - diff --git a/teal-src/util/termcolours.d.tl b/teal-src/util/termcolours.d.tl deleted file mode 100644 index 226259aa..00000000 --- a/teal-src/util/termcolours.d.tl +++ /dev/null @@ -1,7 +0,0 @@ -local record lib - getstring : function (string, string) : string - getstyle : function (...:string) : string - setstyle : function (string) : string - tohtml : function (string) : string -end -return lib diff --git a/teal-src/util/time.d.tl b/teal-src/util/time.d.tl deleted file mode 100644 index e159706b..00000000 --- a/teal-src/util/time.d.tl +++ /dev/null @@ -1,6 +0,0 @@ - -local record lib - now : function () : number - monotonic : function () : number -end -return lib diff --git a/teal-src/util/timer.d.tl b/teal-src/util/timer.d.tl deleted file mode 100644 index a6394cf3..00000000 --- a/teal-src/util/timer.d.tl +++ /dev/null @@ -1,8 +0,0 @@ -local record util_timer - record task end - type timer_callback = function (number) : number - add_task : function ( number, timer_callback, any ) : task - stop : function ( task ) - reschedule : function ( task, number ) : task -end -return util_timer diff --git a/teal-src/util/uuid.d.tl b/teal-src/util/uuid.d.tl deleted file mode 100644 index 284a4e4c..00000000 --- a/teal-src/util/uuid.d.tl +++ /dev/null @@ -1,8 +0,0 @@ -local record lib - get_nibbles : function (number) : string - generate : function () : string - - seed : function (string) -end -return lib - diff --git a/teal-src/util/xtemplate.tl b/teal-src/util/xtemplate.tl deleted file mode 100644 index b3bdc400..00000000 --- a/teal-src/util/xtemplate.tl +++ /dev/null @@ -1,101 +0,0 @@ --- render(template, stanza) --> string --- {path} --> stanza:find(path) --- {{ns}name/child|each({ns}name){sub-template}} - ---[[ -template ::= "{" path ("|" name ("(" args ")")? (template)? )* "}" -path ::= defined by util.stanza -name ::= %w+ -args ::= anything with balanced ( ) pairs -]] - -local s_gsub = string.gsub; -local s_match = string.match; -local s_sub = string.sub; -local t_concat = table.concat; - -local st = require "util.stanza"; - -local type escape_t = function (string) : string -local type filter_t = function (string, string | st.stanza_t, string) : string | st.stanza_t, boolean -local type filter_coll = { string : filter_t } - -local function render(template : string, root : st.stanza_t, escape : escape_t, filters : filter_coll) : string - escape = escape or st.xml_escape; - - return (s_gsub(template, "%b{}", function(block : string) : string - local inner = s_sub(block, 2, -2); - local path, pipe, pos = s_match(inner, "^([^|]+)(|?)()"); - if not path is string then return end - local value : string | st.stanza_t - if path == "." then - value = root; - elseif path == "#" then - value = root:get_text(); - else - value = root:find(path); - end - local is_escaped = false; - - while pipe == "|" do - local func, args, tmpl, p = s_match(inner, "^(%w+)(%b())(%b{})()", pos as integer); - if not func then func, args, p = s_match(inner, "^(%w+)(%b())()", pos as integer); end - if not func then func, tmpl, p = s_match(inner, "^(%w+)(%b{})()", pos as integer); end - if not func then func, p = s_match(inner, "^(%w+)()", pos as integer); end - if not func then break end - if tmpl then tmpl = s_sub(tmpl, 2, -2); end - if args then args = s_sub(args, 2, -2); end - - if func == "each" and tmpl and st.is_stanza(value) then - if not args then value, args = root, path; end - local ns, name = s_match(args, "^(%b{})(.*)$"); - if ns then ns = s_sub(ns, 2, -2); else name, ns = args, nil; end - if ns == "" then ns = nil; end - if name == "" then name = nil; end - local out, i = {}, 1; - for c in (value as st.stanza_t):childtags(name, ns) do - out[i], i = render(tmpl, c, escape, filters), i + 1; - end - value = t_concat(out); - is_escaped = true; - elseif func == "and" and tmpl then - local condition = value; - if args then condition = root:find(args); end - if condition then - value = render(tmpl, root, escape, filters); - is_escaped = true; - end - elseif func == "or" and tmpl then - local condition = value; - if args then condition = root:find(args); end - if not condition then - value = render(tmpl, root, escape, filters); - is_escaped = true; - end - elseif filters and filters[func] then - local f = filters[func]; - if args == nil then - value, is_escaped = f(value, tmpl); - else - value, is_escaped = f(args, value, tmpl); - end - else - error("No such filter function: " .. func); - end - pipe, pos = s_match(inner, "^(|?)()", p as integer); - end - - if value is string then - if not is_escaped then value = escape(value); end - return value; - elseif st.is_stanza(value) then - value = value:get_text(); - if value then - return escape(value); - end - end - return ""; - end)); -end - -return { render = render }; -- cgit v1.2.3