luat_lib_sms.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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. int pdu_mode = 0;
  279. for (size_t i = 0; i < payload_len; i++)
  280. {
  281. if (payload[i] & 0x80) {
  282. LLOGD("found non-ASCII char, using PDU mode");
  283. pdu_mode = 1;
  284. break;
  285. }
  286. }
  287. if (phone_len < 3 || phone_len > 29) {
  288. LLOGI("phone is too short or too long!! %d", phone_len);
  289. return 0;
  290. }
  291. uint8_t gateway_mode = 0; //短信网关特殊处理
  292. if ((phone_len >= 15) && !memcmp(phone, "10", 2)) {
  293. LLOGI("sms gateway mode");
  294. gateway_mode = 1;
  295. pdu_mode = 1;
  296. memcpy(phone_buff, phone, phone_len);
  297. goto NUMBER_CHECK_DONE;
  298. }
  299. // +8613416121234
  300. if (auto_phone) {
  301. if (pdu_mode) { // PDU模式下, 必须带上国家代码
  302. if (phone[0] == '+') {
  303. memcpy(phone_buff, phone + 1, phone_len - 1);
  304. }
  305. // 13416121234
  306. else if (phone[0] != '8' && phone[1] != '6') {
  307. phone_buff[0] = '8';
  308. phone_buff[1] = '6';
  309. memcpy(phone_buff + 2, phone, phone_len);
  310. }
  311. else {
  312. memcpy(phone_buff, phone, phone_len);
  313. }
  314. }
  315. else {
  316. if (phone[0] == '+') {
  317. memcpy(phone_buff, phone + 3, phone_len - 3);
  318. }
  319. else if (phone[0] == '8' && phone[1] == '6') {
  320. memcpy(phone_buff, phone+2, phone_len - 2);
  321. }
  322. else {
  323. memcpy(phone_buff, phone, phone_len);
  324. }
  325. }
  326. }
  327. else {
  328. memcpy(phone_buff, phone, phone_len);
  329. }
  330. NUMBER_CHECK_DONE:
  331. phone_len = strlen(phone_buff);
  332. phone = phone_buff;
  333. LLOGD("phone [%s]", phone);
  334. if (pdu_mode) {
  335. char pdu[280 + 100] = {0};
  336. // 首先, 填充PDU头部
  337. strcat(pdu, "00"); // 使用内置短信中心,暂时不可设置
  338. strcat(pdu, "01"); // 仅收件信息, 不传保留时间
  339. strcat(pdu, "00"); // TP-MR, 固定填0
  340. sprintf_(pdu + strlen(pdu), "%02X", phone_len); // 电话号码长度
  341. if (gateway_mode) {
  342. strcat(pdu, "81"); // 目标地址格式
  343. } else {
  344. strcat(pdu, "91"); // 目标地址格式
  345. }
  346. // 手机方号码
  347. for (size_t i = 0; i < phone_len; i+=2)
  348. {
  349. if (i == (phone_len - 1) && phone_len % 2 != 0) {
  350. pdu[strlen(pdu)] = 'F';
  351. pdu[strlen(pdu)] = phone[i];
  352. }
  353. else {
  354. pdu[strlen(pdu)] = phone[i+1];
  355. pdu[strlen(pdu)] = phone[i];
  356. }
  357. }
  358. strcat(pdu, "00"); // 协议标识(TP-PID) 是普通GSM类型,点到点方式
  359. strcat(pdu, "08"); // 编码格式, UCS编码
  360. size_t pdu_len_offset = strlen(pdu);
  361. strcat(pdu, "00"); // 这是预留的, 填充数据会后更新成正确的值
  362. uint16_t unicode = 0;
  363. size_t pdu_userdata_len = 0;
  364. for (size_t i = 0; i < payload_len; i++)
  365. {
  366. // 首先是不是单字节
  367. if (payload[i] & 0x80) {
  368. // 非ASCII编码
  369. if (payload[i] && 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx
  370. unicode = ((payload[i] & 0x0F) << 12) + ((payload[i+1] & 0x3F) << 6) + (payload[i+2] & 0x3F);
  371. //LLOGD("unicode %04X %02X%02X%02X", unicode, payload[i], payload[i+1], payload[i+2]);
  372. sprintf_(pdu + strlen(pdu), "%02X%02X", (unicode >> 8) & 0xFF, unicode & 0xFF);
  373. i+=2;
  374. pdu_userdata_len += 2;
  375. continue;
  376. }
  377. if (payload[i] & 0xC0) { // 110xxxxx 10xxxxxx
  378. unicode = ((payload[i] & 0x1F) << 6) + (payload[i+1] & 0x3F);
  379. //LLOGD("unicode %04X %02X%02X", unicode, payload[i], payload[i+1]);
  380. sprintf_(pdu + strlen(pdu), "%02X%02X", (unicode >> 8) & 0xFF, unicode & 0xFF);
  381. i++;
  382. pdu_userdata_len += 2;
  383. continue;
  384. }
  385. LLOGD("bad UTF8 string");
  386. break;
  387. }
  388. // 单个ASCII字符, 但需要扩展到2位
  389. else {
  390. // ASCII编码
  391. strcat(pdu, "00");
  392. sprintf_(pdu + strlen(pdu), "%02X", payload[i]);
  393. pdu_userdata_len += 2;
  394. continue;
  395. }
  396. }
  397. if (pdu_userdata_len > 140) {
  398. LLOGI("sms is too long %d", pdu_userdata_len);
  399. return 0;
  400. }
  401. // 修正pdu长度
  402. char tmp[3] = {0};
  403. sprintf_(tmp, "%02X", pdu_userdata_len);
  404. memcpy(pdu + pdu_len_offset, tmp, 2);
  405. // 打印PDU数据, 调试用
  406. LLOGD("PDU %s", pdu);
  407. payload = pdu;
  408. payload_len = strlen(pdu);
  409. phone = "";
  410. ret = luat_sms_send_msg(pdu, "", 1, 54);
  411. lua_pushboolean(L, ret == 0 ? 1 : 0);
  412. }
  413. else {
  414. ret = luat_sms_send_msg(payload, phone, 0, 0);
  415. lua_pushboolean(L, ret == 0 ? 1 : 0);
  416. }
  417. LLOGD("sms ret %d", ret);
  418. return 1;
  419. }
  420. /**
  421. 设置新SMS的回调函数
  422. @api sms.setNewSmsCb(func)
  423. @function 回调函数, 3个参数, num, txt, metas
  424. @return nil 传入是函数就能成功,无返回值
  425. @usage
  426. sms.setNewSmsCb(function(num, txt, metas)
  427. -- num 手机号码
  428. -- txt 文本内容
  429. -- metas 短信的元数据,例如发送的时间,长短信编号
  430. -- 注意, 长短信会自动合并成一条txt
  431. log.info("sms", num, txt, metas and json.encode(metas) or "")
  432. end)
  433. */
  434. static int l_sms_cb(lua_State *L) {
  435. if (lua_sms_ref) {
  436. luaL_unref(L, LUA_REGISTRYINDEX, lua_sms_ref);
  437. lua_sms_ref = 0;
  438. }
  439. if (lua_isfunction(L, 1)) {
  440. lua_sms_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  441. }
  442. return 0;
  443. }
  444. /**
  445. 设置长短信的自动合并功能
  446. @api sms.autoLong(mode)
  447. @bool 是否自动合并,true为自动合并,为默认值
  448. @return bool 设置后的值
  449. @usage
  450. -- 禁用长短信的自动合并, 一般不需要禁用
  451. sms.autoLong(false)
  452. */
  453. static int l_sms_auto_long(lua_State *L) {
  454. if (lua_isboolean(L, 1)) {
  455. lua_sms_recv_long = lua_toboolean(L, 1);
  456. }
  457. else if (lua_isinteger(L, 1))
  458. {
  459. lua_sms_recv_long = lua_toboolean(L, 1);
  460. }
  461. lua_pushboolean(L, lua_sms_recv_long == 0 ? 0 : 1);
  462. return 1;
  463. }
  464. /**
  465. 清除长短信缓存
  466. @api sms.clearLong()
  467. @return int 清理掉的片段数量
  468. @usage
  469. sms.clearLong()
  470. */
  471. static int l_sms_clear_long(lua_State *L) {
  472. int counter = 0;
  473. for (size_t i = 0; i < LONG_SMS_CMAX; i++)
  474. {
  475. if (lngbuffs[i]) {
  476. counter ++;
  477. luat_heap_free(lngbuffs[i]);
  478. lngbuffs[i] = NULL;
  479. }
  480. }
  481. lua_pushinteger(L, counter);
  482. return 1;
  483. }
  484. #include "rotable2.h"
  485. static const rotable_Reg_t reg_sms[] =
  486. {
  487. { "send", ROREG_FUNC(l_sms_send)},
  488. { "setNewSmsCb", ROREG_FUNC(l_sms_cb)},
  489. { "autoLong", ROREG_FUNC(l_sms_auto_long)},
  490. { "clearLong", ROREG_FUNC(l_sms_clear_long)},
  491. { NULL, ROREG_INT(0)}
  492. };
  493. LUAMOD_API int luaopen_sms( lua_State *L ) {
  494. luat_newlib2(L, reg_sms);
  495. return 1;
  496. }