luat_lib_sms.c 15 KB

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