Mercurial > prosody-modules
comparison mod_voipms/mod_voipms.lua @ 6300:8689f49d21ef
mod_voipms: Updates
| author | Menel <menel@snikket.de> |
|---|---|
| date | Tue, 22 Jul 2025 06:24:32 +0200 |
| parents | 5cf5ee23b361 |
| children | c194bec4b56d |
comparison
equal
deleted
inserted
replaced
| 6299:5cf5ee23b361 | 6300:8689f49d21ef |
|---|---|
| 9 local rest_endpoint = "https://voip.ms/api/v1/rest.php" | 9 local rest_endpoint = "https://voip.ms/api/v1/rest.php" |
| 10 | 10 |
| 11 if not api_username or not api_password or not query_key then | 11 if not api_username or not api_password or not query_key then |
| 12 module:log("error", "Missing required config values (voipms_api_username, voipms_api_password, voipms_query_key)") | 12 module:log("error", "Missing required config values (voipms_api_username, voipms_api_password, voipms_query_key)") |
| 13 return | 13 return |
| 14 end | |
| 15 | |
| 16 for jid, dids in pairs(jid_map) do | |
| 17 if type(dids) ~= "table" then | |
| 18 module:log("error", "Invalid voipms_jid_map entry for %s: must be a list of DIDs", jid) | |
| 19 return | |
| 20 end | |
| 14 end | 21 end |
| 15 | 22 |
| 16 module:depends("http") | 23 module:depends("http") |
| 17 | 24 |
| 18 local function normalize_number(num) | 25 local function normalize_number(num) |
| 57 if not from or not to then | 64 if not from or not to then |
| 58 module:log("warn", "Missing phone numbers (from: %s, to: %s)", tostring(from), tostring(to)) | 65 module:log("warn", "Missing phone numbers (from: %s, to: %s)", tostring(from), tostring(to)) |
| 59 return { status_code = 400 } | 66 return { status_code = 400 } |
| 60 end | 67 end |
| 61 | 68 |
| 69 local normalized_from = normalize_number(from) | |
| 62 local normalized_to = normalize_number(to) | 70 local normalized_to = normalize_number(to) |
| 63 local target_jid = nil | 71 local target_jid = nil |
| 64 | 72 |
| 65 for jid, did in pairs(jid_map) do | 73 for jid, dids in pairs(jid_map) do |
| 66 if normalize_number(did) == normalized_to then | 74 for _, did in ipairs(dids) do |
| 67 target_jid = jid | 75 if normalize_number(did) == normalized_to then |
| 68 break | 76 target_jid = jid |
| 77 break | |
| 78 end | |
| 69 end | 79 end |
| 80 if target_jid then break end | |
| 70 end | 81 end |
| 71 | 82 |
| 72 if not target_jid then | 83 if not target_jid then |
| 73 module:log("warn", "No JID mapping for DID %s", normalized_to) | 84 module:log("warn", "No JID mapping for DID %s", normalized_to) |
| 74 return { status_code = 404 } | 85 return { status_code = 404 } |
| 75 end | 86 end |
| 76 | 87 |
| 77 local normalized_from = normalize_number(from) | |
| 78 local message_text = payload.text or "" | 88 local message_text = payload.text or "" |
| 89 local from_jid = normalized_from .. "%" .. normalized_to .. "@" .. module.host | |
| 79 | 90 |
| 80 local message = st.message({ | 91 if message_text ~= "" then |
| 81 from = normalized_from .. "@" .. module.host, | 92 local text_message = st.message({ |
| 82 to = target_jid, | 93 from = from_jid, |
| 83 type = "chat" | 94 to = target_jid, |
| 84 }):tag("body"):text(message_text):up() | 95 type = "chat" |
| 96 }):tag("body"):text(message_text):up() | |
| 97 | |
| 98 module:send(text_message) | |
| 99 module:log("info", "Delivered text SMS from %s to %s", normalized_from, target_jid) | |
| 100 end | |
| 85 | 101 |
| 86 if payload.media and #payload.media > 0 then | 102 if payload.media and #payload.media > 0 then |
| 87 for _, media_item in ipairs(payload.media) do | 103 for _, media_item in ipairs(payload.media) do |
| 88 if media_item.url then | 104 if media_item.url then |
| 89 message_text = message_text .. "\n" .. media_item.url | 105 local media_message = st.message({ |
| 90 message:tag("x", { xmlns = "jabber:x:oob" }) | 106 from = from_jid, |
| 91 :tag("url"):text(media_item.url):up():up() | 107 to = target_jid, |
| 108 type = "chat" | |
| 109 }) | |
| 110 :tag("body"):text(media_item.url):up() | |
| 111 :tag("x", { xmlns = "jabber:x:oob" }) | |
| 112 :tag("url"):text(media_item.url):up() | |
| 113 :up() | |
| 114 | |
| 115 module:send(media_message) | |
| 116 module:log("info", "Delivered media URL from %s to %s: %s", normalized_from, target_jid, media_item.url) | |
| 92 end | 117 end |
| 93 end | 118 end |
| 94 end | 119 end |
| 95 | |
| 96 module:send(message) | |
| 97 module:log("info", "Delivered SMS from %s to %s", normalized_from, target_jid) | |
| 98 | 120 |
| 99 return { status_code = 204 } | 121 return { status_code = 204 } |
| 100 end | 122 end |
| 101 } | 123 } |
| 102 }) | 124 }) |
| 108 local from_jid = stanza.attr.from | 130 local from_jid = stanza.attr.from |
| 109 local to_jid = stanza.attr.to | 131 local to_jid = stanza.attr.to |
| 110 local body = stanza:get_child_text("body") | 132 local body = stanza:get_child_text("body") |
| 111 if not body or body == "" then return end | 133 if not body or body == "" then return end |
| 112 | 134 |
| 113 local from_number = jid_map[from_jid] | 135 local to_node = to_jid:match("^(.-)@") |
| 114 if not from_number then | 136 if not to_node then |
| 115 module:log("warn", "No DID mapping for JID %s", from_jid) | |
| 116 return | |
| 117 end | |
| 118 | |
| 119 local to_number = to_jid:match("^([^@]+)") | |
| 120 if not to_number then | |
| 121 module:log("warn", "Malformed JID in message.to: %s", to_jid) | 137 module:log("warn", "Malformed JID in message.to: %s", to_jid) |
| 122 return | 138 return |
| 123 end | 139 end |
| 124 | 140 |
| 125 to_number = normalize_number(to_number) | 141 local dst_number, from_number = to_node:match("([^%%]+)%%(.+)") |
| 142 if not dst_number or not from_number then | |
| 143 module:log("warn", "Malformed to JID node: %s", to_node) | |
| 144 return | |
| 145 end | |
| 146 | |
| 147 dst_number = normalize_number(dst_number) | |
| 148 from_number = normalize_number(from_number) | |
| 126 | 149 |
| 127 local media_urls = {} | 150 local media_urls = {} |
| 128 for line in body:gmatch("[^\r\n]+") do | 151 for line in body:gmatch("[^\r\n]+") do |
| 129 if line:match("^https?://") then | 152 if line:match("^https?://") then |
| 130 table.insert(media_urls, line) | 153 table.insert(media_urls, line) |
| 135 local query = { | 158 local query = { |
| 136 api_username = api_username, | 159 api_username = api_username, |
| 137 api_password = api_password, | 160 api_password = api_password, |
| 138 method = method, | 161 method = method, |
| 139 did = from_number, | 162 did = from_number, |
| 140 dst = to_number, | 163 dst = dst_number, |
| 141 message = body | 164 message = body |
| 142 } | 165 } |
| 143 | 166 |
| 144 if method == "sendMMS" then | 167 if method == "sendMMS" then |
| 145 for i, url in ipairs(media_urls) do | 168 for i, url in ipairs(media_urls) do |
| 155 if code == 200 then | 178 if code == 200 then |
| 156 local resp, err = json.decode(response_body) | 179 local resp, err = json.decode(response_body) |
| 157 if not resp or resp.status ~= "success" then | 180 if not resp or resp.status ~= "success" then |
| 158 module:log("error", "Failed to send %s: %s", method, err or (resp and resp.status) or "unknown") | 181 module:log("error", "Failed to send %s: %s", method, err or (resp and resp.status) or "unknown") |
| 159 else | 182 else |
| 160 module:log("info", "Sent %s from %s to %s", method, from_number, to_number) | 183 module:log("info", "Sent %s from %s to %s", method, from_number, dst_number) |
| 161 end | 184 end |
| 162 else | 185 else |
| 163 module:log("error", "HTTP error sending %s: code %s", method, tostring(code)) | 186 module:log("error", "HTTP error sending %s: code %s", method, tostring(code)) |
| 164 end | 187 end |
| 165 end) | 188 end) |
