app_sms.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * SMS application - ETSI ES 201 912 protocol 1 implimentation
  5. *
  6. * Copyright (C) 2004, Adrian Kennard, rights assigned to Digium
  7. *
  8. * This program is free software, distributed under the terms of
  9. * the GNU General Public License
  10. */
  11. #include <asterisk/lock.h>
  12. #include <asterisk/file.h>
  13. #include <asterisk/logger.h>
  14. #include <asterisk/options.h>
  15. #include <asterisk/channel.h>
  16. #include <asterisk/pbx.h>
  17. #include <asterisk/module.h>
  18. #include <asterisk/callerid.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <dirent.h>
  28. #include <ctype.h>
  29. #include "../astconf.h"
  30. /* ToDo */
  31. /* When acting as SC and answering, should check for messages and send instead of sending EST as first packet */
  32. /* Add full VP support */
  33. /* Handle status report messages (generation and reception) */
  34. /* Log to show oa and da with no spaces to allow parsing */
  35. /* USC2 coding */
  36. static unsigned char message_ref; /* arbitary message ref */
  37. static char log_file[255];
  38. static char spool_dir[255];
  39. static char *tdesc = "SMS/PSTN handler";
  40. static char *app = "SMS";
  41. static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
  42. static char *descrip =
  43. " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
  44. "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
  45. "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
  46. "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
  47. "Typical usage is to use to handle called from the SMS service centre CLI,\n"
  48. "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
  49. "name is the name of the queue used in /var/spool/asterisk/sms\n"
  50. "Argument 'a' means answer, i.e. send initial FSK packet.\n"
  51. "Argument 's' means act as service centre talking to a phone.\n"
  52. "Messages are processed as per text file message queues.\n"
  53. "Can also call as SMS(name|[s]|number|message) to queue a message.\n";
  54. static signed short wave[] =
  55. { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
  56. 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
  57. 0, -392, -782, -1167,
  58. -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
  59. -4985, -4938, -4862,
  60. -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
  61. };
  62. STANDARD_LOCAL_USER;
  63. LOCAL_USER_DECL;
  64. /* SMS 7 bit character mapping */
  65. /* Note that some greek characters are simply coded as 191 (inverted question mark) as ISO-8859-1 does not do greek */
  66. /* Note 27 (escape) is to be displayed as a space as per GSM 03.38 */
  67. static unsigned char sms7to8[] = {
  68. '@', 163, '$', 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229,
  69. 191, '_', 191, 191, 191, 191, 191, 191, 191, 191, 191, ' ', 198, 230, 223, 201,
  70. ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
  71. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
  72. 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  73. 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
  74. 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  75. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
  76. };
  77. unsigned char sms8to7[256];
  78. typedef struct sms_s
  79. {
  80. unsigned char hangup; /* we are done... */
  81. unsigned char smsc; /* we are SMSC */
  82. char queue[30]; /* queue name */
  83. char oa[20]; /* originating address */
  84. char da[20]; /* destination address */
  85. time_t scts; /* time stamp */
  86. unsigned char pid; /* protocol ID */
  87. unsigned char dcs; /* data coding scheme */
  88. unsigned char mr; /* message reference */
  89. unsigned char udl; /* user date length */
  90. unsigned char srr:1; /* Status Report request */
  91. unsigned char rp:1; /* Reply Path */
  92. unsigned int vp; /* validity period in minutes, 0 for not set */
  93. unsigned char ud[160]; /* user data (message) */
  94. unsigned char cli[20]; /* caller ID */
  95. unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
  96. unsigned char ophasep; /* phase (0-79) for 1200 bps */
  97. unsigned char obyte; /* byte being sent */
  98. unsigned int opause; /* silent pause before sending (in sample periods) */
  99. unsigned char obitp; /* bit in byte */
  100. unsigned char osync; /* sync bits to send */
  101. unsigned char obytep; /* byte in data */
  102. unsigned char obyten; /* bytes in data */
  103. unsigned char omsg[256]; /* data buffer (out) */
  104. unsigned char imsg[200]; /* data buffer (in) */
  105. signed long long ims0, imc0, ims1, imc1; /* magnitude averages sin/cos 0/1 */
  106. unsigned int idle;
  107. unsigned short imag; /* signal level */
  108. unsigned char ips0, ips1, ipc0, ipc1; /* phase sin/cos 0/1 */
  109. unsigned char ibitl; /* last bit */
  110. unsigned char ibitc; /* bit run length count */
  111. unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
  112. unsigned char ibitn; /* bit number in byte being received */
  113. unsigned char ibytev; /* byte value being received */
  114. unsigned char ibytep; /* byte pointer in messafe */
  115. unsigned char ibytec; /* byte checksum for message */
  116. unsigned char ierr; /* error flag */
  117. unsigned char ibith; /* history of last bits */
  118. unsigned char ibitt; /* total of 1's in last 3 bites */
  119. /* more to go here */
  120. } sms_t;
  121. static void *
  122. sms_alloc (struct ast_channel *chan, void *params)
  123. {
  124. return params;
  125. }
  126. static void
  127. sms_release (struct ast_channel *chan, void *data)
  128. {
  129. return;
  130. }
  131. static void sms_messagetx (sms_t * h);
  132. /* copy number, skipping non digits apart from leading + */
  133. static void
  134. numcpy (char *d, char *s)
  135. {
  136. if (*s == '+')
  137. *d++ = *s++;
  138. while (*s)
  139. {
  140. if (isdigit (*s))
  141. *d++ = *s;
  142. s++;
  143. }
  144. *d = 0;
  145. }
  146. static char *
  147. isodate (time_t t)
  148. { /* static, return a date/time in ISO format */
  149. static char date[20];
  150. strftime (date, sizeof (date), "%Y-%m-%d %H:%M:%S", localtime (&t));
  151. return date;
  152. }
  153. /* pack n bytes from i to o and return number of bytes */
  154. static unsigned char
  155. pack7 (unsigned char *o, unsigned char *i, unsigned char n)
  156. {
  157. unsigned char p = 0, b = 0;
  158. /* fixup - map character set perhaps... */
  159. o[0] = 0;
  160. while (n--)
  161. {
  162. o[p] |= ((sms8to7[*i] & 0x7F) << b);
  163. b += 7;
  164. if (b >= 8)
  165. {
  166. b -= 8;
  167. p++;
  168. o[p] = ((sms8to7[*i] & 0x7F) >> (7 - b));
  169. }
  170. i++;
  171. }
  172. if (b)
  173. p++;
  174. return p;
  175. }
  176. /* check if all characters are valid 7 bit coding characters */
  177. static unsigned char
  178. check7 (unsigned char l, unsigned char *p)
  179. {
  180. while (l--)
  181. if (sms8to7[*p++] & 0x80)
  182. return 1;
  183. return 0;
  184. }
  185. /* pack a date and return */
  186. static void
  187. packdate (unsigned char *o, time_t w)
  188. {
  189. struct tm *t = localtime (&w);
  190. #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
  191. int z = - t->tm_gmtoff / 3600 / 15;
  192. #else
  193. int z = timezone / 3600 / 15;
  194. #endif
  195. *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
  196. *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
  197. *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
  198. *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
  199. *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
  200. *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
  201. if (z < 0)
  202. *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
  203. else
  204. *o++ = ((z % 10) << 4) + z / 10;
  205. }
  206. /* unpack a date and return */
  207. static time_t
  208. unpackdate (unsigned char *i)
  209. {
  210. struct tm t;
  211. t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
  212. t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
  213. t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
  214. t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
  215. t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
  216. t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
  217. t.tm_isdst = 0;
  218. if (i[6] & 0x08)
  219. t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
  220. else
  221. t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
  222. return mktime (&t);
  223. }
  224. /* unpack bytes from i to o and return number of source bytes. */
  225. static unsigned char
  226. unpack7 (unsigned char *o, unsigned char *i, unsigned char l)
  227. {
  228. unsigned char b = 0, p = 0;
  229. while (l--)
  230. {
  231. if (b < 2)
  232. *o++ = sms7to8[((i[p] >> b) & 0x7F)];
  233. else
  234. *o++ = sms7to8[((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F)];
  235. b += 7;
  236. if (b >= 8)
  237. {
  238. b -= 8;
  239. p++;
  240. }
  241. }
  242. if (b)
  243. p++;
  244. return p;
  245. }
  246. /* unpack an address from i, return byte length, unpack to o */
  247. static unsigned char
  248. unpackaddress (char *o, unsigned char *i)
  249. {
  250. unsigned char l = i[0], p;
  251. if (i[1] == 0x91)
  252. *o++ = '+';
  253. for (p = 0; p < l; p++)
  254. {
  255. if (p & 1)
  256. *o++ = (i[2 + p / 2] >> 4) + '0';
  257. else
  258. *o++ = (i[2 + p / 2] & 0xF) + '0';
  259. }
  260. *o = 0;
  261. return (l + 5) / 2;
  262. }
  263. /* store an address at o, and return number of bytes used */
  264. static unsigned char
  265. packaddress (unsigned char *o, char *i)
  266. {
  267. unsigned char p = 2;
  268. o[0] = 0;
  269. if (*i == '+')
  270. {
  271. i++;
  272. o[1] = 0x91;
  273. }
  274. else
  275. o[1] = 0x81;
  276. while (*i)
  277. if (isdigit (*i))
  278. {
  279. if (o[0] & 1)
  280. o[p++] |= ((*i & 0xF) << 4);
  281. else
  282. o[p] = (*i & 0xF);
  283. o[0]++;
  284. i++;
  285. }
  286. else
  287. i++;
  288. if (o[0] & 1)
  289. o[p++] |= 0xF0; /* pad */
  290. return p;
  291. }
  292. static void
  293. sms_log (sms_t * h, char status)
  294. { /* log the output, and remove file */
  295. if (*h->oa || *h->da)
  296. {
  297. int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
  298. if (o >= 0)
  299. {
  300. char line[1000], *p;
  301. unsigned char n;
  302. snprintf(line, sizeof(line), "%s %c %s %s %s ", isodate(time(0)), status, h->queue, *h->oa ? h->oa : "-",
  303. *h->da ? h->da : "-");
  304. p = line + strlen (line);
  305. for (n = 0; n < h->udl; n++)
  306. if (h->ud[n] == '\\')
  307. {
  308. *p++ = '\\';
  309. *p++ = '\\';
  310. }
  311. else if (h->ud[n] == '\n')
  312. {
  313. *p++ = '\\';
  314. *p++ = 'n';
  315. }
  316. else if (h->ud[n] == '\r')
  317. {
  318. *p++ = '\\';
  319. *p++ = 'r';
  320. }
  321. else if (h->ud[n] < 32 || h->ud[n] == 127)
  322. *p++ = 191;
  323. else
  324. *p++ = h->ud[n];
  325. *p++ = '\n';
  326. *p = 0;
  327. write (o, line, strlen (line));
  328. close (o);
  329. }
  330. *h->oa = *h->da = h->udl = 0;
  331. }
  332. }
  333. /* parse and delete a file */
  334. static void
  335. sms_readfile (sms_t * h, char *fn)
  336. {
  337. char line[1000];
  338. FILE *s;
  339. char dcsset = 0; /* if DSC set */
  340. ast_log (LOG_EVENT, "Sending %s\n", fn);
  341. h->udl = *h->oa = *h->da = h->pid = h->srr = h->rp = h->vp = 0;
  342. h->dcs = 0xF1; /* normal messages class 1 */
  343. h->scts = time (0);
  344. h->mr = message_ref++;
  345. s = fopen (fn, "r");
  346. if (s)
  347. {
  348. if (unlink (fn))
  349. { /* concurrent access, we lost */
  350. fclose (s);
  351. return;
  352. }
  353. while (fgets (line, sizeof (line), s))
  354. { /* process line in file */
  355. char *p;
  356. for (p = line; *p && *p != '\n' && *p != '\r'; p++);
  357. *p = 0; /* strip eoln */
  358. //ast_log (LOG_EVENT, "Line %s\n", line);
  359. p = line;
  360. if (!*p || *p == ';')
  361. continue; /* blank line or comment, ignore */
  362. while (isalnum (*p))
  363. {
  364. *p = tolower (*p);
  365. p++;
  366. }
  367. while (isspace (*p))
  368. *p++ = 0;
  369. if (*p == '=')
  370. {
  371. *p++ = 0;
  372. if (!strcmp (line, "ud"))
  373. { /* parse message */
  374. unsigned char o = 0;
  375. while (*p && o < 160)
  376. {
  377. if (*p == '\\')
  378. {
  379. p++;
  380. if (*p == '\\')
  381. h->ud[o++] = *p++;
  382. else if (*p == 'n')
  383. {
  384. h->ud[o++] = '\n';
  385. p++;
  386. }
  387. else if (*p == 'r')
  388. {
  389. h->ud[o++] = '\r';
  390. p++;
  391. }
  392. }
  393. else
  394. h->ud[o++] = *p++;
  395. }
  396. h->udl = o;
  397. if (*p)
  398. ast_log (LOG_WARNING, "UD too long in %s\n", fn);
  399. }
  400. else
  401. {
  402. while (isspace (*p))
  403. p++;
  404. if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
  405. numcpy (h->oa, p);
  406. else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
  407. numcpy (h->da, p);
  408. else if (!strcmp (line, "pid"))
  409. h->pid = atoi (p);
  410. else if (!strcmp (line, "dcs"))
  411. {
  412. h->dcs = atoi (p);
  413. dcsset = 1;
  414. }
  415. else if (!strcmp (line, "mr"))
  416. h->mr = atoi (p);
  417. else if (!strcmp (line, "srr"))
  418. h->srr = (atoi (p) ? 1 : 0);
  419. else if (!strcmp (line, "vp"))
  420. h->vp = atoi (p);
  421. else if (!strcmp (line, "rp"))
  422. h->rp = (atoi (p) ? 1 : 0);
  423. else if (!strcmp (line, "scts"))
  424. { /* get date/time */
  425. int Y, m, d, H, M, S;
  426. if (sscanf (p, "%d-%d-%d %d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
  427. {
  428. struct tm t;
  429. t.tm_year = Y - 1900;
  430. t.tm_mon = m - 1;
  431. t.tm_mday = d;
  432. t.tm_hour = H;
  433. t.tm_min = M;
  434. t.tm_sec = S;
  435. t.tm_isdst = -1;
  436. h->scts = mktime (&t);
  437. if (h->scts == (time_t) - 1)
  438. ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
  439. }
  440. }
  441. else
  442. ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
  443. }
  444. }
  445. else if (*p == '#')
  446. { /* raw hex format */
  447. *p++ = 0;
  448. if (!strcmp (line, "ud"))
  449. {
  450. unsigned char o = 0;
  451. while (*p && o < 160)
  452. {
  453. if (isxdigit (*p) && isxdigit (p[1]))
  454. {
  455. h->ud[o] =
  456. (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
  457. o++;
  458. p += 2;
  459. }
  460. else
  461. break;
  462. }
  463. h->udl = o;
  464. if (*p)
  465. ast_log (LOG_WARNING, "UD too long / invalid hex in %s\n", fn);
  466. }
  467. else
  468. ast_log (LOG_WARNING, "Only ud can use 8 bit key format with # instead of =\n");
  469. }
  470. else
  471. ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
  472. }
  473. fclose (s);
  474. if (!dcsset && h->udl <= 140 && check7 (h->udl, h->ud))
  475. {
  476. h->dcs = 0xF5; // default to 8 bit
  477. ast_log (LOG_WARNING, "Sending in 8 bit format because of illegal characters %s\n", fn);
  478. }
  479. if ((h->dcs & 4) && h->udl > 140)
  480. {
  481. ast_log (LOG_WARNING, "8 bit data too long, truncated %s\n", fn);
  482. h->udl = 140;
  483. }
  484. else if (!(h->dcs & 4) && check7 (h->udl, h->ud))
  485. ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
  486. }
  487. //ast_log (LOG_EVENT, "Loaded %s\n", fn);
  488. }
  489. /* white a received text message to a file */
  490. static void
  491. sms_writefile (sms_t * h)
  492. {
  493. char fn[200] = "";
  494. char fn2[200] = "";
  495. FILE *o;
  496. strncpy(fn, spool_dir, sizeof(fn) - 1);
  497. mkdir (fn, 0777); /* ensure it exists */
  498. snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
  499. mkdir (fn, 0777); /* ensure it exists */
  500. strncpy(fn2, fn, sizeof(fn2) - 1);
  501. strftime(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%Y-%m-%d_%H:%M:%S", localtime(&h->scts));
  502. snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "-%02X", h->mr);
  503. snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
  504. o = fopen (fn, "w");
  505. if (o)
  506. {
  507. fprintf (o, "mr=%d\n", h->mr);
  508. if (*h->oa)
  509. fprintf (o, "oa=%s\n", h->oa);
  510. if (*h->da)
  511. fprintf (o, "da=%s\n", h->da);
  512. if (h->pid)
  513. fprintf (o, "pid=%d\n", h->pid);
  514. if (h->dcs != 0xF1)
  515. fprintf (o, "dcs=%d\n", h->dcs);
  516. if (h->vp)
  517. fprintf (o, "srr=%d\n", h->vp);
  518. if (h->srr)
  519. fprintf (o, "srr=1\n");
  520. if (h->rp)
  521. fprintf (o, "rp=1\n");
  522. if (h->scts)
  523. fprintf (o, "scts=%s\n", isodate (h->scts));
  524. if (h->udl)
  525. {
  526. unsigned int p;
  527. for (p = 0; p < h->udl && ((h->ud[p] >= 32 && h->ud[p] != 127) || h->ud[p] == '\n' || h->ud[p] == '\r'); p++);
  528. if (p < h->udl)
  529. { // use a hex format as unprintable characters
  530. fprintf (o, "ud#");
  531. for (p = 0; p < h->udl; p++)
  532. fprintf (o, "%02X", h->ud[p]);
  533. fprintf (o, "\n;");
  534. /* followed by commented line using printable characters */
  535. }
  536. fprintf (o, "ud=");
  537. for (p = 0; p < h->udl; p++)
  538. {
  539. if (h->ud[p] == '\\')
  540. fprintf (o, "\\\\");
  541. else if (h->ud[p] == '\r')
  542. fprintf (o, "\\r");
  543. else if (h->ud[p] == '\n')
  544. fprintf (o, "\\n");
  545. else if (h->ud[p] < 32 || h->ud[p] == 127)
  546. fputc (191, o);
  547. else
  548. fputc (h->ud[p], o);
  549. }
  550. fprintf (o, "\n");
  551. }
  552. fclose (o);
  553. if (rename (fn, fn2))
  554. unlink (fn);
  555. else
  556. ast_log (LOG_EVENT, "Received to %s\n", fn2);
  557. }
  558. }
  559. /* read dir skipping dot files... */
  560. static struct dirent *
  561. readdirdot (DIR * d)
  562. {
  563. struct dirent *f;
  564. do
  565. {
  566. f = readdir (d);
  567. }
  568. while (f && *f->d_name == '.');
  569. return f;
  570. }
  571. /* handle the incoming message */
  572. static unsigned char
  573. sms_handleincoming (sms_t * h)
  574. {
  575. unsigned char p = 3;
  576. if (h->smsc)
  577. { /* SMSC */
  578. if ((h->imsg[2] & 3) == 1)
  579. { /* SMS-SUBMIT */
  580. h->vp = 0;
  581. h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
  582. h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
  583. strncpy (h->oa, h->cli, sizeof(h->oa) - 1);
  584. h->scts = time (0);
  585. h->mr = h->imsg[p++];
  586. p += unpackaddress (h->da, h->imsg + p);
  587. h->pid = h->imsg[p++];
  588. h->dcs = h->imsg[p++];
  589. if ((h->imsg[2] & 0x18) == 0x10)
  590. { /* relative VP */
  591. if (h->imsg[p] < 144)
  592. h->vp = (h->imsg[p] + 1) * 5;
  593. else if (h->imsg[p] < 168)
  594. h->vp = 720 + (h->imsg[p] - 143) * 30;
  595. else if (h->imsg[p] < 197)
  596. h->vp = (h->imsg[p] - 166) * 1440;
  597. else
  598. h->vp = (h->imsg[p] - 192) * 10080;
  599. p++;
  600. }
  601. else if (h->imsg[2] & 0x18)
  602. p += 7; /* ignore enhanced / absolute VP */
  603. h->udl = h->imsg[p++];
  604. if (h->udl)
  605. {
  606. if (h->dcs & 4)
  607. {
  608. memcpy (h->ud, h->imsg + p, h->udl);
  609. p += h->udl;
  610. }
  611. else
  612. p += unpack7 (h->ud, h->imsg + p, h->udl);
  613. }
  614. sms_writefile (h); /* write the file */
  615. if (p != h->imsg[1] + 2)
  616. return 0xFF; /* duh! */
  617. }
  618. else
  619. {
  620. ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
  621. return 0xFF;
  622. }
  623. }
  624. else
  625. { /* client */
  626. if (!(h->imsg[2] & 3))
  627. { /* SMS-DELIVER */
  628. *h->da = h->srr = h->rp = h->vp = 0;
  629. h->mr = message_ref++;
  630. p += unpackaddress (h->oa, h->imsg + p);
  631. h->pid = h->imsg[p++];
  632. h->dcs = h->imsg[p++];
  633. h->scts = unpackdate (h->imsg + p);
  634. p += 7;
  635. h->udl = h->imsg[p++];
  636. if (h->udl)
  637. {
  638. if (h->dcs & 4)
  639. {
  640. memcpy (h->ud, h->imsg + p, h->udl);
  641. p += h->udl;
  642. }
  643. else
  644. p += unpack7 (h->ud, h->imsg + p, h->udl);
  645. }
  646. sms_writefile (h); /* write the file */
  647. if (p != h->imsg[1] + 2)
  648. return 0xFF; /* duh! */
  649. }
  650. else
  651. {
  652. ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
  653. return 0xFF;
  654. }
  655. }
  656. return 0; /* no error */
  657. }
  658. static void
  659. sms_nextoutgoing (sms_t * h)
  660. { /* find and fill in next message, or send a REL if none waiting */
  661. char fn[100 + NAME_MAX] = "";
  662. DIR *d;
  663. char more = 0;
  664. strncpy(fn, spool_dir, sizeof(fn) - 1);
  665. mkdir(fn, 0777); /* ensure it exists */
  666. snprintf(fn + strlen (fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
  667. mkdir (fn, 0777); /* ensure it exists */
  668. d = opendir (fn);
  669. if (d)
  670. {
  671. struct dirent *f = readdirdot (d);
  672. if (f)
  673. {
  674. snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
  675. sms_readfile (h, fn);
  676. if (readdirdot (d))
  677. more = 1; /* more to send */
  678. }
  679. closedir (d);
  680. }
  681. if (*h->da || *h->oa)
  682. { /* message to send */
  683. unsigned char p = 2;
  684. h->omsg[0] = 0x91; /* SMS_DATA */
  685. if (h->smsc)
  686. { /* deliver */
  687. h->omsg[p++] = (more ? 4 : 0);
  688. p += packaddress (h->omsg + p, h->oa);
  689. h->omsg[p++] = h->pid;
  690. h->omsg[p++] = h->dcs;
  691. packdate (h->omsg + p, h->scts);
  692. p += 7;
  693. h->omsg[p++] = h->udl;
  694. if (h->udl)
  695. {
  696. if (h->dcs & 4)
  697. {
  698. memcpy (h->omsg + p, h->ud, h->udl);
  699. p += h->udl;
  700. }
  701. else
  702. p += pack7 (h->omsg + p, h->ud, h->udl);
  703. }
  704. }
  705. else
  706. { /* submit */
  707. h->omsg[p++] = 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0);
  708. h->omsg[p++] = h->mr;
  709. p += packaddress (h->omsg + p, h->da);
  710. h->omsg[p++] = h->pid;
  711. h->omsg[p++] = h->dcs;
  712. if (h->vp)
  713. { /* relative VP */
  714. if (h->vp < 720)
  715. h->omsg[p++] = (h->vp + 4) / 5 - 1;
  716. else if (h->vp < 1440)
  717. h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
  718. else if (h->vp < 43200)
  719. h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
  720. else if (h->vp < 635040)
  721. h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
  722. else
  723. h->omsg[p++] = 255; /* max */
  724. }
  725. h->omsg[p++] = h->udl;
  726. if (h->udl)
  727. {
  728. if (h->dcs & 4)
  729. {
  730. memcpy (h->omsg + p, h->ud, h->udl);
  731. p += h->udl;
  732. }
  733. else
  734. p += pack7 (h->omsg + p, h->ud, h->udl);
  735. }
  736. }
  737. h->omsg[1] = p - 2;
  738. sms_messagetx (h);
  739. }
  740. else
  741. { /* no message */
  742. h->omsg[0] = 0x94; /* SMS_REL */
  743. h->omsg[1] = 0;
  744. h->hangup = 1;
  745. sms_messagetx (h);
  746. }
  747. }
  748. static void
  749. sms_messagerx (sms_t * h)
  750. {
  751. ast_verbose (VERBOSE_PREFIX_3 "SMS RX %02X %02X %02X %02X %02X %02X...\n", h->imsg[0], h->imsg[1], h->imsg[2],
  752. h->imsg[3], h->imsg[4], h->imsg[5]);
  753. /* testing */
  754. switch (h->imsg[0])
  755. {
  756. case 0x91: /* SMS_DATA */
  757. {
  758. unsigned char cause = sms_handleincoming (h);
  759. if (!cause)
  760. {
  761. sms_log (h, 'Y');
  762. h->omsg[0] = 0x95; /* SMS_ACK */
  763. h->omsg[1] = 0x02;
  764. h->omsg[2] = 0x00; /* deliver report */
  765. h->omsg[3] = 0x00; /* no parameters */
  766. }
  767. else
  768. { /* NACK */
  769. sms_log (h, 'N');
  770. h->omsg[0] = 0x96; /* SMS_NACK */
  771. h->omsg[1] = 3;
  772. h->omsg[2] = 0; /* delivery report */
  773. h->omsg[3] = cause; /* cause */
  774. h->omsg[4] = 0; /* no parameters */
  775. }
  776. sms_messagetx (h);
  777. }
  778. break;
  779. case 0x92: /* SMS_ERROR */
  780. sms_messagetx (h); /* send whatever we sent again */
  781. break;
  782. case 0x93: /* SMS_EST */
  783. sms_nextoutgoing (h);
  784. break;
  785. case 0x94: /* SMS_REL */
  786. h->hangup = 1; /* hangup */
  787. break;
  788. case 0x95: /* SMS_ACK */
  789. sms_log (h, 'Y');
  790. sms_nextoutgoing (h);
  791. break;
  792. case 0x96: /* SMS_NACK */
  793. sms_log (h, 'N');
  794. sms_nextoutgoing (h);
  795. break;
  796. default: /* Unknown */
  797. h->omsg[0] = 0x92; /* SMS_ERROR */
  798. h->omsg[1] = 1;
  799. h->omsg[2] = 3; /* unknown message type; */
  800. sms_messagetx (h);
  801. break;
  802. }
  803. }
  804. static void
  805. sms_messagetx (sms_t * h)
  806. {
  807. unsigned char c = 0, p;
  808. for (p = 0; p < h->omsg[1] + 2; p++)
  809. c += h->omsg[p];
  810. h->omsg[h->omsg[1] + 2] = 0 - c;
  811. ast_verbose (VERBOSE_PREFIX_3 "SMS TX %02X %02X %02X %02X %02X %02X...\n", h->omsg[0], h->omsg[1], h->omsg[2],
  812. h->omsg[3], h->omsg[4], h->omsg[5]);
  813. h->obyte = 1;
  814. h->opause = 200;
  815. if (h->omsg[0] == 0x93)
  816. h->opause = 2400; /* initial message delay 300ms (for BT) */
  817. h->obytep = 0;
  818. h->obitp = 0;
  819. h->osync = 80;
  820. h->obyten = h->omsg[1] + 3;
  821. }
  822. static int
  823. sms_generate (struct ast_channel *chan, void *data, int len, int samples)
  824. {
  825. struct ast_frame f;
  826. unsigned char waste[AST_FRIENDLY_OFFSET];
  827. signed short buf[800];
  828. sms_t *h = data;
  829. int i;
  830. if (len > sizeof (buf))
  831. {
  832. ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
  833. len = sizeof (buf);
  834. samples = len / 2;
  835. }
  836. waste[0] = 0; /* make compiler happy */
  837. f.frametype = AST_FRAME_VOICE;
  838. f.subclass = AST_FORMAT_SLINEAR;
  839. f.offset = AST_FRIENDLY_OFFSET;
  840. f.mallocd = 0;
  841. f.data = buf;
  842. f.datalen = samples * 2;
  843. f.samples = samples;
  844. f.src = "app_sms";
  845. /* create a buffer containing the digital sms pattern */
  846. for (i = 0; i < samples; i++)
  847. {
  848. buf[i] = 0;
  849. if (h->opause)
  850. h->opause--;
  851. else if (h->obyten || h->osync)
  852. { /* sending data */
  853. buf[i] = wave[h->ophase];
  854. if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
  855. h->ophase -= 80;
  856. if ((h->ophasep += 12) >= 80)
  857. { /* next bit */
  858. h->ophasep -= 80;
  859. if (h->osync)
  860. h->osync--; /* sending sync bits */
  861. else
  862. {
  863. h->obyte >>= 1;
  864. h->obitp++;
  865. if (h->obitp == 1)
  866. h->obyte = 0; /* start bit; */
  867. else if (h->obitp == 2)
  868. h->obyte = h->omsg[h->obytep];
  869. else if (h->obitp == 10)
  870. {
  871. h->obyte = 1; /* stop bit */
  872. h->obitp = 0;
  873. h->obytep++;
  874. if (h->obytep == h->obyten)
  875. {
  876. h->obytep = h->obyten = 0; /* sent */
  877. h->osync = 10; /* trailing marks */
  878. }
  879. }
  880. }
  881. }
  882. }
  883. }
  884. if (ast_write (chan, &f) < 0)
  885. {
  886. ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
  887. return -1;
  888. }
  889. return 0;
  890. }
  891. static void
  892. sms_process (sms_t * h, int samples, signed short *data)
  893. {
  894. if (h->obyten || h->osync)
  895. return; /* sending */
  896. while (samples--)
  897. {
  898. unsigned long long m0, m1;
  899. if (abs (*data) > h->imag)
  900. h->imag = abs (*data);
  901. else
  902. h->imag = h->imag * 7 / 8;
  903. if (h->imag > 500)
  904. {
  905. h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
  906. h->idle = 0;
  907. h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
  908. h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
  909. h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
  910. m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
  911. m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
  912. if ((h->ips0 += 21) >= 80)
  913. h->ips0 -= 80;
  914. if ((h->ipc0 += 21) >= 80)
  915. h->ipc0 -= 80;
  916. if ((h->ips1 += 13) >= 80)
  917. h->ips1 -= 80;
  918. if ((h->ipc1 += 13) >= 80)
  919. h->ipc1 -= 80;
  920. {
  921. char bit;
  922. h->ibith <<= 1;
  923. if (m1 > m0)
  924. h->ibith |= 1;
  925. if (h->ibith & 8)
  926. h->ibitt--;
  927. if (h->ibith & 1)
  928. h->ibitt++;
  929. bit = ((h->ibitt > 1) ? 1 : 0);
  930. if (bit != h->ibitl)
  931. h->ibitc = 1;
  932. else
  933. h->ibitc++;
  934. h->ibitl = bit;
  935. if (!h->ibitn && h->ibitc == 4 && !bit)
  936. {
  937. h->ibitn = 1;
  938. h->iphasep = 0;
  939. }
  940. if (bit && h->ibitc == 200)
  941. { /* sync, restart message */
  942. h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
  943. }
  944. if (h->ibitn)
  945. {
  946. h->iphasep += 12;
  947. if (h->iphasep >= 80)
  948. { /* next bit */
  949. h->iphasep -= 80;
  950. if (h->ibitn++ == 9)
  951. { /* end of byte */
  952. if (!bit) /* bad stop bit */
  953. h->ierr = 0xFF; /* unknown error */
  954. else
  955. {
  956. if (h->ibytep < sizeof (h->imsg))
  957. {
  958. h->imsg[h->ibytep] = h->ibytev;
  959. h->ibytec += h->ibytev;
  960. h->ibytep++;
  961. }
  962. else if (h->ibytep == sizeof (h->imsg))
  963. h->ierr = 2; /* bad message length */
  964. if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
  965. {
  966. if (!h->ibytec)
  967. sms_messagerx (h);
  968. else
  969. h->ierr = 1; /* bad checksum */
  970. }
  971. }
  972. h->ibitn = 0;
  973. }
  974. h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
  975. }
  976. }
  977. }
  978. }
  979. else
  980. { /* lost carrier */
  981. if (h->idle++ == 80000)
  982. { /* nothing happening */
  983. ast_log (LOG_EVENT, "No data, hanging up\n");
  984. h->hangup = 1;
  985. }
  986. if (h->ierr)
  987. { /* error */
  988. h->omsg[0] = 0x92; /* error */
  989. h->omsg[1] = 1;
  990. h->omsg[2] = h->ierr;
  991. sms_messagetx (h); /* send error */
  992. }
  993. h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
  994. }
  995. data++;
  996. }
  997. }
  998. static struct ast_generator smsgen = {
  999. alloc:sms_alloc,
  1000. release:sms_release,
  1001. generate:sms_generate,
  1002. };
  1003. static int
  1004. sms_exec(struct ast_channel *chan, void *data)
  1005. {
  1006. int res = -1;
  1007. struct localuser *u;
  1008. struct ast_frame *f;
  1009. sms_t h = { 0 };
  1010. h.ipc0 = h.ipc1 = 20; /* phase for cosine */
  1011. h.dcs = 0xF1; /* default */
  1012. if (!data) {
  1013. ast_log (LOG_ERROR, "Requires queue name at least\n");
  1014. return -1;
  1015. }
  1016. if (chan->callerid) {
  1017. /* get caller ID. Used as originating address on sc side receives */
  1018. char temp[256], *name, *num;
  1019. strncpy (temp, chan->callerid, sizeof(temp) - 1);
  1020. ast_callerid_parse (temp, &name, &num);
  1021. if (!num)
  1022. num = temp;
  1023. ast_shrink_phone_number (num);
  1024. if (strlen (num) < sizeof (h.cli))
  1025. strncpy(h.cli, num, sizeof(h.cli) - 1);
  1026. }
  1027. {
  1028. char *d = data, *p, answer = 0;
  1029. if (!*d || *d == '|') {
  1030. ast_log (LOG_ERROR, "Requires queue name\n");
  1031. return -1;
  1032. }
  1033. for (p = d; *p && *p != '|'; p++);
  1034. if (p - d + 1 >= sizeof (h.queue)) {
  1035. ast_log (LOG_ERROR, "Queue name too long\n");
  1036. return -1;
  1037. }
  1038. strncpy(h.queue, d, p - d);
  1039. if (*p == '|')
  1040. p++;
  1041. d = p;
  1042. for (p = h.queue; *p; p++)
  1043. if (!isalnum (*p))
  1044. *p = '-'; /* make very safe for filenames */
  1045. while (*d && *d != '|') {
  1046. switch (*d) {
  1047. case 'a': /* we have to send the initial FSK sequence */
  1048. answer = 1;
  1049. break;
  1050. case 's': /* we are acting as a service centre talking to a phone */
  1051. h.smsc = 1;
  1052. break;
  1053. /* the following apply if there is an arg3/4 and apply to the created message file */
  1054. case 'r':
  1055. h.srr = 1;
  1056. break;
  1057. case 'o':
  1058. h.dcs |= 4; /* octets */
  1059. break;
  1060. case '1':
  1061. case '2':
  1062. case '3':
  1063. case '4':
  1064. case '5':
  1065. case '6':
  1066. case '7': /* set the pid for saved local message */
  1067. h.pid = 0x40 + (*d & 0xF);
  1068. break;
  1069. }
  1070. d++;
  1071. }
  1072. if (*d == '|') {
  1073. /* submitting a message, not taking call. */
  1074. d++;
  1075. h.scts = time (0);
  1076. for (p = d; *p && *p != '|'; p++);
  1077. if (*p)
  1078. *p++ = 0;
  1079. if (strlen (d) >= sizeof (h.oa)) {
  1080. ast_log (LOG_ERROR, "Address too long %s\n", d);
  1081. return 0;
  1082. }
  1083. if (h.smsc) {
  1084. strncpy(h.oa, d, sizeof(h.oa) - 1);
  1085. }
  1086. else {
  1087. strncpy(h.da, d, sizeof(h.da) - 1);
  1088. }
  1089. if (!h.smsc)
  1090. strncpy(h.oa, h.cli, sizeof(h.oa) - 1);
  1091. d = p;
  1092. if (!(h.dcs & 4) && check7 (h.udl, h.ud))
  1093. ast_log (LOG_WARNING, "Invalid GSM characters in %.*s\n", h.udl, h.ud);
  1094. if (strlen (d) > ((h.dcs & 4) ? 140 : 160)) {
  1095. ast_log (LOG_ERROR, "Message too long %s\n", d);
  1096. h.udl = ((h.dcs & 4) ? 140 : 160);
  1097. }
  1098. else
  1099. h.udl = strlen (d);
  1100. if (h.udl)
  1101. memcpy (h.ud, d, h.udl);
  1102. h.smsc = !h.smsc; /* file woul go in wrong directory otherwise... */
  1103. sms_writefile (&h);
  1104. return 0;
  1105. }
  1106. if (answer) {
  1107. /* set up SMS_EST initial message */
  1108. h.omsg[0] = 0x93;
  1109. h.omsg[1] = 0;
  1110. sms_messagetx (&h);
  1111. }
  1112. }
  1113. LOCAL_USER_ADD (u);
  1114. if (chan->_state != AST_STATE_UP)
  1115. ast_answer (chan);
  1116. res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
  1117. if (res >= 0)
  1118. res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
  1119. if (res < 0) {
  1120. LOCAL_USER_REMOVE (u);
  1121. ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
  1122. return -1;
  1123. }
  1124. if (ast_activate_generator (chan, &smsgen, &h) < 0) {
  1125. LOCAL_USER_REMOVE (u);
  1126. ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
  1127. return -1;
  1128. }
  1129. /* Do our thing here */
  1130. while (ast_waitfor (chan, -1) > -1 && !h.hangup) {
  1131. f = ast_read (chan);
  1132. if (!f)
  1133. break;
  1134. if (f->frametype == AST_FRAME_VOICE) {
  1135. sms_process (&h, f->samples, f->data);
  1136. }
  1137. ast_frfree (f);
  1138. }
  1139. sms_log (&h, '?'); /* log incomplete message */
  1140. LOCAL_USER_REMOVE (u);
  1141. return(h.hangup);
  1142. }
  1143. int
  1144. unload_module (void)
  1145. {
  1146. STANDARD_HANGUP_LOCALUSERS;
  1147. return ast_unregister_application (app);
  1148. }
  1149. int
  1150. load_module (void)
  1151. {
  1152. { /* fill in sms8to7 from sms7to8 */
  1153. int p;
  1154. for (p = 0; p < 256; p++)
  1155. sms8to7[p] = 0xE0; /* inverted question mark and invalid */
  1156. for (p = 0; p < 128; p++)
  1157. sms8to7[sms7to8[p]] = p;
  1158. }
  1159. snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
  1160. snprintf(spool_dir, sizeof(spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
  1161. return ast_register_application (app, sms_exec, synopsis, descrip);
  1162. }
  1163. char *
  1164. description (void)
  1165. {
  1166. return tdesc;
  1167. }
  1168. int
  1169. usecount (void)
  1170. {
  1171. int res;
  1172. STANDARD_USECOUNT (res);
  1173. return res;
  1174. }
  1175. char *
  1176. key ()
  1177. {
  1178. return ASTERISK_GPL_KEY;
  1179. }