changeset 6300:8689f49d21ef

mod_voipms: Updates
author Menel <menel@snikket.de>
date Tue, 22 Jul 2025 06:24:32 +0200
parents 5cf5ee23b361
children 77b5dd33a8f3
files mod_voipms/README.md mod_voipms/mod_voipms.lua
diffstat 2 files changed, 61 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/mod_voipms/README.md	Mon Jul 21 23:57:37 2025 +0200
+++ b/mod_voipms/README.md	Tue Jul 22 06:24:32 2025 +0200
@@ -17,22 +17,23 @@
 Configuration
 =============
 
-| option                | type   | default |
-|-----------------------|--------|---------|
-| voipms\_api\_username | string | nil     |
-| voipms\_api\_password | string | nil     |
-| voipms\_query\_key    | string | nil     |
-| voipms\_jid\_map      | table  | nil     |
+| option                | type   | default | description
+|-----------------------|--------|---------|------------|
+| voipms\_api\_username | string | nil     | E-mail address used at voip.ms 
+| voipms\_api\_password | string | nil     | API password (not login password)
+| voipms\_query\_key    | string | nil     | Key to secure service (part of webhook)
+| voipms\_jid\_map      | table  | nil     | JID -> DIDs mapping
 ```
 VirtualHost "sms.example.com"
 modules_enabled = {
     "voipms";
 }
-voipms_api_username = john@example.com -- E-mail registered with VoIP.ms
-voipms_api_password = abcd1234 -- API password configured in VoIP.ms
-voipms_query_key = some_query_key -- query param 'key' part of your URL callback
+voipms_api_username = john@example.com
+voipms_api_password = abcd1234
+voipms_query_key = some_query_key
 voipms_jid_map = {
-        ["your_jid@your_domain.com"] = "+1234567890"
+        ["your_jid@your_domain.com"] = { "+1234567890" },
+        ["your_jid2@your_domain.com"] = { "+0123456789", "+18573647583" }
 }
 ```
 
--- a/mod_voipms/mod_voipms.lua	Mon Jul 21 23:57:37 2025 +0200
+++ b/mod_voipms/mod_voipms.lua	Tue Jul 22 06:24:32 2025 +0200
@@ -13,6 +13,13 @@
     return
 end
 
+for jid, dids in pairs(jid_map) do
+    if type(dids) ~= "table" then
+        module:log("error", "Invalid voipms_jid_map entry for %s: must be a list of DIDs", jid)
+        return
+    end
+end
+
 module:depends("http")
 
 local function normalize_number(num)
@@ -59,14 +66,18 @@
                 return { status_code = 400 }
             end
 
+            local normalized_from = normalize_number(from)
             local normalized_to = normalize_number(to)
             local target_jid = nil
 
-            for jid, did in pairs(jid_map) do
-                if normalize_number(did) == normalized_to then
-                    target_jid = jid
-                    break
+            for jid, dids in pairs(jid_map) do
+                for _, did in ipairs(dids) do
+                    if normalize_number(did) == normalized_to then
+                        target_jid = jid
+                        break
+                    end
                 end
+                if target_jid then break end
             end
 
             if not target_jid then
@@ -74,28 +85,39 @@
                 return { status_code = 404 }
             end
 
-            local normalized_from = normalize_number(from)
             local message_text = payload.text or ""
+            local from_jid = normalized_from .. "%" .. normalized_to .. "@" .. module.host
 
-            local message = st.message({
-                from = normalized_from .. "@" .. module.host,
-                to = target_jid,
-                type = "chat"
-            }):tag("body"):text(message_text):up()
+            if message_text ~= "" then
+                local text_message = st.message({
+                    from = from_jid,
+                    to = target_jid,
+                    type = "chat"
+                }):tag("body"):text(message_text):up()
+
+                module:send(text_message)
+                module:log("info", "Delivered text SMS from %s to %s", normalized_from, target_jid)
+            end
 
             if payload.media and #payload.media > 0 then
                 for _, media_item in ipairs(payload.media) do
                     if media_item.url then
-                        message_text = message_text .. "\n" .. media_item.url
-                        message:tag("x", { xmlns = "jabber:x:oob" })
-                               :tag("url"):text(media_item.url):up():up()
+                        local media_message = st.message({
+                            from = from_jid,
+                            to = target_jid,
+                            type = "chat"
+                        })
+                        :tag("body"):text(media_item.url):up()
+                        :tag("x", { xmlns = "jabber:x:oob" })
+                            :tag("url"):text(media_item.url):up()
+                        :up()
+
+                        module:send(media_message)
+                        module:log("info", "Delivered media URL from %s to %s: %s", normalized_from, target_jid, media_item.url)
                     end
                 end
             end
 
-            module:send(message)
-            module:log("info", "Delivered SMS from %s to %s", normalized_from, target_jid)
-
             return { status_code = 204 }
         end
     }
@@ -110,19 +132,20 @@
     local body = stanza:get_child_text("body")
     if not body or body == "" then return end
 
-    local from_number = jid_map[from_jid]
-    if not from_number then
-        module:log("warn", "No DID mapping for JID %s", from_jid)
-        return
-    end
-
-    local to_number = to_jid:match("^([^@]+)")
-    if not to_number then
+    local to_node = to_jid:match("^(.-)@")
+    if not to_node then
         module:log("warn", "Malformed JID in message.to: %s", to_jid)
         return
     end
 
-    to_number = normalize_number(to_number)
+    local dst_number, from_number = to_node:match("([^%%]+)%%(.+)")
+    if not dst_number or not from_number then
+        module:log("warn", "Malformed to JID node: %s", to_node)
+        return
+    end
+
+    dst_number = normalize_number(dst_number)
+    from_number = normalize_number(from_number)
 
     local media_urls = {}
     for line in body:gmatch("[^\r\n]+") do
@@ -137,7 +160,7 @@
         api_password = api_password,
         method = method,
         did = from_number,
-        dst = to_number,
+        dst = dst_number,
         message = body
     }
 
@@ -157,7 +180,7 @@
             if not resp or resp.status ~= "success" then
                 module:log("error", "Failed to send %s: %s", method, err or (resp and resp.status) or "unknown")
             else
-                module:log("info", "Sent %s from %s to %s", method, from_number, to_number)
+                module:log("info", "Sent %s from %s to %s", method, from_number, dst_number)
             end
         else
             module:log("error", "HTTP error sending %s: code %s", method, tostring(code))