00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153710 $")
00040
00041 #include <dirent.h>
00042 #include <ctype.h>
00043 #include <sys/stat.h>
00044
00045 #include "asterisk/paths.h"
00046 #include "asterisk/lock.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/module.h"
00051 #include "asterisk/alaw.h"
00052 #include "asterisk/callerid.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/app.h"
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 static volatile unsigned char message_ref;
00065 static volatile unsigned int seq;
00066
00067 static char log_file[255];
00068
00069 static char *app = "SMS";
00070
00071 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
00072
00073 static char *descrip =
00074 " SMS(name,[a][s][t][p(d)][r][o],addr,body):\n"
00075 "SMS handles exchange of SMS data with a call to/from SMS capable\n"
00076 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
00077 "Works to ETSI ES 201 912; compatible with BT SMS PSTN service in UK\n"
00078 "and Telecom Italia in Italy.\n"
00079 "Typical usage is to use to handle calls from the SMS service centre CLI,\n"
00080 "or to set up a call using 'outgoing' or manager interface to connect\n"
00081 "service centre to SMS()\n"
00082 "name is the name of the queue used in /var/spool/asterisk/sms\n"
00083 "Arguments:\n"
00084 " a - answer, i.e. send initial FSK packet.\n"
00085 " s - act as service centre talking to a phone.\n"
00086 " t - use protocol 2 (default used is protocol 1).\n"
00087 " p(N) - set the initial delay to N ms (default is 300).\n"
00088 " addr and body are a deprecated format to send messages out.\n"
00089 " r - set the Status Report Request (SRR) bit.\n"
00090 " o - the body should be coded as octets not 7-bit symbols.\n"
00091 "Messages are processed as per text file message queues.\n"
00092 "smsq (a separate software) is a command to generate message\n"
00093 "queues and send messages.\n"
00094 "NOTE: the protocol has tight delay bounds. Please use short frames\n"
00095 "and disable/keep short the jitter buffer on the ATA to make sure that\n"
00096 "respones (ACK etc.) are received in time.\n";
00097
00098
00099
00100
00101
00102
00103
00104 static signed short wave[] = {
00105 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
00106 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
00107 0, -392, -782, -1167,
00108 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
00109 -4985, -4938, -4862,
00110 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
00111 };
00112
00113 #ifdef OUTALAW
00114 static unsigned char wavea[80];
00115 typedef unsigned char output_t;
00116 static const output_t *wave_out = wavea;
00117 #define __OUT_FMT AST_FORMAT_ALAW;
00118 #else
00119 typedef signed short output_t;
00120 static const output_t *wave_out = wave;
00121 #define __OUT_FMT AST_FORMAT_SLINEAR
00122 #endif
00123
00124 #define OSYNC_BITS 80
00125
00126
00127
00128
00129
00130
00131
00132
00133 enum message_types {
00134 DLL_SMS_MASK = 0x7f,
00135
00136
00137 DLL1_SMS_DATA = 0x11,
00138 DLL1_SMS_ERROR = 0x12,
00139 DLL1_SMS_EST = 0x13,
00140 DLL1_SMS_REL = 0x14,
00141 DLL1_SMS_ACK = 0x15,
00142 DLL1_SMS_NACK = 0x16,
00143
00144 DLL1_SMS_COMPLETE = 0x80,
00145 DLL1_SMS_MORE = 0x00,
00146
00147
00148 DLL2_SMS_EST = 0x7f,
00149 DLL2_SMS_INFO_MO = 0x10,
00150 DLL2_SMS_INFO_MT = 0x11,
00151 DLL2_SMS_INFO_STA = 0x12,
00152 DLL2_SMS_NACK = 0x13,
00153 DLL2_SMS_ACK0 = 0x14,
00154 DLL2_SMS_ACK1 = 0x15,
00155 DLL2_SMS_ENQ = 0x16,
00156 DLL2_SMS_REL = 0x17,
00157
00158 DLL2_SMS_COMPLETE = 0x00,
00159 DLL2_SMS_MORE = 0x80,
00160 };
00161
00162
00163 static const unsigned short defaultalphabet[] = {
00164 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
00165 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
00166 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
00167 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
00168 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
00169 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
00170 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
00171 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
00172 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
00173 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
00174 };
00175
00176 static const unsigned short escapes[] = {
00177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
00178 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00179 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
00180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
00181 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00183 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00185 };
00186
00187 #define SMSLEN 160
00188 #define SMSLEN_8 140
00189
00190 typedef struct sms_s {
00191 unsigned char hangup;
00192 unsigned char err;
00193 unsigned char smsc:1;
00194 unsigned char rx:1;
00195 char queue[30];
00196 char oa[20];
00197 char da[20];
00198 struct timeval scts;
00199 unsigned char pid;
00200 unsigned char dcs;
00201 short mr;
00202 int udl;
00203 int udhl;
00204 unsigned char srr:1;
00205 unsigned char udhi:1;
00206 unsigned char rp:1;
00207 unsigned int vp;
00208 unsigned short ud[SMSLEN];
00209 unsigned char udh[SMSLEN];
00210 char cli[20];
00211 unsigned char ophase;
00212 unsigned char ophasep;
00213 unsigned char obyte;
00214 unsigned int opause;
00215 unsigned char obitp;
00216 unsigned char osync;
00217 unsigned char obytep;
00218 unsigned char obyten;
00219 unsigned char omsg[256];
00220 unsigned char imsg[250];
00221 signed long long ims0,
00222 imc0,
00223 ims1,
00224 imc1;
00225 unsigned int idle;
00226 unsigned short imag;
00227 unsigned char ips0;
00228 unsigned char ips1;
00229 unsigned char ipc0;
00230 unsigned char ipc1;
00231 unsigned char ibitl;
00232 unsigned char ibitc;
00233 unsigned char iphasep;
00234 unsigned char ibitn;
00235 unsigned char ibytev;
00236 unsigned char ibytep;
00237 unsigned char ibytec;
00238 unsigned char ierr;
00239 unsigned char ibith;
00240 unsigned char ibitt;
00241
00242
00243 int opause_0;
00244 int protocol;
00245 int oseizure;
00246 int framenumber;
00247 char udtxt[SMSLEN];
00248 } sms_t;
00249
00250
00251 #define is7bit(dcs) ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) )
00252 #define is8bit(dcs) ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) )
00253 #define is16bit(dcs) ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) )
00254
00255 static void sms_messagetx(sms_t *h);
00256
00257
00258 static void numcpy(char *d, char *s)
00259 {
00260 if (*s == '+') {
00261 *d++ = *s++;
00262 }
00263 while (*s) {
00264 if (isdigit(*s)) {
00265 *d++ = *s;
00266 }
00267 s++;
00268 }
00269 *d = 0;
00270 }
00271
00272
00273 static char *isodate(time_t t, char *buf, int len)
00274 {
00275 struct ast_tm tm;
00276 struct timeval local = { t, 0 };
00277 ast_localtime(&local, &tm, NULL);
00278 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
00279 return buf;
00280 }
00281
00282
00283
00284
00285 static long utf8decode(unsigned char **pp)
00286 {
00287 unsigned char *p = *pp;
00288 if (!*p) {
00289 return 0;
00290 }
00291 (*pp)++;
00292 if (*p < 0xC0) {
00293 return *p;
00294 }
00295 if (*p < 0xE0) {
00296 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) {
00297 return *p;
00298 }
00299 (*pp)++;
00300 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
00301 }
00302 if (*p < 0xF0) {
00303 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) {
00304 return *p;
00305 }
00306 (*pp) += 2;
00307 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
00308 }
00309 if (*p < 0xF8) {
00310 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) {
00311 return *p;
00312 }
00313 (*pp) += 3;
00314 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
00315 }
00316 if (*p < 0xFC) {
00317 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00318 || (p[4] & 0xC0) != 0x80) {
00319 return *p;
00320 }
00321 (*pp) += 4;
00322 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
00323 }
00324 if (*p < 0xFE) {
00325 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00326 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) {
00327 return *p;
00328 }
00329 (*pp) += 5;
00330 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
00331 }
00332 return *p;
00333 }
00334
00335
00336
00337
00338
00339 static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00340 {
00341 unsigned char p = 0;
00342 unsigned char b = 0;
00343 unsigned char n = 0;
00344 unsigned char dummy[SMSLEN];
00345
00346 if (o == NULL) {
00347 o = dummy;
00348 }
00349
00350 if (udhl) {
00351 o[p++] = udhl;
00352 b = 1;
00353 n = 1;
00354 while (udhl--) {
00355 o[p++] = *udh++;
00356 b += 8;
00357 while (b >= 7) {
00358 b -= 7;
00359 n++;
00360 }
00361 if (n >= SMSLEN)
00362 return n;
00363 }
00364 if (b) {
00365 b = 7 - b;
00366 if (++n >= SMSLEN)
00367 return n;
00368 }
00369 }
00370 o[p] = 0;
00371
00372 while (udl--) {
00373 long u;
00374 unsigned char v;
00375 u = *ud++;
00376
00377
00378 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
00379 if (v == 128 && u && n + 1 < SMSLEN) {
00380
00381 for (v = 0; v < 128 && escapes[v] != u; v++);
00382 if (v < 128) {
00383
00384 o[p] |= (27 << b);
00385 b += 7;
00386 if (b >= 8) {
00387 b -= 8;
00388 p++;
00389 o[p] = (27 >> (7 - b));
00390 }
00391 n++;
00392 }
00393 }
00394 if (v == 128)
00395 return -1;
00396
00397 o[p] |= (v << b);
00398 b += 7;
00399 if (b >= 8) {
00400 b -= 8;
00401 p++;
00402 o[p] = (v >> (7 - b));
00403 }
00404 if (++n >= SMSLEN)
00405 return n;
00406 }
00407 return n;
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00417 {
00418 unsigned char p = 0;
00419 unsigned char dummy[SMSLEN_8];
00420
00421 if (o == NULL)
00422 o = dummy;
00423
00424 if (udhl) {
00425 o[p++] = udhl;
00426 while (udhl--) {
00427 o[p++] = *udh++;
00428 if (p >= SMSLEN_8) {
00429 return p;
00430 }
00431 }
00432 }
00433 while (udl--) {
00434 long u;
00435 u = *ud++;
00436 if (u < 0 || u > 0xFF) {
00437 return -1;
00438 }
00439 o[p++] = u;
00440 if (p >= SMSLEN_8) {
00441 return p;
00442 }
00443 }
00444 return p;
00445 }
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00456 {
00457 unsigned char p = 0;
00458 unsigned char dummy[SMSLEN_8];
00459
00460 if (o == NULL) {
00461 o = dummy;
00462 }
00463
00464 if (udhl) {
00465 o[p++] = udhl;
00466 while (udhl--) {
00467 o[p++] = *udh++;
00468 if (p >= SMSLEN_8) {
00469 return p;
00470 }
00471 }
00472 }
00473 while (udl--) {
00474 long u;
00475 u = *ud++;
00476 o[p++] = (u >> 8);
00477 if (p >= SMSLEN_8) {
00478 return p - 1;
00479 }
00480 o[p++] = u;
00481 if (p >= SMSLEN_8) {
00482 return p;
00483 }
00484 }
00485 return p;
00486 }
00487
00488
00489
00490 static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
00491 {
00492 unsigned char *p = base;
00493 if (udl == 0) {
00494 *p++ = 0;
00495 } else {
00496
00497 int l = 0;
00498 if (is7bit(dcs)) {
00499 if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
00500 l = 0;
00501 }
00502 *p++ = l;
00503 p += (l * 7 + 7) / 8;
00504 } else if (is8bit(dcs)) {
00505 if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
00506 l = 0;
00507 }
00508 *p++ = l;
00509 p += l;
00510 } else {
00511 if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
00512 l = 0;
00513 }
00514 *p++ = l;
00515 p += l;
00516 }
00517 }
00518 return p - base;
00519 }
00520
00521
00522
00523 static void packdate(unsigned char *o, time_t w)
00524 {
00525 struct ast_tm t;
00526 struct timeval topack = { w, 0 };
00527 int z;
00528
00529 ast_localtime(&topack, &t, NULL);
00530 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
00531 z = -t.tm_gmtoff / 60 / 15;
00532 #else
00533 z = timezone / 60 / 15;
00534 #endif
00535 *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
00536 *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
00537 *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
00538 *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
00539 *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
00540 *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
00541 if (z < 0) {
00542 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00543 } else {
00544 *o++ = ((z % 10) << 4) + z / 10;
00545 }
00546 }
00547
00548
00549 static struct timeval unpackdate(unsigned char *i)
00550 {
00551 struct ast_tm t;
00552
00553 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00554 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00555 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00556 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00557 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00558 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00559 t.tm_isdst = 0;
00560 if (i[6] & 0x08) {
00561 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00562 } else {
00563 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00564 }
00565
00566 return ast_mktime(&t, NULL);
00567 }
00568
00569
00570
00571
00572 static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00573 {
00574 unsigned char b = 0, p = 0;
00575 unsigned short *o = ud;
00576 *udhl = 0;
00577 if (udhi && l) {
00578 int h = i[p];
00579 *udhl = h;
00580 if (h) {
00581 b = 1;
00582 p++;
00583 l--;
00584 while (h-- && l) {
00585 *udh++ = i[p++];
00586 b += 8;
00587 while (b >= 7) {
00588 b -= 7;
00589 l--;
00590 if (!l) {
00591 break;
00592 }
00593 }
00594 }
00595
00596 if (b) {
00597 b = 7 - b;
00598 l--;
00599 }
00600 }
00601 }
00602 while (l--) {
00603 unsigned char v;
00604 if (b < 2) {
00605 v = ((i[p] >> b) & 0x7F);
00606 } else {
00607 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00608 }
00609 b += 7;
00610 if (b >= 8) {
00611 b -= 8;
00612 p++;
00613 }
00614
00615 if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
00616 o[-1] = escapes[v];
00617 } else {
00618 *o++ = defaultalphabet[v];
00619 }
00620 }
00621 *udl = (o - ud);
00622 }
00623
00624
00625
00626
00627
00628 static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00629 {
00630 unsigned short *o = ud;
00631 *udhl = 0;
00632 if (udhi) {
00633 int n = *i;
00634 *udhl = n;
00635 if (n) {
00636 i++;
00637 l--;
00638 while (l && n) {
00639 l--;
00640 n--;
00641 *udh++ = *i++;
00642 }
00643 }
00644 }
00645 while (l--) {
00646 *o++ = *i++;
00647 }
00648 *udl = (o - ud);
00649 }
00650
00651
00652
00653
00654 static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00655 {
00656 unsigned short *o = ud;
00657 *udhl = 0;
00658 if (udhi) {
00659 int n = *i;
00660 *udhl = n;
00661 if (n) {
00662 i++;
00663 l--;
00664 while (l && n) {
00665 l--;
00666 n--;
00667 *udh++ = *i++;
00668 }
00669 }
00670 }
00671 while (l--) {
00672 int v = *i++;
00673 if (l--) {
00674 v = (v << 8) + *i++;
00675 }
00676 *o++ = v;
00677 }
00678 *udl = (o - ud);
00679 }
00680
00681
00682 static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00683 {
00684 int l = *i++;
00685 if (is7bit(dcs)) {
00686 unpacksms7(i, l, udh, udhl, ud, udl, udhi);
00687 l = (l * 7 + 7) / 8;
00688 } else if (is8bit(dcs)) {
00689 unpacksms8(i, l, udh, udhl, ud, udl, udhi);
00690 } else {
00691 unpacksms16(i, l, udh, udhl, ud, udl, udhi);
00692 }
00693 return l + 1;
00694 }
00695
00696
00697 static unsigned char unpackaddress(char *o, unsigned char *i)
00698 {
00699 unsigned char l = i[0], p;
00700 if (i[1] == 0x91) {
00701 *o++ = '+';
00702 }
00703 for (p = 0; p < l; p++) {
00704 if (p & 1) {
00705 *o++ = (i[2 + p / 2] >> 4) + '0';
00706 } else {
00707 *o++ = (i[2 + p / 2] & 0xF) + '0';
00708 }
00709 }
00710 *o = 0;
00711 return (l + 5) / 2;
00712 }
00713
00714
00715 static unsigned char packaddress(unsigned char *o, char *i)
00716 {
00717 unsigned char p = 2;
00718 o[0] = 0;
00719 if (*i == '+') {
00720 i++;
00721 o[1] = 0x91;
00722 } else {
00723 o[1] = 0x81;
00724 }
00725 for ( ; *i ; i++) {
00726 if (!isdigit(*i)) {
00727 continue;
00728 }
00729 if (o[0] & 1) {
00730 o[p++] |= ((*i & 0xF) << 4);
00731 } else {
00732 o[p] = (*i & 0xF);
00733 }
00734 o[0]++;
00735 }
00736 if (o[0] & 1) {
00737 o[p++] |= 0xF0;
00738 }
00739 return p;
00740 }
00741
00742
00743 static void sms_log(sms_t * h, char status)
00744 {
00745 int o;
00746
00747 if (*h->oa == '\0' && *h->da == '\0') {
00748 return;
00749 }
00750 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
00751 if (o >= 0) {
00752 char line[1000], mrs[3] = "", *p;
00753 char buf[30];
00754 unsigned char n;
00755
00756 if (h->mr >= 0) {
00757 snprintf(mrs, sizeof(mrs), "%02X", h->mr);
00758 }
00759 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
00760 isodate(time(NULL), buf, sizeof(buf)),
00761 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
00762 S_OR(h->oa, "-"), S_OR(h->da, "-") );
00763 p = line + strlen(line);
00764 for (n = 0; n < h->udl; n++) {
00765 if (h->ud[n] == '\\') {
00766 *p++ = '\\';
00767 *p++ = '\\';
00768 } else if (h->ud[n] == '\n') {
00769 *p++ = '\\';
00770 *p++ = 'n';
00771 } else if (h->ud[n] == '\r') {
00772 *p++ = '\\';
00773 *p++ = 'r';
00774 } else if (h->ud[n] < 32 || h->ud[n] == 127) {
00775 *p++ = 191;
00776 } else {
00777 *p++ = h->ud[n];
00778 }
00779 }
00780 *p++ = '\n';
00781 *p = 0;
00782 if (write(o, line, strlen(line)) < 0) {
00783 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00784 }
00785 close(o);
00786 }
00787 *h->oa = *h->da = h->udl = 0;
00788 }
00789
00790
00791 static void sms_readfile(sms_t * h, char *fn)
00792 {
00793 char line[1000];
00794 FILE *s;
00795 char dcsset = 0;
00796 ast_log(LOG_EVENT, "Sending %s\n", fn);
00797 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00798 h->mr = -1;
00799 h->dcs = 0xF1;
00800 h->scts = ast_tvnow();
00801 s = fopen(fn, "r");
00802 if (s) {
00803 if (unlink(fn)) {
00804 fclose(s);
00805 return;
00806 }
00807 while (fgets (line, sizeof(line), s)) {
00808 char *p;
00809 void *pp = &p;
00810 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00811 *p = 0;
00812 p = line;
00813 if (!*p || *p == ';') {
00814 continue;
00815 }
00816 while (isalnum(*p)) {
00817 *p = tolower (*p);
00818 p++;
00819 }
00820 while (isspace (*p)) {
00821 *p++ = 0;
00822 }
00823 if (*p == '=') {
00824 *p++ = 0;
00825 if (!strcmp(line, "ud")) {
00826 unsigned char o = 0;
00827 memcpy(h->udtxt, p, SMSLEN);
00828 while (*p && o < SMSLEN) {
00829 h->ud[o++] = utf8decode(pp);
00830 }
00831 h->udl = o;
00832 if (*p) {
00833 ast_log(LOG_WARNING, "UD too long in %s\n", fn);
00834 }
00835 } else {
00836 while (isspace (*p)) {
00837 p++;
00838 }
00839 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
00840 numcpy (h->oa, p);
00841 } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
00842 numcpy (h->da, p);
00843 } else if (!strcmp(line, "pid")) {
00844 h->pid = atoi(p);
00845 } else if (!strcmp(line, "dcs")) {
00846 h->dcs = atoi(p);
00847 dcsset = 1;
00848 } else if (!strcmp(line, "mr")) {
00849 h->mr = atoi(p);
00850 } else if (!strcmp(line, "srr")) {
00851 h->srr = (atoi(p) ? 1 : 0);
00852 } else if (!strcmp(line, "vp")) {
00853 h->vp = atoi(p);
00854 } else if (!strcmp(line, "rp")) {
00855 h->rp = (atoi(p) ? 1 : 0);
00856 } else if (!strcmp(line, "scts")) {
00857 int Y, m, d, H, M, S;
00858
00859 if (sscanf(p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6) {
00860 struct ast_tm t = { 0, };
00861 t.tm_year = Y - 1900;
00862 t.tm_mon = m - 1;
00863 t.tm_mday = d;
00864 t.tm_hour = H;
00865 t.tm_min = M;
00866 t.tm_sec = S;
00867 t.tm_isdst = -1;
00868 h->scts = ast_mktime(&t, NULL);
00869 if (h->scts.tv_sec == 0) {
00870 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00871 }
00872 }
00873 } else {
00874 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00875 }
00876 }
00877 } else if (*p == '#') {
00878 *p++ = 0;
00879 if (*p == '#') {
00880 p++;
00881 if (!strcmp(line, "ud")) {
00882 int o = 0;
00883 while (*p && o < SMSLEN) {
00884 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
00885 h->ud[o++] =
00886 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00887 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00888 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
00889 p += 4;
00890 } else
00891 break;
00892 }
00893 h->udl = o;
00894 if (*p)
00895 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00896 } else
00897 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00898 } else if (!strcmp(line, "ud")) {
00899 int o = 0;
00900 while (*p && o < SMSLEN) {
00901 if (isxdigit(*p) && isxdigit(p[1])) {
00902 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00903 p += 2;
00904 } else {
00905 break;
00906 }
00907 }
00908 h->udl = o;
00909 if (*p) {
00910 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00911 }
00912 } else if (!strcmp(line, "udh")) {
00913 unsigned char o = 0;
00914 h->udhi = 1;
00915 while (*p && o < SMSLEN) {
00916 if (isxdigit(*p) && isxdigit(p[1])) {
00917 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00918 o++;
00919 p += 2;
00920 } else {
00921 break;
00922 }
00923 }
00924 h->udhl = o;
00925 if (*p) {
00926 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00927 }
00928 } else {
00929 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00930 }
00931 } else {
00932 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00933 }
00934 }
00935 fclose(s);
00936 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00937 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00938 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00939 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00940 } else {
00941 h->dcs = 0x08;
00942 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
00943 }
00944 } else {
00945 h->dcs = 0xF5;
00946 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
00947 }
00948 }
00949 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00950 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00951 }
00952 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00953 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00954 }
00955 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00956 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00957 }
00958 }
00959 }
00960
00961
00962 static void sms_writefile(sms_t * h)
00963 {
00964 char fn[200] = "", fn2[200] = "";
00965 char buf[30];
00966 FILE *o;
00967
00968 if (ast_tvzero(h->scts)) {
00969 h->scts = ast_tvnow();
00970 }
00971 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00972 ast_mkdir(fn, 0777);
00973 ast_copy_string(fn2, fn, sizeof(fn2));
00974 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
00975 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
00976 if ((o = fopen(fn, "w")) == NULL) {
00977 return;
00978 }
00979
00980 if (*h->oa) {
00981 fprintf(o, "oa=%s\n", h->oa);
00982 }
00983 if (*h->da) {
00984 fprintf(o, "da=%s\n", h->da);
00985 }
00986 if (h->udhi) {
00987 unsigned int p;
00988 fprintf(o, "udh#");
00989 for (p = 0; p < h->udhl; p++) {
00990 fprintf(o, "%02X", h->udh[p]);
00991 }
00992 fprintf(o, "\n");
00993 }
00994 if (h->udl) {
00995 unsigned int p;
00996 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00997 if (p < h->udl) {
00998 fputc(';', o);
00999 }
01000 fprintf(o, "ud=");
01001 for (p = 0; p < h->udl; p++) {
01002 unsigned short v = h->ud[p];
01003 if (v < 32) {
01004 fputc(191, o);
01005 } else if (v < 0x80) {
01006 fputc(v, o);
01007 } else if (v < 0x800) {
01008 fputc(0xC0 + (v >> 6), o);
01009 fputc(0x80 + (v & 0x3F), o);
01010 } else {
01011 fputc(0xE0 + (v >> 12), o);
01012 fputc(0x80 + ((v >> 6) & 0x3F), o);
01013 fputc(0x80 + (v & 0x3F), o);
01014 }
01015 }
01016 fprintf(o, "\n");
01017 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
01018 if (p < h->udl) {
01019 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
01020 if (p == h->udl) {
01021 fprintf(o, "ud#");
01022 for (p = 0; p < h->udl; p++) {
01023 fprintf(o, "%02X", h->ud[p]);
01024 }
01025 fprintf(o, "\n");
01026 } else {
01027 fprintf(o, "ud##");
01028 for (p = 0; p < h->udl; p++) {
01029 fprintf(o, "%04X", h->ud[p]);
01030 }
01031 fprintf(o, "\n");
01032 }
01033 }
01034 }
01035 if (h->scts.tv_sec) {
01036 char datebuf[30];
01037 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
01038 }
01039 if (h->pid) {
01040 fprintf(o, "pid=%d\n", h->pid);
01041 }
01042 if (h->dcs != 0xF1) {
01043 fprintf(o, "dcs=%d\n", h->dcs);
01044 }
01045 if (h->vp) {
01046 fprintf(o, "vp=%d\n", h->vp);
01047 }
01048 if (h->srr) {
01049 fprintf(o, "srr=1\n");
01050 }
01051 if (h->mr >= 0) {
01052 fprintf(o, "mr=%d\n", h->mr);
01053 }
01054 if (h->rp) {
01055 fprintf(o, "rp=1\n");
01056 }
01057 fclose(o);
01058 if (rename(fn, fn2)) {
01059 unlink(fn);
01060 } else {
01061 ast_log(LOG_EVENT, "Received to %s\n", fn2);
01062 }
01063 }
01064
01065
01066 static struct dirent *readdirqueue(DIR *d, char *queue)
01067 {
01068 struct dirent *f;
01069 do {
01070 f = readdir(d);
01071 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
01072 return f;
01073 }
01074
01075
01076 static unsigned char sms_handleincoming (sms_t * h)
01077 {
01078 unsigned char p = 3;
01079 if (h->smsc) {
01080 if ((h->imsg[2] & 3) == 1) {
01081 h->udhl = h->udl = 0;
01082 h->vp = 0;
01083 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01084 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01085 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01086 ast_copy_string(h->oa, h->cli, sizeof(h->oa));
01087 h->scts = ast_tvnow();
01088 h->mr = h->imsg[p++];
01089 p += unpackaddress(h->da, h->imsg + p);
01090 h->pid = h->imsg[p++];
01091 h->dcs = h->imsg[p++];
01092 if ((h->imsg[2] & 0x18) == 0x10) {
01093 if (h->imsg[p] < 144) {
01094 h->vp = (h->imsg[p] + 1) * 5;
01095 } else if (h->imsg[p] < 168) {
01096 h->vp = 720 + (h->imsg[p] - 143) * 30;
01097 } else if (h->imsg[p] < 197) {
01098 h->vp = (h->imsg[p] - 166) * 1440;
01099 } else {
01100 h->vp = (h->imsg[p] - 192) * 10080;
01101 }
01102 p++;
01103 } else if (h->imsg[2] & 0x18) {
01104 p += 7;
01105 }
01106 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01107 h->rx = 1;
01108 sms_writefile(h);
01109 if (p != h->imsg[1] + 2) {
01110 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01111 return 0xFF;
01112 }
01113 } else {
01114 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01115 return 0xFF;
01116 }
01117 } else {
01118 if (!(h->imsg[2] & 3)) {
01119 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
01120 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01121 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01122 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01123 h->mr = -1;
01124 p += unpackaddress(h->oa, h->imsg + p);
01125 h->pid = h->imsg[p++];
01126 h->dcs = h->imsg[p++];
01127 h->scts = unpackdate(h->imsg + p);
01128 p += 7;
01129 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01130 h->rx = 1;
01131 sms_writefile(h);
01132 if (p != h->imsg[1] + 2) {
01133 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01134 return 0xFF;
01135 }
01136 } else {
01137 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01138 return 0xFF;
01139 }
01140 }
01141 return 0;
01142 }
01143
01144 #ifdef SOLARIS
01145 #define NAME_MAX 1024
01146 #endif
01147
01148
01149
01150
01151
01152 static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
01153 {
01154 int x = h->omsg[1] + 2;
01155 if (x == 2) {
01156 x += 2;
01157 }
01158 h->omsg[x++] = msg;
01159 h->omsg[x++] = (unsigned char)size;
01160 h->omsg[x++] = 0;
01161 for (; size > 0 ; size--) {
01162 h->omsg[x++] = *data++;
01163 }
01164 h->omsg[1] = x - 2;
01165 h->omsg[2] = x - 4;
01166 h->omsg[3] = 0;
01167 }
01168
01169 static void putdummydata_proto2(sms_t *h)
01170 {
01171 adddata_proto2(h, 0x10, "\0", 1);
01172 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6);
01173 adddata_proto2(h, 0x12, "\2\0\4", 3);
01174 adddata_proto2(h, 0x13, h->udtxt, h->udl);
01175 }
01176
01177 static void sms_compose2(sms_t *h, int more)
01178 {
01179 struct ast_tm tm;
01180 struct timeval now = h->scts;
01181 char stm[9];
01182
01183 h->omsg[0] = 0x00;
01184 h->omsg[1] = 0;
01185 putdummydata_proto2(h);
01186 if (h->smsc) {
01187 h->omsg[0] = 0x11;
01188
01189 ast_localtime(&now, &tm, NULL);
01190 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
01191 adddata_proto2(h, 0x14, stm, 8);
01192 if (*h->oa == 0) {
01193 strcpy(h->oa, "00000000");
01194 }
01195 adddata_proto2(h, 0x15, h->oa, strlen(h->oa));
01196 adddata_proto2(h, 0x17, "\1", 1);
01197 } else {
01198 h->omsg[0] = 0x10;
01199
01200 adddata_proto2(h, 0x17, "\1", 1);
01201 if (*h->da == 0) {
01202 strcpy(h->da, "00000000");
01203 }
01204 adddata_proto2(h, 0x18, h->da, strlen(h->da));
01205 adddata_proto2(h, 0x1B, "\1", 1);
01206 adddata_proto2(h, 0x1C, "\0\0\0", 3);
01207 }
01208 }
01209
01210 static void putdummydata_proto2(sms_t *h);
01211
01212 #define MAX_DEBUG_LEN 300
01213 static char *sms_hexdump(unsigned char buf[], int size, char *s )
01214 {
01215 char *p;
01216 int f;
01217
01218 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
01219 sprintf(p, "%02X ", (unsigned char)buf[f]);
01220 }
01221 return(s);
01222 }
01223
01224
01225
01226 static int sms_handleincoming_proto2(sms_t *h)
01227 {
01228 int f, i, sz = 0;
01229 int msg, msgsz;
01230 struct ast_tm tm;
01231 struct timeval now = { 0, 0 };
01232 char debug_buf[MAX_DEBUG_LEN * 3 + 1];
01233
01234 sz = h->imsg[1] + 2;
01235
01236
01237
01238 now = h->scts = ast_tvnow();
01239 for (f = 4; f < sz; ) {
01240 msg = h->imsg[f++];
01241 msgsz = h->imsg[f++];
01242 msgsz += (h->imsg[f++] * 256);
01243 switch (msg) {
01244 case 0x13:
01245 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01246 if (msgsz >= sizeof(h->imsg)) {
01247 msgsz = sizeof(h->imsg) - 1;
01248 }
01249 for (i = 0; i < msgsz; i++) {
01250 h->ud[i] = h->imsg[f + i];
01251 }
01252 h->udl = msgsz;
01253 break;
01254 case 0x14:
01255 now = h->scts = ast_tvnow();
01256 ast_localtime(&now, &tm, NULL);
01257 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
01258 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
01259 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
01260 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
01261 tm.tm_sec = 0;
01262 h->scts = ast_mktime(&tm, NULL);
01263 ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
01264 break;
01265 case 0x15:
01266 if (msgsz >= 20) {
01267 msgsz = 20 - 1;
01268 }
01269 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01270 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
01271 break;
01272 case 0x18:
01273 if (msgsz >= 20) {
01274 msgsz = 20 - 1;
01275 }
01276 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01277 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
01278 break;
01279 case 0x1C:
01280 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
01281 break;
01282 default:
01283 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
01284 break;
01285 }
01286 f+=msgsz;
01287 }
01288 h->rx = 1;
01289 sms_writefile(h);
01290 return 0;
01291 }
01292
01293 #if 0
01294 static void smssend(sms_t *h, char *c)
01295 {
01296 int f, x;
01297 for (f = 0; f < strlen(c); f++) {
01298 sscanf(&c[f*3], "%x", &x);
01299 h->omsg[f] = x;
01300 }
01301 sms_messagetx(h);
01302 }
01303 #endif
01304
01305 static void sms_nextoutgoing (sms_t *h);
01306
01307 static void sms_messagerx2(sms_t * h)
01308 {
01309 int p = h->imsg[0] & DLL_SMS_MASK ;
01310 int cause;
01311
01312 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
01313 switch (p) {
01314 case DLL2_SMS_EST:
01315 sms_nextoutgoing (h);
01316
01317 break;
01318
01319 case DLL2_SMS_INFO_MO:
01320 case DLL2_SMS_INFO_MT:
01321 cause = sms_handleincoming_proto2(h);
01322 if (!cause) {
01323 sms_log(h, 'Y');
01324 }
01325 h->omsg[0] = DLL2_ACK(h);
01326 h->omsg[1] = 0x06;
01327 h->omsg[2] = 0x04;
01328 h->omsg[3] = 0x00;
01329 h->omsg[4] = 0x1f;
01330 h->omsg[5] = 0x01;
01331 h->omsg[6] = 0x00;
01332 h->omsg[7] = cause;
01333 sms_messagetx(h);
01334 break;
01335
01336 case DLL2_SMS_NACK:
01337 h->omsg[0] = DLL2_SMS_REL;
01338 h->omsg[1] = 0x00;
01339 sms_messagetx(h);
01340 break;
01341
01342 case DLL2_SMS_ACK0:
01343 case DLL2_SMS_ACK1:
01344
01345 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
01346
01347 h->hangup = 1;
01348 } else {
01349
01350 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY");
01351 sms_nextoutgoing (h);
01352 }
01353 break;
01354
01355 case DLL2_SMS_REL:
01356 h->omsg[0] = DLL2_ACK(h);
01357 h->omsg[1] = 0;
01358 sms_messagetx(h);
01359 break;
01360 }
01361 }
01362
01363
01364 static void sms_compose1(sms_t *h, int more)
01365 {
01366 unsigned int p = 2;
01367
01368 h->omsg[0] = 0x91;
01369 if (h->smsc) {
01370 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01371 p += packaddress(h->omsg + p, h->oa);
01372 h->omsg[p++] = h->pid;
01373 h->omsg[p++] = h->dcs;
01374 packdate(h->omsg + p, h->scts.tv_sec);
01375 p += 7;
01376 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01377 } else {
01378 h->omsg[p++] =
01379 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01380 if (h->mr < 0) {
01381 h->mr = message_ref++;
01382 }
01383 h->omsg[p++] = h->mr;
01384 p += packaddress(h->omsg + p, h->da);
01385 h->omsg[p++] = h->pid;
01386 h->omsg[p++] = h->dcs;
01387 if (h->vp) {
01388 if (h->vp < 720) {
01389 h->omsg[p++] = (h->vp + 4) / 5 - 1;
01390 } else if (h->vp < 1440) {
01391 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01392 } else if (h->vp < 43200) {
01393 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01394 } else if (h->vp < 635040) {
01395 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01396 } else {
01397 h->omsg[p++] = 255;
01398 }
01399 }
01400 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01401 }
01402 h->omsg[1] = p - 2;
01403 }
01404
01405
01406 static void sms_nextoutgoing (sms_t * h)
01407 {
01408 char fn[100 + NAME_MAX] = "";
01409 DIR *d;
01410 char more = 0;
01411
01412 *h->da = *h->oa = '\0';
01413 h->rx = 0;
01414 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
01415 ast_mkdir(fn, 0777);
01416 d = opendir(fn);
01417 if (d) {
01418 struct dirent *f = readdirqueue(d, h->queue);
01419 if (f) {
01420 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
01421 sms_readfile(h, fn);
01422 if (readdirqueue(d, h->queue)) {
01423 more = 1;
01424 }
01425 }
01426 closedir(d);
01427 }
01428 if (*h->da || *h->oa) {
01429 if (h->protocol == 2) {
01430 sms_compose2(h, more);
01431 } else {
01432 sms_compose1(h, more);
01433 }
01434 } else {
01435 if (h->protocol == 2) {
01436 h->omsg[0] = 0x17;
01437 h->omsg[1] = 0;
01438 } else {
01439 h->omsg[0] = 0x94;
01440 h->omsg[1] = 0;
01441 }
01442 }
01443 sms_messagetx(h);
01444 }
01445
01446 #define DIR_RX 1
01447 #define DIR_TX 2
01448 static void sms_debug (int dir, sms_t *h)
01449 {
01450 char txt[259 * 3 + 1];
01451 char *p = txt;
01452 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
01453 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
01454 int q = 0;
01455 while (q < n && q < 30) {
01456 sprintf(p, " %02X", msg[q++]);
01457 p += 3;
01458 }
01459 if (q < n) {
01460 sprintf(p, "...");
01461 }
01462 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
01463 }
01464
01465
01466 static void sms_messagerx(sms_t * h)
01467 {
01468 int cause;
01469
01470 sms_debug (DIR_RX, h);
01471 if (h->protocol == 2) {
01472 sms_messagerx2(h);
01473 return;
01474 }
01475
01476 switch (h->imsg[0]) {
01477 case 0x91:
01478 cause = sms_handleincoming (h);
01479 if (!cause) {
01480 sms_log(h, 'Y');
01481 h->omsg[0] = 0x95;
01482 h->omsg[1] = 0x02;
01483 h->omsg[2] = 0x00;
01484 h->omsg[3] = 0x00;
01485 } else {
01486 sms_log(h, 'N');
01487 h->omsg[0] = 0x96;
01488 h->omsg[1] = 3;
01489 h->omsg[2] = 0;
01490 h->omsg[3] = cause;
01491 h->omsg[4] = 0;
01492 }
01493 sms_messagetx(h);
01494 break;
01495
01496 case 0x92:
01497 h->err = 1;
01498 sms_messagetx(h);
01499 break;
01500 case 0x93:
01501 sms_nextoutgoing (h);
01502 break;
01503 case 0x94:
01504 h->hangup = 1;
01505 break;
01506 case 0x95:
01507 sms_log(h, 'Y');
01508 sms_nextoutgoing (h);
01509 break;
01510 case 0x96:
01511 h->err = 1;
01512 sms_log(h, 'N');
01513 sms_nextoutgoing (h);
01514 break;
01515 default:
01516 h->omsg[0] = 0x92;
01517 h->omsg[1] = 1;
01518 h->omsg[2] = 3;
01519 sms_messagetx(h);
01520 break;
01521 }
01522 }
01523
01524 static void sms_messagetx(sms_t * h)
01525 {
01526 unsigned char c = 0, p;
01527 int len = h->omsg[1] + 2;
01528
01529 for (p = 0; p < len; p++) {
01530 c += h->omsg[p];
01531 }
01532 h->omsg[len] = 0 - c;
01533 sms_debug(DIR_TX, h);
01534 h->framenumber++;
01535 h->obytep = 0;
01536 h->obitp = 0;
01537 if (h->protocol == 2) {
01538 h->oseizure = 300;
01539 h->obyte = 0;
01540 if (h->omsg[0] == 0x7F) {
01541 h->opause = 8 * h->opause_0;
01542 } else {
01543 h->opause = 400;
01544 }
01545 } else {
01546 h->oseizure = 0;
01547 h->obyte = 1;
01548
01549
01550
01551
01552 if (h->omsg[0] == 0x93) {
01553 h->opause = 8 * h->opause_0;
01554 } else {
01555 h->opause = 200;
01556 }
01557 }
01558
01559 h->osync = OSYNC_BITS;
01560 h->obyten = len + 1;
01561 }
01562
01563
01564
01565
01566
01567 static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
01568 {
01569 struct ast_frame f = { 0 };
01570 #define MAXSAMPLES (800)
01571 output_t *buf;
01572 sms_t *h = data;
01573 int i;
01574
01575 if (samples > MAXSAMPLES) {
01576 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
01577 MAXSAMPLES, samples);
01578 samples = MAXSAMPLES;
01579 }
01580 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
01581 buf = alloca(len);
01582
01583 f.frametype = AST_FRAME_VOICE;
01584 f.subclass = __OUT_FMT;
01585 f.datalen = samples * sizeof(*buf);
01586 f.offset = AST_FRIENDLY_OFFSET;
01587 f.mallocd = 0;
01588 f.data.ptr = buf;
01589 f.samples = samples;
01590 f.src = "app_sms";
01591
01592 for (i = 0; i < samples; i++) {
01593 buf[i] = wave_out[0];
01594
01595 if (h->opause) {
01596 h->opause--;
01597 } else if (h->obyten || h->osync) {
01598 buf[i] = wave_out[h->ophase];
01599 h->ophase += (h->obyte & 1) ? 13 : 21;
01600 if (h->ophase >= 80)
01601 h->ophase -= 80;
01602 if ((h->ophasep += 12) >= 80) {
01603 h->ophasep -= 80;
01604 if (h->oseizure > 0) {
01605 h->oseizure--;
01606 h->obyte ^= 1;
01607 } else if (h->osync) {
01608 h->obyte = 1;
01609 h->osync--;
01610 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
01611 h->obytep = h->obyten = 0;
01612 }
01613 } else {
01614 h->obitp++;
01615 if (h->obitp == 1) {
01616 h->obyte = 0;
01617 } else if (h->obitp == 2) {
01618 h->obyte = h->omsg[h->obytep];
01619 } else if (h->obitp == 10) {
01620 h->obyte = 1;
01621 h->obitp = 0;
01622 h->obytep++;
01623 if (h->obytep == h->obyten) {
01624 h->obytep = h->obyten = 0;
01625 h->osync = 10;
01626 }
01627 } else {
01628 h->obyte >>= 1;
01629 }
01630 }
01631 }
01632 }
01633 }
01634 if (ast_write(chan, &f) < 0) {
01635 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
01636 return -1;
01637 }
01638 return 0;
01639 #undef MAXSAMPLES
01640 }
01641
01642
01643
01644
01645 static void *sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
01646 {
01647 return sms_t_ptr;
01648 }
01649
01650 static void sms_release(struct ast_channel *chan, void *data)
01651 {
01652 return;
01653 }
01654
01655 static struct ast_generator smsgen = {
01656 .alloc = sms_alloc,
01657 .release = sms_release,
01658 .generate = sms_generate,
01659 };
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673 static void sms_process(sms_t * h, int samples, signed short *data)
01674 {
01675 int bit;
01676
01677
01678
01679
01680
01681
01682
01683
01684 if (h->obyten || h->osync) {
01685 return;
01686 }
01687 for ( ; samples-- ; data++) {
01688 unsigned long long m0, m1;
01689 if (abs(*data) > h->imag) {
01690 h->imag = abs(*data);
01691 } else {
01692 h->imag = h->imag * 7 / 8;
01693 }
01694 if (h->imag <= 500) {
01695 if (h->idle++ == 80000) {
01696 ast_log(LOG_NOTICE, "No data, hanging up\n");
01697 h->hangup = 1;
01698 h->err = 1;
01699 }
01700 if (h->ierr) {
01701 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
01702
01703 h->err = 1;
01704 h->omsg[0] = 0x92;
01705 h->omsg[1] = 1;
01706 h->omsg[2] = h->ierr;
01707 sms_messagetx(h);
01708 }
01709 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01710 continue;
01711 }
01712 h->idle = 0;
01713
01714
01715 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01716 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01717 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01718 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01719
01720 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01721 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01722
01723
01724 if ((h->ips0 += 21) >= 80) {
01725 h->ips0 -= 80;
01726 }
01727 if ((h->ipc0 += 21) >= 80) {
01728 h->ipc0 -= 80;
01729 }
01730 if ((h->ips1 += 13) >= 80) {
01731 h->ips1 -= 80;
01732 }
01733 if ((h->ipc1 += 13) >= 80) {
01734 h->ipc1 -= 80;
01735 }
01736
01737
01738 h->ibith <<= 1;
01739 if (m1 > m0) {
01740 h->ibith |= 1;
01741 }
01742 if (h->ibith & 8) {
01743 h->ibitt--;
01744 }
01745 if (h->ibith & 1) {
01746 h->ibitt++;
01747 }
01748 bit = ((h->ibitt > 1) ? 1 : 0);
01749 if (bit != h->ibitl) {
01750 h->ibitc = 1;
01751 } else {
01752 h->ibitc++;
01753 }
01754 h->ibitl = bit;
01755 if (!h->ibitn && h->ibitc == 4 && !bit) {
01756 h->ibitn = 1;
01757 h->iphasep = 0;
01758 }
01759 if (bit && h->ibitc == 200) {
01760
01761 if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
01762 h->framenumber = 1;
01763 ast_verb(3, "SMS protocol 2 detected\n");
01764 h->protocol = 2;
01765 h->imsg[0] = 0xff;
01766 h->imsg[1] = h->imsg[2] = 0x00;
01767 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01768 sms_messagerx(h);
01769 }
01770 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01771 }
01772 if (h->ibitn) {
01773 h->iphasep += 12;
01774 if (h->iphasep >= 80) {
01775 h->iphasep -= 80;
01776 if (h->ibitn++ == 9) {
01777 if (!bit) {
01778 ast_log(LOG_NOTICE, "bad stop bit");
01779 h->ierr = 0xFF;
01780 } else {
01781 if (h->ibytep < sizeof(h->imsg)) {
01782 h->imsg[h->ibytep] = h->ibytev;
01783 h->ibytec += h->ibytev;
01784 h->ibytep++;
01785 } else if (h->ibytep == sizeof(h->imsg)) {
01786 ast_log(LOG_NOTICE, "msg too large");
01787 h->ierr = 2;
01788 }
01789 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01790 if (!h->ibytec) {
01791 sms_messagerx(h);
01792 } else {
01793 ast_log(LOG_NOTICE, "bad checksum");
01794 h->ierr = 1;
01795 }
01796 }
01797 }
01798 h->ibitn = 0;
01799 }
01800 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01801 }
01802 }
01803 }
01804 }
01805
01806
01807
01808
01809
01810
01811
01812
01813 enum {
01814 OPTION_BE_SMSC = (1 << 0),
01815 OPTION_ANSWER = (1 << 1),
01816 OPTION_TWO = (1 << 2),
01817 OPTION_PAUSE = (1 << 3),
01818 OPTION_SRR = (1 << 4),
01819 OPTION_DCS = (1 << 5),
01820 } sms_flags;
01821
01822 enum {
01823 OPTION_ARG_PAUSE = 0,
01824 OPTION_ARG_ARRAY_SIZE
01825 } sms_opt_args;
01826
01827 AST_APP_OPTIONS(sms_options, {
01828 AST_APP_OPTION('s', OPTION_BE_SMSC),
01829 AST_APP_OPTION('a', OPTION_ANSWER),
01830 AST_APP_OPTION('t', OPTION_TWO),
01831 AST_APP_OPTION('r', OPTION_SRR),
01832 AST_APP_OPTION('o', OPTION_DCS),
01833 AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
01834 } );
01835
01836 static int sms_exec(struct ast_channel *chan, void *data)
01837 {
01838 int res = -1;
01839 sms_t h = { 0 };
01840
01841 struct ast_flags flags;
01842 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
01843 char *p;
01844 AST_DECLARE_APP_ARGS(sms_args,
01845 AST_APP_ARG(queue);
01846 AST_APP_ARG(options);
01847 AST_APP_ARG(addr);
01848 AST_APP_ARG(body);
01849 );
01850
01851 if (!data) {
01852 ast_log(LOG_ERROR, "Requires queue name at least\n");
01853 return -1;
01854 }
01855
01856 parse = ast_strdupa(data);
01857 AST_STANDARD_APP_ARGS(sms_args, parse);
01858 if (sms_args.argc > 1) {
01859 ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
01860 }
01861
01862 ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
01863 sms_args.argc, S_OR(sms_args.queue, ""),
01864 S_OR(sms_args.options, ""),
01865 S_OR(sms_args.addr, ""),
01866 S_OR(sms_args.body, "") );
01867
01868 h.ipc0 = h.ipc1 = 20;
01869 h.dcs = 0xF1;
01870
01871 if (chan->cid.cid_num)
01872 ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli));
01873
01874 if (ast_strlen_zero(sms_args.queue)) {
01875 ast_log(LOG_ERROR, "Requires queue name\n");
01876 goto done;
01877 }
01878 if (strlen(sms_args.queue) >= sizeof(h.queue)) {
01879 ast_log(LOG_ERROR, "Queue name too long\n");
01880 goto done;
01881 }
01882 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
01883
01884 for (p = h.queue; *p; p++) {
01885 if (!isalnum(*p)) {
01886 *p = '-';
01887 }
01888 }
01889
01890 h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC);
01891 h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
01892 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
01893 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
01894 }
01895 if (h.opause_0 < 25 || h.opause_0 > 2000) {
01896 h.opause_0 = 300;
01897 }
01898 ast_verb(1, "initial delay %dms\n", h.opause_0);
01899
01900
01901
01902 if (ast_test_flag(&flags, OPTION_SRR)) {
01903 h.srr = 1;
01904 }
01905 if (ast_test_flag(&flags, OPTION_DCS)) {
01906 h.dcs = 1;
01907 }
01908 #if 0
01909 case '1':
01910 case '2':
01911 case '3':
01912 case '4':
01913 case '5':
01914 case '6':
01915 case '7':
01916 h.pid = 0x40 + (*d & 0xF);
01917 break;
01918 }
01919 #endif
01920 if (sms_args.argc > 2) {
01921 unsigned char *up;
01922
01923
01924
01925 h.scts = ast_tvnow();
01926 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
01927 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
01928 goto done;
01929 }
01930 if (h.smsc) {
01931 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
01932 } else {
01933 ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
01934 ast_copy_string(h.oa, h.cli, sizeof(h.oa));
01935 }
01936 h.udl = 0;
01937 if (ast_strlen_zero(sms_args.body)) {
01938 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
01939 goto done;
01940 }
01941 up = (unsigned char *)sms_args.body;
01942 while (*up && h.udl < SMSLEN) {
01943 h.ud[h.udl++] = utf8decode(&up);
01944 }
01945 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01946 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
01947 goto done;
01948 }
01949 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01950 ast_log(LOG_WARNING, "Invalid 8 bit data\n");
01951 goto done;
01952 }
01953 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01954 ast_log(LOG_WARNING, "Invalid 16 bit data\n");
01955 goto done;
01956 }
01957 h.rx = 0;
01958 h.mr = -1;
01959 sms_writefile(&h);
01960 res = h.err;
01961 goto done;
01962 }
01963
01964 if (chan->_state != AST_STATE_UP) {
01965 ast_answer(chan);
01966 }
01967
01968 if (ast_test_flag(&flags, OPTION_ANSWER)) {
01969 h.framenumber = 1;
01970
01971 if (h.protocol == 2) {
01972 h.omsg[0] = DLL2_SMS_EST;
01973 h.omsg[1] = 0;
01974 } else {
01975 h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE;
01976 h.omsg[1] = 0;
01977 }
01978 sms_messagetx(&h);
01979 }
01980
01981 res = ast_set_write_format(chan, __OUT_FMT);
01982 if (res >= 0) {
01983 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
01984 }
01985 if (res < 0) {
01986 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
01987 goto done;
01988 }
01989
01990 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
01991 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01992 goto done;
01993 }
01994
01995
01996 for (;;) {
01997 struct ast_frame *f;
01998 int i = ast_waitfor(chan, -1);
01999 if (i < 0) {
02000 ast_log(LOG_NOTICE, "waitfor failed\n");
02001 break;
02002 }
02003 if (h.hangup) {
02004 ast_log(LOG_NOTICE, "channel hangup\n");
02005 break;
02006 }
02007 f = ast_read(chan);
02008 if (!f) {
02009 ast_log(LOG_NOTICE, "ast_read failed\n");
02010 break;
02011 }
02012 if (f->frametype == AST_FRAME_VOICE) {
02013 sms_process(&h, f->samples, f->data.ptr);
02014 }
02015
02016 ast_frfree(f);
02017 }
02018 res = h.err;
02019
02020 sms_log(&h, '?');
02021 done:
02022 return (res);
02023 }
02024
02025 static int unload_module(void)
02026 {
02027 return ast_unregister_application(app);
02028 }
02029
02030 static int load_module(void)
02031 {
02032 #ifdef OUTALAW
02033 int p;
02034 for (p = 0; p < 80; p++) {
02035 wavea[p] = AST_LIN2A(wave[p]);
02036 }
02037 #endif
02038 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
02039 return ast_register_application(app, sms_exec, synopsis, descrip);
02040 }
02041
02042 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");