luat_lib_sms.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /*
  2. @module sms
  3. @summary 短信
  4. @version 1.0
  5. @date 2022.12.08
  6. @demo sms
  7. @tag LUAT_USE_SMS
  8. @usage
  9. -- 注意, Air780E/Air600E/Air780EG/Air780EG均不支持电信卡的短信!!
  10. -- 意思是, 当上述模块搭配电信SIM卡, 无法从模块发出短信, 也无法在模块接收短信
  11. -- 如果是联通卡或者移动卡, 均可收取短信, 但实名制的卡才能发送短信
  12. */
  13. #include "luat_base.h"
  14. #include "luat_msgbus.h"
  15. #include "luat_mem.h"
  16. #include "luat_mobile.h"
  17. #include "luat_timer.h"
  18. void luat_str_fromhex(char* str, size_t len, char* buff) ;
  19. #ifndef bool
  20. #define bool uint8_t
  21. #endif
  22. #include "luat_sms.h"
  23. #define LUAT_LOG_TAG "sms"
  24. #include "luat_log.h"
  25. static int lua_sms_ref = 0;
  26. static int lua_sms_recv_long = 1;
  27. typedef struct long_sms
  28. {
  29. uint8_t refNum;
  30. uint8_t maxNum;
  31. uint8_t seqNum;
  32. char buff[1];
  33. }long_sms_t;
  34. #define LONG_SMS_CMAX (128)
  35. static long_sms_t* lngbuffs[LONG_SMS_CMAX];
  36. // static char* longsms = NULL;
  37. // static int longsms_refNum = -1;
  38. static void ucs2char(char* source, size_t size, char* dst2, size_t* outlen) {
  39. char buff[size + 2];
  40. memset(buff, 0, size + 2);
  41. luat_str_fromhex(source, size, buff);
  42. //LLOGD("sms %s", source);
  43. uint16_t* tmp = (uint16_t*)buff;
  44. char* dst = dst2;
  45. // size_t tmplen = origin_len / 2;
  46. // size_t dstoff = 0;
  47. uint16_t unicode = 0;
  48. size_t dstlen = 0;
  49. while (1) {
  50. unicode = *tmp ++;
  51. unicode = ((unicode >> 8) & 0xFF) + ((unicode & 0xFF) << 8);
  52. //LLOGD("unicode %04X", unicode);
  53. if (unicode == 0)
  54. break; // 终止了
  55. if (unicode <= 0x0000007F) {
  56. dst[dstlen++] = (unicode & 0x7F);
  57. continue;
  58. }
  59. if (unicode <= 0x000007FF) {
  60. dst[dstlen++] = ((unicode >> 6) & 0x1F) | 0xC0;
  61. dst[dstlen++] = (unicode & 0x3F) | 0x80;
  62. continue;
  63. }
  64. if (unicode <= 0x0000FFFF) {
  65. dst[dstlen++] = ((unicode >> 12) & 0x0F) | 0xE0;
  66. dst[dstlen++] = ((unicode >> 6) & 0x3F) | 0x80;
  67. dst[dstlen++] = (unicode & 0x3F) | 0x80;
  68. //LLOGD("why? %02X %02X %02X", ((unicode >> 12) & 0x0F) | 0xE0, ((unicode >> 6) & 0x3F) | 0x80, (unicode & 0x3F) | 0x80);
  69. continue;
  70. }
  71. break;
  72. }
  73. *outlen = dstlen;
  74. //LLOGD("ucs2char %d", dstlen);
  75. }
  76. static void push_sms_args(lua_State* L, LUAT_SMS_RECV_MSG_T* sms, char* dst, size_t dstlen) {
  77. char phone[strlen(sms->phone_address) * 3 + 1];
  78. memset(phone, 0, strlen(sms->phone_address) * 3 + 1);
  79. size_t outlen = 0;
  80. memcpy(phone, sms->phone_address, strlen(sms->phone_address));
  81. if (strlen(phone) > 4 && phone[0] == '0' && phone[1] == '0' && strlen(phone) % 2 == 0) {
  82. // 看来是ucs编码了
  83. ucs2char(sms->phone_address, strlen(sms->phone_address), phone, &outlen);
  84. phone[outlen] = 0x00;
  85. }
  86. lua_pushstring(L, phone);
  87. if (dst == NULL) {
  88. luaL_Buffer buff;
  89. luaL_buffinit(L, &buff);
  90. for (size_t j = 0; j < sms->maxNum; j++)
  91. {
  92. for (size_t i = 0; i < LONG_SMS_CMAX; i++)
  93. {
  94. if (lngbuffs[i] && lngbuffs[i]->refNum == dstlen && lngbuffs[i]->seqNum == j + 1) {
  95. luaL_addstring(&buff, lngbuffs[i]->buff);
  96. }
  97. }
  98. }
  99. luaL_pushresult(&buff);
  100. }
  101. else {
  102. lua_pushlstring(L, dst, dstlen);
  103. }
  104. // 添加元数据
  105. lua_newtable(L);
  106. // 长短信总数
  107. lua_pushinteger(L, sms->refNum);
  108. lua_setfield(L, -2, "refNum");
  109. // 当前序号
  110. lua_pushinteger(L, sms->seqNum);
  111. lua_setfield(L, -2, "seqNum");
  112. // 当前序号
  113. lua_pushinteger(L, sms->maxNum);
  114. lua_setfield(L, -2, "maxNum");
  115. // 时间信息
  116. lua_pushinteger(L, sms->time.year);
  117. lua_setfield(L, -2, "year");
  118. lua_pushinteger(L, sms->time.month);
  119. lua_setfield(L, -2, "mon");
  120. lua_pushinteger(L, sms->time.day);
  121. lua_setfield(L, -2, "day");
  122. lua_pushinteger(L, sms->time.hour);
  123. lua_setfield(L, -2, "hour");
  124. lua_pushinteger(L, sms->time.minute);
  125. lua_setfield(L, -2, "min");
  126. lua_pushinteger(L, sms->time.second);
  127. lua_setfield(L, -2, "sec");
  128. lua_pushinteger(L, sms->time.tz_sign == '+' ? sms->time.tz : - sms->time.tz);
  129. lua_setfield(L, -2, "tz");
  130. }
  131. static int l_sms_recv_handler(lua_State* L, void* ptr) {
  132. LUAT_SMS_RECV_MSG_T* sms = ((LUAT_SMS_RECV_MSG_T*)ptr);
  133. // char buff[280+2] = {0};
  134. size_t dstlen = strlen(sms->sms_buffer);
  135. char tmpbuff[140*3+2] = {0};
  136. char *dst = tmpbuff;
  137. LLOGD("dcs %d | %d | %d | %d", sms->dcs_info.alpha_bet, sms->dcs_info.dcs, sms->dcs_info.msg_class, sms->dcs_info.type);
  138. if (sms->dcs_info.alpha_bet == 0) {
  139. memcpy(dst, sms->sms_buffer, strlen(sms->sms_buffer));
  140. }
  141. else {
  142. ucs2char(sms->sms_buffer, strlen(sms->sms_buffer), dst, &dstlen);
  143. dst[dstlen] = 0;
  144. }
  145. if (sms->maxNum > 0 && lua_sms_recv_long) {
  146. int index = -1;
  147. for (size_t i = 0; i < LONG_SMS_CMAX; i++)
  148. {
  149. if (lngbuffs[i] == NULL) {
  150. index = i;
  151. break;
  152. }
  153. }
  154. if (index < 0) {
  155. LLOGE("too many long-sms!!");
  156. goto exit;
  157. }
  158. lngbuffs[index] = luat_heap_malloc(sizeof(long_sms_t) + dstlen);
  159. if (lngbuffs[index] == NULL) {
  160. LLOGE("out of memory when malloc long sms buff");
  161. goto exit;
  162. }
  163. lngbuffs[index]->maxNum = sms->maxNum;
  164. lngbuffs[index]->seqNum = sms->seqNum;
  165. lngbuffs[index]->refNum = sms->refNum;
  166. memcpy(lngbuffs[index]->buff, dst, dstlen);
  167. lngbuffs[index]->buff[dstlen] = 0x00;
  168. size_t counter = (sms->maxNum + 1) * sms->maxNum / 2;
  169. for (size_t i = 0; i < LONG_SMS_CMAX; i++)
  170. {
  171. if (lngbuffs[i] == NULL || lngbuffs[i]->refNum != sms->refNum) {
  172. continue;
  173. }
  174. counter -= lngbuffs[i]->seqNum;
  175. }
  176. if (counter != 0) {
  177. LLOGI("long-sms, wait more frags %d/%d", sms->seqNum, sms->maxNum);
  178. goto exit;
  179. }
  180. LLOGI("long-sms is ok");
  181. dst = NULL;
  182. dstlen = sms->refNum;
  183. }
  184. // 先发系统消息
  185. lua_getglobal(L, "sys_pub");
  186. if (lua_isnil(L, -1)) {
  187. luat_heap_free(sms);
  188. return 0;
  189. }
  190. /*
  191. @sys_pub sms
  192. 收到短信
  193. SMS_INC
  194. @string 手机号
  195. @string 短信内容,UTF8编码
  196. @usage
  197. --使用的例子,可多行
  198. -- 接收短信, 支持多种方式, 选一种就可以了
  199. -- 1. 设置回调函数
  200. --sms.setNewSmsCb( function(phone,sms)
  201. log.info("sms",phone,sms)
  202. end)
  203. -- 2. 订阅系统消息
  204. --sys.subscribe("SMS_INC", function(phone,sms)
  205. log.info("sms",phone,sms)
  206. end)
  207. */
  208. lua_pushliteral(L, "SMS_INC");
  209. push_sms_args(L, sms, dst, dstlen);
  210. lua_call(L, 4, 0);
  211. // 如果有回调函数, 就调用
  212. if (lua_sms_ref) {
  213. lua_geti(L, LUA_REGISTRYINDEX, lua_sms_ref);
  214. if (lua_isfunction(L, -1)) {
  215. push_sms_args(L, sms, dst, dstlen);
  216. lua_call(L, 3, 0);
  217. }
  218. }
  219. // 清理长短信的缓冲,如果有的话
  220. for (size_t i = 0; i < 16; i++)
  221. {
  222. if (lngbuffs[i] && lngbuffs[i]->refNum == sms->refNum) {
  223. luat_heap_free(lngbuffs[i]);
  224. lngbuffs[i] = NULL;
  225. }
  226. }
  227. exit:
  228. luat_heap_free(sms);
  229. return 0;
  230. }
  231. void luat_sms_recv_cb(uint32_t event, void *param)
  232. {
  233. LUAT_SMS_RECV_MSG_T* sms = ((LUAT_SMS_RECV_MSG_T*)param);
  234. rtos_msg_t msg = {0};
  235. if (event != 0) {
  236. return;
  237. }
  238. LUAT_SMS_RECV_MSG_T* tmp = luat_heap_malloc(sizeof(LUAT_SMS_RECV_MSG_T));
  239. if (tmp == NULL) {
  240. LLOGE("out of memory when malloc sms content");
  241. return;
  242. }
  243. memcpy(tmp, sms, sizeof(LUAT_SMS_RECV_MSG_T));
  244. msg.handler = l_sms_recv_handler;
  245. msg.ptr = tmp;
  246. luat_msgbus_put(&msg, 0);
  247. }
  248. /*
  249. 发送短信
  250. @api sms.send(phone, msg, auto_phone_fix)
  251. @string 电话号码,必填
  252. @string 短信内容,必填
  253. @bool 是否自动处理电话号号码的格式,默认是按短信内容和号码格式进行自动判断, 设置为false可禁用
  254. @return bool 成功返回true,否则返回false或nil
  255. @usgae
  256. -- 短信号码支持2种形式
  257. -- +XXYYYYYYY 其中XX代表国家代码, 中国是86, 推荐使用这种
  258. -- YYYYYYYYY 直接填目标号码, 例如10010, 10086, 或者国内的手机号码
  259. log.info("sms", sms.send("+8613416121234", "Hi, LuatOS - " .. os.date()))
  260. -- 直接使用目标号码, 不做任何自动化处理. 2023.09.21新增
  261. log.info("sms", sms.send("85513416121234", "Hi, LuatOS - " .. os.date()), false)
  262. */
  263. static int l_sms_send(lua_State *L) {
  264. size_t phone_len = 0;
  265. size_t payload_len = 0;
  266. const char* phone = luaL_checklstring(L, 1, &phone_len);
  267. const char* payload = luaL_checklstring(L, 2, &payload_len);
  268. int auto_phone = 1;
  269. if (lua_isboolean(L, 3) && !lua_toboolean(L, 3)) {
  270. auto_phone = 0;
  271. }
  272. int ret = 0;
  273. char phone_buff[32] = {0};
  274. if (payload_len == 0) {
  275. LLOGI("sms is emtry");
  276. return 0;
  277. }
  278. if (payload_len >= 140) {
  279. LLOGE("sms is too long %d > 140", payload_len);
  280. return 0;
  281. }
  282. int pdu_mode = 0;
  283. for (size_t i = 0; i < payload_len; i++)
  284. {
  285. if (payload[i] & 0x80) {
  286. LLOGD("found non-ASCII char, using PDU mode");
  287. pdu_mode = 1;
  288. break;
  289. }
  290. }
  291. if (phone_len < 3 || phone_len > 29) {
  292. LLOGI("phone is too short or too long!! %d", phone_len);
  293. return 0;
  294. }
  295. uint8_t gateway_mode = 0; //短信网关特殊处理
  296. if ((phone_len >= 15) && !memcmp(phone, "10", 2)) {
  297. LLOGI("sms gateway mode");
  298. gateway_mode = 1;
  299. pdu_mode = 1;
  300. memcpy(phone_buff, phone, phone_len);
  301. goto NUMBER_CHECK_DONE;
  302. }
  303. // +8613416121234
  304. if (auto_phone) {
  305. if (pdu_mode) { // PDU模式下, 必须带上国家代码
  306. if (phone[0] == '+') {
  307. memcpy(phone_buff, phone + 1, phone_len - 1);
  308. }
  309. // 13416121234
  310. else if (phone[0] != '8' && phone[1] != '6') {
  311. phone_buff[0] = '8';
  312. phone_buff[1] = '6';
  313. memcpy(phone_buff + 2, phone, phone_len);
  314. }
  315. else {
  316. memcpy(phone_buff, phone, phone_len);
  317. }
  318. }
  319. else {
  320. if (phone[0] == '+') {
  321. memcpy(phone_buff, phone + 3, phone_len - 3);
  322. }
  323. else if (phone[0] == '8' && phone[1] == '6') {
  324. memcpy(phone_buff, phone+2, phone_len - 2);
  325. }
  326. else {
  327. memcpy(phone_buff, phone, phone_len);
  328. }
  329. }
  330. }
  331. else {
  332. memcpy(phone_buff, phone, phone_len);
  333. }
  334. NUMBER_CHECK_DONE:
  335. phone_len = strlen(phone_buff);
  336. phone = phone_buff;
  337. LLOGD("phone [%s]", phone);
  338. if (pdu_mode) {
  339. char pdu[280 + 100] = {0};
  340. // 首先, 填充PDU头部
  341. strcat(pdu, "00"); // 使用内置短信中心,暂时不可设置
  342. strcat(pdu, "01"); // 仅收件信息, 不传保留时间
  343. strcat(pdu, "00"); // TP-MR, 固定填0
  344. sprintf_(pdu + strlen(pdu), "%02X", phone_len); // 电话号码长度
  345. if (gateway_mode) {
  346. strcat(pdu, "81"); // 目标地址格式
  347. } else {
  348. strcat(pdu, "91"); // 目标地址格式
  349. }
  350. // 手机方号码
  351. for (size_t i = 0; i < phone_len; i+=2)
  352. {
  353. if (i == (phone_len - 1) && phone_len % 2 != 0) {
  354. pdu[strlen(pdu)] = 'F';
  355. pdu[strlen(pdu)] = phone[i];
  356. }
  357. else {
  358. pdu[strlen(pdu)] = phone[i+1];
  359. pdu[strlen(pdu)] = phone[i];
  360. }
  361. }
  362. strcat(pdu, "00"); // 协议标识(TP-PID) 是普通GSM类型,点到点方式
  363. strcat(pdu, "08"); // 编码格式, UCS编码
  364. size_t pdu_len_offset = strlen(pdu);
  365. strcat(pdu, "00"); // 这是预留的, 填充数据会后更新成正确的值
  366. uint16_t unicode = 0;
  367. size_t pdu_userdata_len = 0;
  368. for (size_t i = 0; i < payload_len; i++)
  369. {
  370. // 首先是不是单字节
  371. if (payload[i] & 0x80) {
  372. // 非ASCII编码
  373. if (payload[i] && 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx
  374. unicode = ((payload[i] & 0x0F) << 12) + ((payload[i+1] & 0x3F) << 6) + (payload[i+2] & 0x3F);
  375. //LLOGD("unicode %04X %02X%02X%02X", unicode, payload[i], payload[i+1], payload[i+2]);
  376. sprintf_(pdu + strlen(pdu), "%02X%02X", (unicode >> 8) & 0xFF, unicode & 0xFF);
  377. i+=2;
  378. pdu_userdata_len += 2;
  379. continue;
  380. }
  381. if (payload[i] & 0xC0) { // 110xxxxx 10xxxxxx
  382. unicode = ((payload[i] & 0x1F) << 6) + (payload[i+1] & 0x3F);
  383. //LLOGD("unicode %04X %02X%02X", unicode, payload[i], payload[i+1]);
  384. sprintf_(pdu + strlen(pdu), "%02X%02X", (unicode >> 8) & 0xFF, unicode & 0xFF);
  385. i++;
  386. pdu_userdata_len += 2;
  387. continue;
  388. }
  389. LLOGD("bad UTF8 string");
  390. break;
  391. }
  392. // 单个ASCII字符, 但需要扩展到2位
  393. else {
  394. // ASCII编码
  395. strcat(pdu, "00");
  396. sprintf_(pdu + strlen(pdu), "%02X", payload[i]);
  397. pdu_userdata_len += 2;
  398. continue;
  399. }
  400. }
  401. if (pdu_userdata_len > 140) {
  402. LLOGI("sms is too long %d", pdu_userdata_len);
  403. return 0;
  404. }
  405. // 修正pdu长度
  406. char tmp[3] = {0};
  407. sprintf_(tmp, "%02X", pdu_userdata_len);
  408. memcpy(pdu + pdu_len_offset, tmp, 2);
  409. // 打印PDU数据, 调试用
  410. LLOGD("PDU %s", pdu);
  411. payload = pdu;
  412. payload_len = strlen(pdu);
  413. phone = "";
  414. ret = luat_sms_send_msg(pdu, "", 1, 54);
  415. lua_pushboolean(L, ret == 0 ? 1 : 0);
  416. }
  417. else {
  418. ret = luat_sms_send_msg(payload, phone, 0, 0);
  419. lua_pushboolean(L, ret == 0 ? 1 : 0);
  420. }
  421. LLOGD("sms ret %d", ret);
  422. return 1;
  423. }
  424. /**
  425. 设置新SMS的回调函数
  426. @api sms.setNewSmsCb(func)
  427. @function 回调函数, 3个参数, num, txt, metas
  428. @return nil 传入是函数就能成功,无返回值
  429. @usage
  430. sms.setNewSmsCb(function(num, txt, metas)
  431. -- num 手机号码
  432. -- txt 文本内容
  433. -- metas 短信的元数据,例如发送的时间,长短信编号
  434. -- 注意, 长短信会自动合并成一条txt
  435. log.info("sms", num, txt, metas and json.encode(metas) or "")
  436. end)
  437. */
  438. static int l_sms_cb(lua_State *L) {
  439. if (lua_sms_ref) {
  440. luaL_unref(L, LUA_REGISTRYINDEX, lua_sms_ref);
  441. lua_sms_ref = 0;
  442. }
  443. if (lua_isfunction(L, 1)) {
  444. lua_sms_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  445. }
  446. return 0;
  447. }
  448. /**
  449. 设置长短信的自动合并功能
  450. @api sms.autoLong(mode)
  451. @bool 是否自动合并,true为自动合并,为默认值
  452. @return bool 设置后的值
  453. @usage
  454. -- 禁用长短信的自动合并, 一般不需要禁用
  455. sms.autoLong(false)
  456. */
  457. static int l_sms_auto_long(lua_State *L) {
  458. if (lua_isboolean(L, 1)) {
  459. lua_sms_recv_long = lua_toboolean(L, 1);
  460. }
  461. else if (lua_isinteger(L, 1))
  462. {
  463. lua_sms_recv_long = lua_toboolean(L, 1);
  464. }
  465. lua_pushboolean(L, lua_sms_recv_long == 0 ? 0 : 1);
  466. return 1;
  467. }
  468. /**
  469. 清除长短信缓存
  470. @api sms.clearLong()
  471. @return int 清理掉的片段数量
  472. @usage
  473. sms.clearLong()
  474. */
  475. static int l_sms_clear_long(lua_State *L) {
  476. int counter = 0;
  477. for (size_t i = 0; i < LONG_SMS_CMAX; i++)
  478. {
  479. if (lngbuffs[i]) {
  480. counter ++;
  481. luat_heap_free(lngbuffs[i]);
  482. lngbuffs[i] = NULL;
  483. }
  484. }
  485. lua_pushinteger(L, counter);
  486. return 1;
  487. }
  488. #include "rotable2.h"
  489. static const rotable_Reg_t reg_sms[] =
  490. {
  491. { "send", ROREG_FUNC(l_sms_send)},
  492. { "setNewSmsCb", ROREG_FUNC(l_sms_cb)},
  493. { "autoLong", ROREG_FUNC(l_sms_auto_long)},
  494. { "clearLong", ROREG_FUNC(l_sms_clear_long)},
  495. { NULL, ROREG_INT(0)}
  496. };
  497. LUAMOD_API int luaopen_sms( lua_State *L ) {
  498. luat_newlib2(L, reg_sms);
  499. return 1;
  500. }