--- a/GNUmakefile Fri Mar 17 19:38:39 2023 +0100
+++ b/GNUmakefile Thu Mar 23 13:36:52 2023 +0100
@@ -135,7 +135,7 @@
@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 $@
--- a/teal-src/core/storagemanager.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/core/usermanager.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/module.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ b/teal-src/module.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -1,4 +1,4 @@
-local st = require"util.stanza"
+local st = require "prosody.util.stanza"
global record moduleapi
get_name : function (moduleapi) : string
--- a/teal-src/net/http.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/net/http/codes.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-local type response_codes = { integer : string }
-return response_codes
--- a/teal-src/net/http/errors.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/net/http/files.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/net/http/parser.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/net/http/server.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-local record http_server
- -- TODO
-end
-
-return http_server
--- a/teal-src/net/server.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/plugins/mod_cron.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-module:set_global();
-
-local async = require "util.async";
-local datetime = require "util.datetime";
-
-local record map_store<K,V>
- -- TODO move to somewhere sensible
- get : function (map_store<K,V>, string, K) : V
- set : function (map_store<K,V>, 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<string,integer>;
- 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<task_spec> = 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
--- a/teal-src/plugins/muc/muc.lib.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/core/storagemanager.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/core/usermanager.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http/codes.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,2 @@
+local type response_codes = { integer : string }
+return response_codes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http/errors.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http/files.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http/parser.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/http/server.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,6 @@
+
+local record http_server
+ -- TODO
+end
+
+return http_server
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/net/server.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/plugins/mod_cron.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,106 @@
+module:set_global();
+
+local async = require "prosody.util.async";
+local datetime = require "prosody.util.datetime";
+
+local record map_store<K,V>
+ -- TODO move to somewhere sensible
+ get : function (map_store<K,V>, string, K) : V
+ set : function (map_store<K,V>, 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<string,integer>;
+ 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<task_spec> = 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/plugins/muc/muc.lib.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/array.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,9 @@
+local record array_t<T>
+ { T }
+end
+
+local record lib
+ metamethod __call : function () : array_t
+end
+
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/async.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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<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<T>, ... : any)
+ type watchers_t = { state_e : watcher_t }
+ data : any
+ id : string
+
+ run : function (runner_t<T>, T) : boolean, state_e, integer
+ enqueue : function (runner_t<T>, T) : runner_t<T>
+ log : function (runner_t<T>, string, string, ... : any)
+ onready : function (runner_t<T>, function) : runner_t<T>
+ onready : function (runner_t<T>, function) : runner_t<T>
+ onwaiting : function (runner_t<T>, function) : runner_t<T>
+ onerror : function (runner_t<T>, function) : runner_t<T>
+ end
+ runner : function <T>(function (T), runner_t.watchers_t, any) : runner_t<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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/bitcompat.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/compat.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,4 @@
+local record lib
+ xpcall : function (function, function, ...:any):boolean, any
+end
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/crand.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,6 @@
+local record lib
+ bytes : function (n : integer) : string
+ enum sourceid "OpenSSL" "arc4random()" "Linux" end
+ _source : sourceid
+end
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/crypto.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/dataforms.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/datamapper.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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 <tag-name/> is the value
+-- x_single_attribute for <tag attr="this"/>
+--
+-- 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,
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/datetime.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/encodings.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/error.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/format.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,4 @@
+local record lib
+ format : function (string, ... : any) : string
+end
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/hashes.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/hex.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/http.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/human/io.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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<K,V>
+ 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> ({ K : V }) : string
+ table : function<K,V> ({ tablerow<K,V> }, width : integer) : getrow<K,V>
+end
+
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/human/units.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/id.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,9 @@
+local record lib
+ short : function () : string
+ medium : function () : string
+ long : function () : string
+ custom : function (integer) : function () : string
+
+end
+return lib
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/interpolation.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/ip.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/jid.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/json.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/jsonpointer.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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,
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/jsonschema.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/jwt.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/logger.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/mathcompat.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/net.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/poll.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/pposix.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/promise.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,22 @@
+
+local record lib
+ type resolve_func = function (any)
+ type promise_body = function (resolve_func, resolve_func)
+
+ record Promise<A, B>
+ type on_resolved = function (A) : any
+ type on_rejected = function (B) : any
+ next : function (Promise, on_resolved, on_rejected) : Promise<any, any>
+ 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/queue.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,21 @@
+local record lib
+ record queue<T>
+ size : integer
+ count : function (queue<T>) : integer
+ enum push_errors
+ "queue full"
+ end
+
+ push : function (queue<T>, T) : boolean, push_errors
+ pop : function (queue<T>) : T
+ peek : function (queue<T>) : T
+ replace : function (queue<T>, T) : boolean, push_errors
+ type iterator = function (T, integer) : integer, T
+ items : function (queue<T>) : iterator, T, integer
+ type consume_iter = function (queue<T>) : T
+ consume : function (queue<T>) : consume_iter
+ end
+
+ new : function<T> (size:integer, allow_wrapping:boolean) : queue<T>
+end
+return lib;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/random.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,4 @@
+local record lib
+ bytes : function (n:integer):string
+end
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/ringbuffer.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/roles.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/serialization.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/set.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,21 @@
+local record lib
+ record Set<T>
+ add : function<T> (Set<T>, T)
+ contains : function<T> (Set<T>, T) : boolean
+ contains_set : function<T> (Set<T>, Set<T>) : boolean
+ items : function<T> (Set<T>) : function<T> (Set<T>, T) : T
+ add_list : function<T> (Set<T>, { T })
+ include : function<T> (Set<T>, Set<T>)
+ exclude : function<T> (Set<T>, Set<T>)
+ empty : function<T> (Set<T>) : boolean
+ end
+
+ new : function<T> ({ T }) : Set<T>
+ is_set : function (any) : boolean
+ union : function<T> (Set<T>, Set<T>) : Set <T>
+ difference : function<T> (Set<T>, Set<T>) : Set <T>
+ intersection : function<T> (Set<T>, Set<T>) : Set <T>
+ xor : function<T> (Set<T>, Set<T>) : Set <T>
+end
+
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/signal.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/smqueue.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,99 @@
+local queue = require "prosody.util.queue";
+
+local record lib
+ -- T would typically be util.stanza
+ record smqueue<T>
+ _queue : queue.queue<T>
+ _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<T>) : boolean
+ resume : function (smqueue<T>) : queue.queue.iterator, any, integer
+ type consume_iter = function (smqueue<T>) : T
+ consume : function (smqueue<T>) : consume_iter
+
+ table : function (smqueue<T>) : { T }
+ end
+ new : function <T>(integer) : smqueue<T>
+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<any>) : { 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<T>(size : integer) : queue.queue<T>
+ assert(size>0);
+ return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true) }, queue_mt);
+end
+
+return lib;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/stanza.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/strbitop.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/struct.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/table.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/termcolours.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/time.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,6 @@
+
+local record lib
+ now : function () : number
+ monotonic : function () : number
+end
+return lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/timer.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/uuid.d.tl Thu Mar 23 13:36:52 2023 +0100
@@ -0,0 +1,8 @@
+local record lib
+ get_nibbles : function (number) : string
+ generate : function () : string
+
+ seed : function (string)
+end
+return lib
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/teal-src/prosody/util/xtemplate.tl Thu Mar 23 13:36:52 2023 +0100
@@ -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 };
--- a/teal-src/util/array.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-local record array_t<T>
- { T }
-end
-
-local record lib
- metamethod __call : function () : array_t
-end
-
-return lib
--- a/teal-src/util/async.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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<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<T>, ... : any)
- type watchers_t = { state_e : watcher_t }
- data : any
- id : string
-
- run : function (runner_t<T>, T) : boolean, state_e, integer
- enqueue : function (runner_t<T>, T) : runner_t<T>
- log : function (runner_t<T>, string, string, ... : any)
- onready : function (runner_t<T>, function) : runner_t<T>
- onready : function (runner_t<T>, function) : runner_t<T>
- onwaiting : function (runner_t<T>, function) : runner_t<T>
- onerror : function (runner_t<T>, function) : runner_t<T>
- end
- runner : function <T>(function (T), runner_t.watchers_t, any) : runner_t<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
--- a/teal-src/util/bitcompat.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/compat.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-local record lib
- xpcall : function (function, function, ...:any):boolean, any
-end
-return lib
--- a/teal-src/util/crand.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-local record lib
- bytes : function (n : integer) : string
- enum sourceid "OpenSSL" "arc4random()" "Linux" end
- _source : sourceid
-end
-return lib
--- a/teal-src/util/crypto.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/dataforms.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/datamapper.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 <tag-name/> is the value
--- x_single_attribute for <tag attr="this"/>
---
--- 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,
-}
--- a/teal-src/util/datetime.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/encodings.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
-
--- a/teal-src/util/error.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/format.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-local record lib
- format : function (string, ... : any) : string
-end
-return lib
--- a/teal-src/util/hashes.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/hex.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/http.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/human/io.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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<K,V>
- 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> ({ K : V }) : string
- table : function<K,V> ({ tablerow<K,V> }, width : integer) : getrow<K,V>
-end
-
-return lib
--- a/teal-src/util/human/units.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/id.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-local record lib
- short : function () : string
- medium : function () : string
- long : function () : string
- custom : function (integer) : function () : string
-
-end
-return lib
-
--- a/teal-src/util/interpolation.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/ip.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/jid.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/json.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/jsonpointer.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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,
-}
--- a/teal-src/util/jsonschema.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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;
--- a/teal-src/util/jwt.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/logger.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/mathcompat.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/net.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/poll.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/pposix.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/promise.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-
-local record lib
- type resolve_func = function (any)
- type promise_body = function (resolve_func, resolve_func)
-
- record Promise<A, B>
- type on_resolved = function (A) : any
- type on_rejected = function (B) : any
- next : function (Promise, on_resolved, on_rejected) : Promise<any, any>
- 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
--- a/teal-src/util/queue.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-local record lib
- record queue<T>
- size : integer
- count : function (queue<T>) : integer
- enum push_errors
- "queue full"
- end
-
- push : function (queue<T>, T) : boolean, push_errors
- pop : function (queue<T>) : T
- peek : function (queue<T>) : T
- replace : function (queue<T>, T) : boolean, push_errors
- type iterator = function (T, integer) : integer, T
- items : function (queue<T>) : iterator, T, integer
- type consume_iter = function (queue<T>) : T
- consume : function (queue<T>) : consume_iter
- end
-
- new : function<T> (size:integer, allow_wrapping:boolean) : queue<T>
-end
-return lib;
--- a/teal-src/util/random.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-local record lib
- bytes : function (n:integer):string
-end
-return lib
--- a/teal-src/util/ringbuffer.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
-
-
--- a/teal-src/util/roles.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/serialization.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/set.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-local record lib
- record Set<T>
- add : function<T> (Set<T>, T)
- contains : function<T> (Set<T>, T) : boolean
- contains_set : function<T> (Set<T>, Set<T>) : boolean
- items : function<T> (Set<T>) : function<T> (Set<T>, T) : T
- add_list : function<T> (Set<T>, { T })
- include : function<T> (Set<T>, Set<T>)
- exclude : function<T> (Set<T>, Set<T>)
- empty : function<T> (Set<T>) : boolean
- end
-
- new : function<T> ({ T }) : Set<T>
- is_set : function (any) : boolean
- union : function<T> (Set<T>, Set<T>) : Set <T>
- difference : function<T> (Set<T>, Set<T>) : Set <T>
- intersection : function<T> (Set<T>, Set<T>) : Set <T>
- xor : function<T> (Set<T>, Set<T>) : Set <T>
-end
-
-return lib
--- a/teal-src/util/signal.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/smqueue.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-local queue = require "util.queue";
-
-local record lib
- -- T would typically be util.stanza
- record smqueue<T>
- _queue : queue.queue<T>
- _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<T>) : boolean
- resume : function (smqueue<T>) : queue.queue.iterator, any, integer
- type consume_iter = function (smqueue<T>) : T
- consume : function (smqueue<T>) : consume_iter
-
- table : function (smqueue<T>) : { T }
- end
- new : function <T>(integer) : smqueue<T>
-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<any>) : { 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<T>(size : integer) : queue.queue<T>
- assert(size>0);
- return setmetatable({ _head = 0; _tail = 0; _queue = queue.new(size, true) }, queue_mt);
-end
-
-return lib;
--- a/teal-src/util/stanza.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/strbitop.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/struct.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/table.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
-
--- a/teal-src/util/termcolours.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/time.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-local record lib
- now : function () : number
- monotonic : function () : number
-end
-return lib
--- a/teal-src/util/timer.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/teal-src/util/uuid.d.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-local record lib
- get_nibbles : function (number) : string
- generate : function () : string
-
- seed : function (string)
-end
-return lib
-
--- a/teal-src/util/xtemplate.tl Fri Mar 17 19:38:39 2023 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 };