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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include <errno.h>
00072 #include <stdarg.h>
00073 #include <stdio.h>
00074 #include <stdlib.h>
00075 #include <string.h>
00076 #include <unistd.h>
00077 #include <fcntl.h>
00078 #include <ctype.h>
00079 #include <termios.h>
00080 #include <sys/time.h>
00081 #include <sys/types.h>
00082 #include <sys/socket.h>
00083 #include <netinet/in.h>
00084 #include <netdb.h>
00085 #include <sys/ioctl.h>
00086 #include <time.h>
00087 #include <math.h>
00088
00089 #include "gwlib/gwlib.h"
00090 #include "gwlib/charset.h"
00091 #include "smscconn.h"
00092 #include "smscconn_p.h"
00093 #include "bb_smscconn_cb.h"
00094 #include "msg.h"
00095 #include "sms.h"
00096 #include "dlr.h"
00097 #include "smsc_at.h"
00098
00099 static Octstr *gsm2number(Octstr *pdu);
00100 static unsigned char nibble2hex(unsigned char b);
00101
00102 static void at2_scan_for_telnet_escapes(PrivAT2data *privdata)
00103 {
00104 int len;
00105 int pos;
00106 int start;
00107 int a;
00108 int b;
00109 int i;
00110 Octstr *hex;
00111
00112 char answer[5];
00113
00114
00115 if(!privdata->ilb)
00116 return;
00117 start = 0;
00118 len = octstr_len(privdata->ilb);
00119 hex = octstr_duplicate(privdata->ilb);
00120 octstr_binary_to_hex(hex,1);
00121
00122 octstr_destroy(hex);
00123
00124 while(start < len)
00125 {
00126 pos = octstr_search_char(privdata->ilb, 0xFF, start);
00127 if(pos < 0)
00128 return;
00129 if((len - pos )<3)
00130 return;
00131 a = octstr_get_char(privdata->ilb,pos+1);
00132 b = octstr_get_char(privdata->ilb,pos+2);
00133 switch(a)
00134 {
00135 case 0xFD:
00136 answer[0] = 0xFF;
00137 answer[1] = 0xFC;
00138 answer[2] = b;
00139 i = write(privdata->fd,&answer,3);
00140 octstr_delete(privdata->ilb,pos,3);
00141 len -=3;
00142 break;
00143 break;
00144 case 0xFA:
00145 octstr_delete(privdata->ilb,pos,3);
00146 len -=3;
00147 break;
00148 break;
00149 case 0xFB:
00150 octstr_delete(privdata->ilb,pos,3);
00151 len -=3;
00152 break;
00153 case 0xFC:
00154 octstr_delete(privdata->ilb,pos,3);
00155 len -=3;
00156 break;
00157 }
00158 start = pos;
00159 }
00160
00161 }
00162
00163 static int at2_open_device1(PrivAT2data *privdata)
00164 {
00165 info(0, "AT2[%s]: opening device", octstr_get_cstr(privdata->name));
00166 if (privdata->fd > 0) {
00167 warning(0, "AT2[%s]: trying to open device with not closed device!!! Please report!!!",
00168 octstr_get_cstr(privdata->name));
00169 at2_close_device(privdata);
00170 }
00171 if (privdata->is_serial) {
00172 privdata->fd = open(octstr_get_cstr(privdata->device),
00173 O_RDWR | O_NONBLOCK | O_NOCTTY);
00174 privdata->use_telnet = 0;
00175 } else {
00176 if (octstr_str_compare(privdata->device, "rawtcp") == 0) {
00177 privdata->use_telnet = 0;
00178 privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host),
00179 privdata->rawtcp_port, NULL);
00180 }
00181 else if (octstr_str_compare(privdata->device, "telnet") == 0) {
00182 privdata->use_telnet = 1;
00183 privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host),
00184 privdata->rawtcp_port, NULL);
00185
00186 } else {
00187 gw_assert(0);
00188 }
00189 }
00190 if (privdata->fd == -1) {
00191 error(errno, "AT2[%s]: open failed! ERRNO=%d", octstr_get_cstr(privdata->name), errno);
00192 privdata->fd = -1;
00193 return -1;
00194 }
00195 debug("bb.smsc.at2", 0, "AT2[%s]: device opened. Telnet mode = %d", octstr_get_cstr(privdata->name),privdata->use_telnet);
00196
00197 return 0;
00198 }
00199
00200
00201 static int at2_login_device(PrivAT2data *privdata)
00202 {
00203 info(0, "AT2[%s]: Logging in", octstr_get_cstr(privdata->name));
00204
00205 at2_read_buffer(privdata);
00206 gwthread_sleep(0.5);
00207 at2_read_buffer(privdata);
00208
00209 if((octstr_len(privdata->username) == 0 ) && (octstr_len(privdata->password)> 0)) {
00210 at2_wait_modem_command(privdata, 10, 3, NULL);
00211 at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0);
00212 at2_send_modem_command(privdata, "AT", 2,0);
00213 }
00214 else if((octstr_len(privdata->username) > 0 ) && (octstr_len(privdata->password)> 0)) {
00215 at2_wait_modem_command(privdata, 10, 2, NULL);
00216 at2_send_modem_command(privdata, octstr_get_cstr(privdata->username), 10,3);
00217 at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0);
00218 at2_send_modem_command(privdata, "AT", 2,0);
00219 }
00220
00221 return 0;
00222 }
00223
00224
00225 static int at2_open_device(PrivAT2data *privdata)
00226 {
00227 struct termios tios;
00228 int ret;
00229
00230 if ((ret = at2_open_device1(privdata)) != 0)
00231 return ret;
00232
00233 if (!privdata->is_serial)
00234 return 0;
00235
00236 tcgetattr(privdata->fd, &tios);
00237
00238 kannel_cfmakeraw(&tios);
00239
00240 tios.c_iflag |= IGNBRK;
00241 tios.c_iflag &= ~INPCK;
00242 tios.c_cflag |= HUPCL;
00243 tios.c_cflag |= CREAD;
00244 tios.c_cflag |= CLOCAL;
00245 tios.c_cflag &= ~CSIZE;
00246 tios.c_cflag |= CS8;
00247 tios.c_oflag &= ~ONLCR;
00248 tios.c_iflag |= IGNPAR;
00249 tios.c_iflag &= ~INPCK;
00250 #if defined(CRTSCTS)
00251 tios.c_cflag |= CRTSCTS;
00252 #endif
00253 tios.c_cc[VSUSP] = 0;
00254
00255
00256
00257
00258
00259
00260 ret = tcsetattr(privdata->fd, TCSANOW, &tios);
00261 if (ret == -1) {
00262 error(errno, "AT2[%s]: at_data_link: fail to set termios attribute",
00263 octstr_get_cstr(privdata->name));
00264 }
00265 tcflush(privdata->fd, TCIOFLUSH);
00266
00267
00268
00269
00270
00271 if (privdata->modem == NULL || privdata->modem->need_sleep)
00272 sleep(1);
00273 debug("bb.smsc.at2", 0, "AT2[%s]: device opened", octstr_get_cstr(privdata->name));
00274 return 0;
00275 }
00276
00277
00278 static void at2_close_device(PrivAT2data *privdata)
00279 {
00280 info(0, "AT2[%s]: Closing device", octstr_get_cstr(privdata->name));
00281 close(privdata->fd);
00282 privdata->fd = -1;
00283 privdata->pin_ready = 0;
00284 privdata->phase2plus = 0;
00285 if (privdata->ilb != NULL)
00286 octstr_destroy(privdata->ilb);
00287 privdata->ilb = octstr_create("");
00288 }
00289
00290
00291 static void at2_read_buffer(PrivAT2data *privdata)
00292 {
00293 char buf[MAX_READ + 1];
00294 int ret;
00295 size_t count;
00296 signed int s;
00297 fd_set read_fd;
00298 struct timeval tv;
00299
00300 if (privdata->fd == -1) {
00301 error(errno, "AT2[%s]: at2_read_buffer: fd = -1. Can not read",
00302 octstr_get_cstr(privdata->name));
00303 return;
00304 }
00305 count = MAX_READ;
00306
00307 #ifdef SSIZE_MAX
00308 if (count > SSIZE_MAX)
00309 count = SSIZE_MAX;
00310 #endif
00311
00312 tv.tv_sec = 0;
00313 tv.tv_usec = 1000;
00314
00315 FD_ZERO(&read_fd);
00316 FD_SET(privdata->fd, &read_fd);
00317 ret = select(privdata->fd + 1, &read_fd, NULL, NULL, &tv);
00318 if (ret == -1) {
00319 if (!(errno == EINTR || errno == EAGAIN))
00320 error(errno, "AT2[%s]: error on select", octstr_get_cstr(privdata->name));
00321 return;
00322 }
00323
00324 if (ret == 0)
00325 return;
00326
00327 s = read(privdata->fd, buf, count);
00328 if (s < 0) {
00329 error(errno, "AT2[%s]: at2_read_buffer: Error during read",
00330 octstr_get_cstr(privdata->name));
00331 at2_close_device(privdata);
00332 } else {
00333 octstr_append_data(privdata->ilb, buf, s);
00334 if(privdata->use_telnet)
00335 at2_scan_for_telnet_escapes(privdata);
00336 }
00337 }
00338
00339
00340 static Octstr *at2_wait_line(PrivAT2data *privdata, time_t timeout, int gt_flag)
00341 {
00342 Octstr *line;
00343 time_t end_time;
00344 time_t cur_time;
00345
00346 time(&end_time);
00347 if (timeout == 0)
00348 timeout = 3;
00349 end_time += timeout;
00350
00351 if (privdata->lines != NULL)
00352 octstr_destroy(privdata->lines);
00353 privdata->lines = octstr_create("");
00354 while (time(&cur_time) <= end_time) {
00355 line = at2_read_line(privdata, gt_flag);
00356 if (line)
00357 return line;
00358 }
00359 return NULL;
00360 }
00361
00362 static Octstr *at2_read_line(PrivAT2data *privdata, int gt_flag)
00363 {
00364 int eol;
00365 int gtloc;
00366 int len;
00367 Octstr *line;
00368 Octstr *buf2;
00369 int i;
00370
00371 at2_read_buffer(privdata);
00372 at2_scan_for_telnet_escapes(privdata);
00373 len = octstr_len(privdata->ilb);
00374 if (len == 0)
00375 return NULL;
00376
00377 if (gt_flag==1) {
00378
00379 gtloc = octstr_search_char(privdata->ilb, '>', 0);
00380 }
00381 else if((gt_flag == 2) && (privdata->username)) {
00382 gtloc = -1;
00383 if(privdata->login_prompt) {
00384 gtloc = octstr_search(privdata->ilb,privdata->login_prompt,0);
00385 }
00386 if(gtloc == -1) {
00387 gtloc = octstr_search(privdata->ilb,octstr_imm("Login:"),0);
00388 }
00389 if(gtloc == -1) {
00390 gtloc = octstr_search(privdata->ilb,octstr_imm("Username:"),0);
00391 }
00392 }
00393 else if ((gt_flag == 3) && (privdata->password)) {
00394 gtloc = -1;
00395 if(privdata->password_prompt) {
00396 gtloc = octstr_search(privdata->ilb,privdata->password_prompt,0);
00397 }
00398 if(gtloc == -1) {
00399 gtloc = octstr_search(privdata->ilb,octstr_imm("Password:"),0);
00400 }
00401 }
00402 else
00403 gtloc = -1;
00404
00405
00406
00407
00408
00409
00410
00411 eol = octstr_search_char(privdata->ilb, '\r', 0);
00412
00413 if ((gtloc != -1) && ((eol == -1) || (eol > gtloc)))
00414 eol = gtloc;
00415
00416 if (eol == -1)
00417 return NULL;
00418
00419 line = octstr_copy(privdata->ilb, 0, eol);
00420 buf2 = octstr_copy(privdata->ilb, eol + 1, len);
00421 octstr_destroy(privdata->ilb);
00422 privdata->ilb = buf2;
00423
00424
00425 for (i = 0; i < octstr_len(line); i++) {
00426 if (octstr_get_char(line, i) < 32)
00427 octstr_set_char(line, i, ' ');
00428 }
00429 octstr_strip_blanks(line);
00430
00431
00432 if ((strcmp(octstr_get_cstr(line), "") == 0) && ( gt_flag == 0))
00433 {
00434 octstr_destroy(line);
00435 return NULL;
00436 }
00437 if ((gt_flag) && (gtloc != -1)) {
00438
00439 octstr_append_cstr(line, ">");
00440 }
00441 debug("bb.smsc.at2", 0, "AT2[%s]: <-- %s", octstr_get_cstr(privdata->name),
00442 octstr_get_cstr(line));
00443 return line;
00444 }
00445
00446
00447 static int at2_write_line(PrivAT2data *privdata, char *line)
00448 {
00449 int count;
00450 int s = 0;
00451 int write_count = 0, data_written = 0;
00452 Octstr *linestr = NULL;
00453
00454 linestr = octstr_format("%s\r", line);
00455
00456 debug("bb.smsc.at2", 0, "AT2[%s]: --> %s^M", octstr_get_cstr(privdata->name), line);
00457
00458 count = octstr_len(linestr);
00459 while (count > data_written) {
00460 errno = 0;
00461 s = write(privdata->fd, octstr_get_cstr(linestr) + data_written,
00462 count - data_written);
00463 if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) {
00464 gwthread_sleep(1);
00465 ++write_count;
00466 } else if (s > 0) {
00467 data_written += s;
00468 write_count = 0;
00469 } else
00470 break;
00471 }
00472 O_DESTROY(linestr);
00473 if (s < 0) {
00474 error(errno, "AT2[%s]: Couldnot write to device.",
00475 octstr_get_cstr(privdata->name));
00476 tcflush(privdata->fd, TCOFLUSH);
00477 return s;
00478 }
00479 tcdrain(privdata->fd);
00480 gwthread_sleep((double) (privdata->modem == NULL ?
00481 100 : privdata->modem->sendline_sleep) / 1000);
00482 return s;
00483 }
00484
00485
00486 static int at2_write_ctrlz(PrivAT2data *privdata)
00487 {
00488 int s;
00489 char *ctrlz = "\032" ;
00490 int write_count = 0;
00491
00492 debug("bb.smsc.at2", 0, "AT2[%s]: --> ^Z", octstr_get_cstr(privdata->name));
00493 while (1) {
00494 errno = 0;
00495 s = write(privdata->fd, ctrlz, 1);
00496 if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) {
00497 gwthread_sleep(1);
00498 ++write_count;
00499 } else
00500 break;
00501 }
00502 if (s < 0) {
00503 error(errno, "AT2[%s]: Couldnot write to device.",
00504 octstr_get_cstr(privdata->name));
00505 tcflush(privdata->fd, TCOFLUSH);
00506 return s;
00507 }
00508 tcdrain(privdata->fd);
00509 gwthread_sleep((double) (privdata->modem == NULL ?
00510 100 : privdata->modem->sendline_sleep) / 1000);
00511 return s;
00512 }
00513
00514
00515 static int at2_write(PrivAT2data *privdata, char *line)
00516 {
00517 int count, data_written = 0, write_count = 0;
00518 int s = 0;
00519
00520 debug("bb.smsc.at2", 0, "AT2[%s]: --> %s", octstr_get_cstr(privdata->name), line);
00521
00522 count = strlen(line);
00523 while(count > data_written) {
00524 s = write(privdata->fd, line + data_written, count - data_written);
00525 if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) {
00526 gwthread_sleep(1);
00527 ++write_count;
00528 } else if (s > 0) {
00529 data_written += s;
00530 write_count = 0;
00531 } else
00532 break;
00533 }
00534
00535 if (s < 0) {
00536 error(errno, "AT2[%s]: Couldnot write to device.",
00537 octstr_get_cstr(privdata->name));
00538 tcflush(privdata->fd, TCOFLUSH);
00539 return s;
00540 }
00541 tcdrain(privdata->fd);
00542 gwthread_sleep((double) (privdata->modem == NULL ?
00543 100 : privdata->modem->sendline_sleep) / 1000);
00544 return s;
00545 }
00546
00547
00548 static void at2_flush_buffer(PrivAT2data *privdata)
00549 {
00550 at2_read_buffer(privdata);
00551 octstr_destroy(privdata->ilb);
00552 privdata->ilb = octstr_create("");
00553 }
00554
00555
00556 static int at2_init_device(PrivAT2data *privdata)
00557 {
00558 int ret;
00559 Octstr *setpin;
00560
00561 info(0, "AT2[%s]: init device", octstr_get_cstr(privdata->name));
00562
00563 at2_set_speed(privdata, privdata->speed);
00564
00565 gwthread_sleep(0.10);
00566
00567
00568 if (at2_send_modem_command(privdata, "ATZ", 0, 0) == -1) {
00569 error(0, "AT2[%s]: Wrong or no answer to ATZ, ignoring",
00570 octstr_get_cstr(privdata->name));
00571 }
00572
00573
00574 if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) {
00575 error(0, "AT2[%s]: Wrong or no answer to AT. Trying again",
00576 octstr_get_cstr(privdata->name));
00577 if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) {
00578 error(0, "AT2[%s]: Second attempt to send AT failed",
00579 octstr_get_cstr(privdata->name));
00580 return -1;
00581 }
00582 }
00583
00584 at2_flush_buffer(privdata);
00585
00586 if (at2_send_modem_command(privdata, "AT&F", 7, 0) == -1) {
00587 error(0, "AT2[%s]: No answer to AT&F. Trying again",
00588 octstr_get_cstr(privdata->name));
00589 if (at2_send_modem_command(privdata, "AT&F", 7, 0) == -1) {
00590 return -1;
00591 }
00592 }
00593
00594 at2_flush_buffer(privdata);
00595
00596
00597 if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) {
00598 error(0, "AT2[%s]: Wrong or no answer to ATE0. Trying again",
00599 octstr_get_cstr(privdata->name));
00600 if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) {
00601 error(0, "AT2[%s]: Second attempt to send ATE0 failed",
00602 octstr_get_cstr(privdata->name));
00603 return -1;
00604 }
00605 }
00606
00607 at2_flush_buffer(privdata);
00608
00609
00610
00611 if (octstr_len(privdata->modem->enable_hwhs)) {
00612 if (at2_send_modem_command(privdata,
00613 octstr_get_cstr(privdata->modem->enable_hwhs), 0, 0) == -1)
00614 info(0, "AT2[%s]: cannot enable hardware handshake",
00615 octstr_get_cstr(privdata->name));
00616 }
00617
00618
00619
00620
00621
00622 if (!privdata->modem->no_pin) {
00623 ret = at2_send_modem_command(privdata, "AT+CPIN?", 10, 0);
00624
00625 if (!privdata->pin_ready) {
00626 if (ret == 2) {
00627 if (privdata->pin == NULL)
00628 return -1;
00629 setpin = octstr_format("AT+CPIN=\"%s\"", octstr_get_cstr(privdata->pin));
00630 ret = at2_send_modem_command(privdata, octstr_get_cstr(setpin), 0, 0);
00631 octstr_destroy(setpin);
00632 if (ret != 0 )
00633 return -1;
00634 } else if (ret == -1)
00635 return -1;
00636 }
00637
00638
00639
00640
00641
00642 if (!privdata->pin_ready) {
00643 at2_wait_modem_command(privdata, 10, 0, NULL);
00644 if (!privdata->pin_ready) {
00645 at2_send_modem_command(privdata, "AT+CPIN?", 10, 0);
00646 if (!privdata->pin_ready) {
00647 return -1;
00648 }
00649 }
00650 }
00651 }
00652
00653
00654
00655 if (octstr_len(privdata->sms_center)) {
00656 Octstr *temp;
00657 temp = octstr_create("AT+CSCA=");
00658 octstr_append_char(temp, 34);
00659 octstr_append(temp, privdata->sms_center);
00660 octstr_append_char(temp, 34);
00661
00662
00663
00664
00665 ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
00666 octstr_destroy(temp);
00667 if (ret == -1)
00668 return -1;
00669 if (ret > 0) {
00670 info(0, "AT2[%s]: Cannot set SMS message center, continuing",
00671 octstr_get_cstr(privdata->name));
00672 }
00673 }
00674
00675
00676 ret = at2_send_modem_command(privdata, "AT+CMGF=0", 0, 0);
00677 if (ret != 0 )
00678 return -1;
00679
00680
00681 ret = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
00682 if (ret != 0) {
00683
00684 privdata->phase2plus = 0;
00685 } else {
00686
00687 Octstr *ts;
00688 int i;
00689 List *vals;
00690
00691 ts = privdata->lines;
00692 privdata->lines = NULL;
00693
00694 i = octstr_search_char(ts, '(', 0);
00695 if (i > 0) {
00696 octstr_delete(ts, 0, i + 1);
00697 }
00698 i = octstr_search_char(ts, ')', 0);
00699 if (i > 0) {
00700 octstr_truncate(ts, i);
00701 }
00702 vals = octstr_split(ts, octstr_imm(","));
00703 octstr_destroy(ts);
00704 ts = gwlist_search(vals, octstr_imm("1"), (void*) octstr_item_match);
00705 if (ts)
00706 privdata->phase2plus = 1;
00707 gwlist_destroy(vals, octstr_destroy_item);
00708 }
00709 if (privdata->phase2plus) {
00710 info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name));
00711 ret = at2_send_modem_command(privdata, "AT+CSMS=1", 0, 0);
00712 if (ret != 0)
00713 return -1;
00714 }
00715
00716
00717 ret = at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->init_string), 0, 0);
00718 if (ret != 0)
00719 return -1;
00720
00721 if (privdata->sms_memory_poll_interval && privdata->modem->message_storage) {
00722
00723 if (at2_set_message_storage(privdata, privdata->modem->message_storage) != 0)
00724 return -1;
00725 }
00726
00727 info(0, "AT2[%s]: AT SMSC successfully opened.", octstr_get_cstr(privdata->name));
00728 return 0;
00729 }
00730
00731
00732 static int at2_send_modem_command(PrivAT2data *privdata, char *cmd, time_t timeout, int gt_flag)
00733 {
00734 at2_write_line(privdata, cmd);
00735 return at2_wait_modem_command(privdata, timeout, gt_flag, NULL);
00736 }
00737
00738
00739 static int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag,
00740 int *output)
00741 {
00742 Octstr *line = NULL;
00743 Octstr *line2 = NULL;
00744 Octstr *pdu = NULL;
00745 Octstr *smsc_number = NULL;
00746 int ret;
00747 time_t end_time;
00748 time_t cur_time;
00749 Msg *msg;
00750 int len;
00751 int cmgr_flag = 0;
00752 int expect_extra_ok = 0;
00753
00754 time(&end_time);
00755 if (timeout == 0)
00756 timeout = 3;
00757 end_time += timeout;
00758
00759 if (privdata->lines != NULL)
00760 octstr_destroy(privdata->lines);
00761 privdata->lines = octstr_create("");
00762
00763 smsc_number = octstr_create("");
00764 while (privdata->fd != -1 && time(&cur_time) <= end_time) {
00765 O_DESTROY(line);
00766 if ((line = at2_read_line(privdata, gt_flag))) {
00767 octstr_append(privdata->lines, line);
00768 octstr_append_cstr(privdata->lines, "\n");
00769
00770 if (octstr_search(line, octstr_imm("SIM PIN"), 0) != -1) {
00771 ret = 2;
00772 goto end;
00773 }
00774 if (octstr_search(line, octstr_imm("OK"), 0) != -1) {
00775 if (!expect_extra_ok) {
00776 ret = 0;
00777 goto end;
00778 } else {
00779 --expect_extra_ok;
00780 }
00781 }
00782 if ((gt_flag ) && (octstr_search(line, octstr_imm(">"), 0) != -1)) {
00783 ret = 1;
00784 goto end;
00785 }
00786 if (octstr_search(line, octstr_imm("RING"), 0) != -1) {
00787 at2_write_line(privdata, "ATH0");
00788 continue;
00789 }
00790 if (octstr_search(line, octstr_imm("+CPIN: READY"), 0) != -1) {
00791 privdata->pin_ready = 1;
00792 continue;
00793 }
00794 if (octstr_search(line, octstr_imm("+CMS ERROR"), 0) != -1) {
00795 int errcode;
00796 error(0, "AT2[%s]: CMS ERROR: %s", octstr_get_cstr(privdata->name),
00797 octstr_get_cstr(line));
00798 if (sscanf(octstr_get_cstr(line), "+CMS ERROR: %d", &errcode) == 1)
00799 error(0, "AT2[%s]: CMS ERROR: %s (%d)", octstr_get_cstr(privdata->name),
00800 at2_error_string(errcode), errcode);
00801 ret = 1;
00802 goto end;
00803 }
00804 if (octstr_search(line, octstr_imm("+CMTI:"), 0) != -1 ||
00805 octstr_search(line, octstr_imm("+CDSI:"), 0) != -1) {
00806
00807
00808
00809
00810 debug("bb.smsc.at2", 0, "AT2[%s]: +CMTI incoming SMS indication: %s",
00811 octstr_get_cstr(privdata->name), octstr_get_cstr(line));
00812 gwlist_append(privdata->pending_incoming_messages, line);
00813 line = NULL;
00814 continue;
00815 }
00816 if (octstr_search(line, octstr_imm("+CMT:"), 0) != -1 ||
00817 octstr_search(line, octstr_imm("+CDS:"), 0) != -1 ||
00818 ((octstr_search(line, octstr_imm("+CMGR:"), 0) != -1) && (cmgr_flag = 1)) ) {
00819 line2 = at2_wait_line(privdata, 1, 0);
00820
00821 if (line2 == NULL) {
00822 error(0, "AT2[%s]: got +CMT but waiting for next line timed out",
00823 octstr_get_cstr(privdata->name));
00824 } else {
00825 octstr_append_cstr(line, "\n");
00826 octstr_append(line, line2);
00827 O_DESTROY(line2);
00828 at2_pdu_extract(privdata, &pdu, line, smsc_number);
00829 if (pdu == NULL) {
00830 error(0, "AT2[%s]: got +CMT but pdu_extract failed",
00831 octstr_get_cstr(privdata->name));
00832 } else {
00833
00834 if (output)
00835 ++(*output);
00836 msg = at2_pdu_decode(pdu, privdata);
00837 if (msg != NULL) {
00838 octstr_destroy(msg->sms.smsc_id);
00839 octstr_destroy(msg->sms.smsc_number);
00840 msg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
00841 msg->sms.smsc_number = octstr_duplicate(smsc_number);
00842 bb_smscconn_receive(privdata->conn, msg);
00843 } else {
00844 error(0, "AT2[%s]: could not decode PDU to a message.",
00845 octstr_get_cstr(privdata->name));
00846 }
00847
00848 if (!cmgr_flag) {
00849 if (privdata->phase2plus) {
00850 at2_write_line(privdata, "AT+CNMA");
00851 ++expect_extra_ok;
00852 }
00853 }
00854
00855 O_DESTROY(pdu);
00856 }
00857 }
00858 continue;
00859 }
00860 if ((octstr_search(line, octstr_imm("+CMGS:"),0) != -1) && (output)) {
00861
00862
00863
00864
00865 long temp;
00866 if (octstr_parse_long(&temp, line, octstr_search(line, octstr_imm("+CMGS:"), 0) + 6, 10) == -1)
00867 error(0, "AT2[%s]: Got +CMGS but failed to read message id",
00868 octstr_get_cstr(privdata->name));
00869 else
00870 *output = temp;
00871 }
00872
00873 if (octstr_search(line, octstr_imm("ERROR"), 0) != -1) {
00874 int errcode;
00875 error(0, "AT2[%s]: Generic error: %s", octstr_get_cstr(privdata->name),
00876 octstr_get_cstr(line));
00877 if (sscanf(octstr_get_cstr(line), "ERROR: %d", &errcode) == 1)
00878 error(0, "AT2[%s]: Generic error: %s (%d)", octstr_get_cstr(privdata->name),
00879 at2_error_string(errcode), errcode);
00880 ret = -1;
00881 goto end;
00882 }
00883 }
00884 }
00885
00886 len = octstr_len(privdata->ilb);
00887
00888
00889
00890
00891
00892
00893 O_DESTROY(line);
00894 O_DESTROY(line2);
00895 O_DESTROY(pdu);
00896 O_DESTROY(smsc_number);
00897 return -1;
00898
00899 end:
00900 O_DESTROY(smsc_number);
00901 octstr_append(privdata->lines, line);
00902 octstr_append_cstr(privdata->lines, "\n");
00903 O_DESTROY(line);
00904 O_DESTROY(line2);
00905 O_DESTROY(pdu);
00906 return ret;
00907 }
00908
00909
00910 static int at2_read_delete_message(PrivAT2data* privdata, int message_number)
00911 {
00912 char cmd[20];
00913 int message_count = 0;
00914
00915 sprintf(cmd, "AT+CMGR=%d", message_number);
00916
00917 at2_write_line(privdata, cmd);
00918 if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) {
00919 debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.",
00920 octstr_get_cstr(privdata->name), message_number);
00921 return 0;
00922 }
00923
00924
00925 if (!message_count) {
00926 debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.",
00927 octstr_get_cstr(privdata->name));
00928 return 0;
00929 }
00930
00931 sprintf(cmd, "AT+CMGD=%d", message_number);
00932
00933
00934
00935
00936 if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) {
00937
00938
00939
00940
00941
00942 error(2, "AT2[%s]: failed to delete message %d.",
00943 octstr_get_cstr(privdata->name), message_number);
00944 }
00945
00946 return 1;
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956 static void at2_read_pending_incoming_messages(PrivAT2data *privdata)
00957 {
00958 Octstr *current_storage = NULL;
00959
00960 if (privdata->modem->message_storage) {
00961 current_storage = octstr_duplicate(privdata->modem->message_storage);
00962 }
00963 while (gwlist_len(privdata->pending_incoming_messages) > 0) {
00964 int pos;
00965 long location;
00966 Octstr *cmti_storage = NULL, *line = NULL;
00967
00968 line = gwlist_extract_first(privdata->pending_incoming_messages);
00969
00970 if ((pos = octstr_search_char(line, '"', 0)) != -1) {
00971
00972 int next_quote = octstr_search_char(line, '"', ++pos);
00973 if (next_quote == -1) {
00974 O_DESTROY(line);
00975 continue;
00976 }
00977
00978
00979 cmti_storage = octstr_copy(line, pos, next_quote - pos);
00980 } else
00981
00982
00983 pos = 0;
00984
00985
00986 if (!privdata->modem->message_storage && cmti_storage) {
00987 info(2, "AT2[%s]: CMTI received, but no message-storage is set in confiuration."
00988 "setting now to <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(cmti_storage));
00989 privdata->modem->message_storage = octstr_duplicate(cmti_storage);
00990 current_storage = octstr_duplicate(cmti_storage);
00991 at2_set_message_storage(privdata, cmti_storage);
00992 }
00993
00994
00995 if ((pos = octstr_search_char(line, ',', pos)) == -1) {
00996 error(2, "AT2[%s]: failed to find memory location in CMTI notification",
00997 octstr_get_cstr(privdata->name));
00998 O_DESTROY(line);
00999 octstr_destroy(cmti_storage);
01000 continue;
01001 }
01002
01003 if ((pos = octstr_parse_long(&location, line, ++pos, 10)) == -1) {
01004
01005 error(2, "AT2[%s]: error parsing memory location in CMTI notification",
01006 octstr_get_cstr(privdata->name));
01007 O_DESTROY(line);
01008 octstr_destroy(cmti_storage);
01009 continue;
01010 }
01011
01012
01013 if (!current_storage || (octstr_compare(current_storage, cmti_storage) != 0)) {
01014 octstr_destroy(current_storage);
01015 current_storage = octstr_duplicate(cmti_storage);
01016 at2_set_message_storage(privdata, cmti_storage);
01017 }
01018
01019 if (!at2_read_delete_message(privdata, location)) {
01020 error(1, "AT2[%s]: CMTI notification received, but no message found in memory!",
01021 octstr_get_cstr(privdata->name));
01022 }
01023
01024 octstr_destroy(line);
01025 octstr_destroy(cmti_storage);
01026 }
01027
01028
01029 if (current_storage && privdata->modem->message_storage
01030 && (octstr_compare(privdata->modem->message_storage, current_storage) != 0))
01031 at2_set_message_storage(privdata, privdata->modem->message_storage);
01032
01033 octstr_destroy(current_storage);
01034 }
01035
01036
01037 static int at2_read_sms_memory(PrivAT2data* privdata)
01038 {
01039
01040 if (at2_check_sms_memory(privdata) == -1) {
01041 debug("bb.smsc.at2", 0, "AT2[%s]: memory check error", octstr_get_cstr(privdata->name));
01042 return -1;
01043 }
01044
01045 if (privdata->sms_memory_usage) {
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 int i;
01072 int message_count = 0;
01073
01074 debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory",
01075 octstr_get_cstr(privdata->name), privdata->sms_memory_usage);
01076
01077
01078
01079
01080 for (i = 1; i <= privdata->sms_memory_capacity &&
01081 message_count < privdata->sms_memory_usage; ++i) {
01082
01083
01084
01085 while (gwlist_len(privdata->pending_incoming_messages) > 0) {
01086 at2_read_pending_incoming_messages(privdata);
01087 }
01088
01089 message_count += at2_read_delete_message(privdata, i);
01090 }
01091 }
01092
01093
01094
01095
01096 return 0;
01097 }
01098
01099
01100 static int at2_check_sms_memory(PrivAT2data *privdata)
01101 {
01102 long values[4];
01103 int pos;
01104 int ret;
01105 Octstr *search_cpms = NULL;
01106
01107
01108 if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) {
01109 debug("bb.smsc.at2.memory_check", 0, "failed to send mem select command to modem %d", ret);
01110 return -1;
01111 }
01112
01113 search_cpms = octstr_create("+CPMS:");
01114
01115 if ((pos = octstr_search(privdata->lines, search_cpms, 0)) != -1) {
01116
01117 int index = 0;
01118 pos += 6;
01119
01120
01121 pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1;
01122
01123
01124 while (index < 4 && pos < octstr_len(privdata->lines) &&
01125 (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) {
01126 ++pos;
01127 ++index;
01128 if (index == 2)
01129
01130 pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1;
01131 }
01132
01133 if (index < 4) {
01134
01135 debug("bb.smsc.at2", 0, "AT2[%s]: couldn't parse all memory locations : %d:'%s'.",
01136 octstr_get_cstr(privdata->name), index,
01137 &(octstr_get_cstr(privdata->lines)[pos]));
01138 O_DESTROY(search_cpms);
01139 return -1;
01140 }
01141
01142 privdata->sms_memory_usage = values[0];
01143 privdata->sms_memory_capacity = values[1];
01144
01145
01146
01147
01148
01149
01150 ret = 0;
01151
01152
01153 O_DESTROY(privdata->lines);
01154
01155 } else {
01156 debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.",
01157 octstr_get_cstr(privdata->name));
01158
01159
01160 ret = -1;
01161 }
01162
01163 O_DESTROY(search_cpms);
01164 return ret;
01165 }
01166
01167
01168 static void at2_set_speed(PrivAT2data *privdata, int bps)
01169 {
01170 struct termios tios;
01171 int ret;
01172 int speed;
01173
01174 if (!privdata->is_serial)
01175 return;
01176
01177 tcgetattr(privdata->fd, &tios);
01178
01179 switch (bps) {
01180 case 300:
01181 speed = B300;
01182 break;
01183 case 1200:
01184 speed = B1200;
01185 break;
01186 case 2400:
01187 speed = B2400;
01188 break;
01189 case 4800:
01190 speed = B4800;
01191 break;
01192 case 9600:
01193 speed = B9600;
01194 break;
01195 case 19200:
01196 speed = B19200;
01197 break;
01198 case 38400:
01199 speed = B38400;
01200 break;
01201 #ifdef B57600
01202 case 57600:
01203 speed = B57600;
01204 break;
01205 #endif
01206 #ifdef B115200
01207 case 115200:
01208 speed = B115200;
01209 break;
01210 #endif
01211 default:
01212 speed = B9600;
01213 }
01214
01215 cfsetospeed(&tios, speed);
01216 cfsetispeed(&tios, speed);
01217 ret = tcsetattr(privdata->fd, TCSANOW, &tios);
01218 if (ret == -1) {
01219 error(errno, "AT2[%s]: at_data_link: fail to set termios attribute",
01220 octstr_get_cstr(privdata->name));
01221 }
01222 tcflush(privdata->fd, TCIOFLUSH);
01223
01224 info(0, "AT2[%s]: speed set to %d", octstr_get_cstr(privdata->name), bps);
01225 }
01226
01227
01228 static void at2_device_thread(void *arg)
01229 {
01230 SMSCConn *conn = arg;
01231 PrivAT2data *privdata = conn->data;
01232 int reconnecting = 0, error_count = 0;
01233 long idle_timeout, memory_poll_timeout = 0;
01234
01235 conn->status = SMSCCONN_CONNECTING;
01236
01237
01238 log_thread_to(conn->log_idx);
01239
01240 reconnect:
01241
01242 do {
01243 if (reconnecting) {
01244 if (conn->status == SMSCCONN_ACTIVE) {
01245 mutex_lock(conn->flow_mutex);
01246 conn->status = SMSCCONN_RECONNECTING;
01247 mutex_unlock(conn->flow_mutex);
01248 }
01249 error(0, "AT2[%s]: Couldn't connect (retrying in %ld seconds).",
01250 octstr_get_cstr(privdata->name), conn->reconnect_delay);
01251 gwthread_sleep(conn->reconnect_delay);
01252 reconnecting = 0;
01253 }
01254
01255
01256 if (privdata->speed == 0 && privdata->modem != NULL && privdata->modem->speed != 0) {
01257
01258 info(0, "AT2[%s]: trying to use speed <%ld> from modem definition",
01259 octstr_get_cstr(privdata->name), privdata->modem->speed);
01260 if (at2_test_speed(privdata, privdata->modem->speed) == 0) {
01261 privdata->speed = privdata->modem->speed;
01262 info(0, "AT2[%s]: speed is %ld",
01263 octstr_get_cstr(privdata->name), privdata->speed);
01264 } else {
01265 info(0, "AT2[%s]: speed in modem definition don't work, will autodetect",
01266 octstr_get_cstr(privdata->name));
01267 }
01268 }
01269
01270 if (privdata->speed == 0 && at2_detect_speed(privdata) == -1) {
01271 reconnecting = 1;
01272 continue;
01273 }
01274
01275 if (privdata->modem == NULL && at2_detect_modem_type(privdata) == -1) {
01276 reconnecting = 1;
01277 continue;
01278 }
01279
01280 if (at2_open_device(privdata)) {
01281 error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed.",
01282 octstr_get_cstr(privdata->name));
01283 reconnecting = 1;
01284 continue;
01285 }
01286
01287 if (at2_login_device(privdata)) {
01288 error(errno, "AT2[%s]: at2_device_thread: at2_login_device failed.",
01289 octstr_get_cstr(privdata->name));
01290 reconnecting = 1;
01291 continue;
01292 }
01293
01294 if (privdata->max_error_count > 0 && error_count > privdata->max_error_count
01295 && privdata->modem != NULL && privdata->modem->reset_string != NULL) {
01296 error_count = 0;
01297 if (at2_send_modem_command(privdata,
01298 octstr_get_cstr(privdata->modem->reset_string), 0, 0) != 0) {
01299 error(0, "AT2[%s]: Reset of modem failed.", octstr_get_cstr(privdata->name));
01300 at2_close_device(privdata);
01301 reconnecting = 1;
01302 continue;
01303 } else {
01304 info(0, "AT2[%s]: Modem reseted.", octstr_get_cstr(privdata->name));
01305 }
01306 }
01307
01308 if (at2_init_device(privdata) != 0) {
01309 error(0, "AT2[%s]: Initialization of device failed.", octstr_get_cstr(privdata->name));
01310 at2_close_device(privdata);
01311 error_count++;
01312 reconnecting = 1;
01313 continue;
01314 } else
01315 error_count = 0;
01316
01317
01318 break;
01319 } while (!privdata->shutdown);
01320
01321 mutex_lock(conn->flow_mutex);
01322 conn->status = SMSCCONN_ACTIVE;
01323 conn->connect_time = time(NULL);
01324 mutex_unlock(conn->flow_mutex);
01325 bb_smscconn_connected(conn);
01326
01327 idle_timeout = 0;
01328 while (!privdata->shutdown) {
01329 at2_wait_modem_command(privdata, 1, 0, NULL);
01330
01331
01332 if (privdata->fd == -1) {
01333 reconnecting = 1;
01334 goto reconnect;
01335 }
01336
01337 while (gwlist_len(privdata->pending_incoming_messages) > 0) {
01338 at2_read_pending_incoming_messages(privdata);
01339 }
01340
01341 if (privdata->keepalive &&
01342 idle_timeout + privdata->keepalive < time(NULL)) {
01343 if (at2_send_modem_command(privdata,
01344 octstr_get_cstr(privdata->modem->keepalive_cmd), 5, 0) < 0) {
01345 at2_close_device(privdata);
01346 reconnecting = 1;
01347 goto reconnect;
01348 }
01349 idle_timeout = time(NULL);
01350 }
01351
01352 if (privdata->sms_memory_poll_interval &&
01353 memory_poll_timeout + privdata->sms_memory_poll_interval < time(NULL)) {
01354 if (at2_read_sms_memory(privdata) == -1) {
01355 at2_close_device(privdata);
01356 reconnecting = 1;
01357 goto reconnect;
01358 }
01359 memory_poll_timeout = time(NULL);
01360 }
01361
01362 if (gw_prioqueue_len(privdata->outgoing_queue) > 0) {
01363 at2_send_messages(privdata);
01364 idle_timeout = time(NULL);
01365 }
01366 }
01367 at2_close_device(privdata);
01368 mutex_lock(conn->flow_mutex);
01369 conn->status = SMSCCONN_DISCONNECTED;
01370 mutex_unlock(conn->flow_mutex);
01371
01372 at2_destroy_modem(privdata->modem);
01373 octstr_destroy(privdata->device);
01374 octstr_destroy(privdata->ilb);
01375 octstr_destroy(privdata->lines);
01376 octstr_destroy(privdata->pin);
01377 octstr_destroy(privdata->validityperiod);
01378 octstr_destroy(privdata->my_number);
01379 octstr_destroy(privdata->sms_center);
01380 octstr_destroy(privdata->name);
01381 octstr_destroy(privdata->configfile);
01382 gw_prioqueue_destroy(privdata->outgoing_queue, NULL);
01383 gwlist_destroy(privdata->pending_incoming_messages, octstr_destroy_item);
01384 gw_free(conn->data);
01385 conn->data = NULL;
01386 mutex_lock(conn->flow_mutex);
01387 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01388 conn->status = SMSCCONN_DEAD;
01389 mutex_unlock(conn->flow_mutex);
01390 bb_smscconn_killed();
01391 }
01392
01393
01394 static int at2_shutdown_cb(SMSCConn *conn, int finish_sending)
01395 {
01396 PrivAT2data *privdata = conn->data;
01397
01398 debug("bb.sms", 0, "AT2[%s]: Shutting down SMSCConn, %s",
01399 octstr_get_cstr(privdata->name),
01400 finish_sending ? "slow" : "instant");
01401
01402
01403
01404
01405
01406 conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01407 privdata->shutdown = 1;
01408
01409
01410
01411
01412 if (finish_sending == 0) {
01413 Msg *msg;
01414 while ((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL) {
01415 bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
01416 }
01417 }
01418 gwthread_wakeup(privdata->device_thread);
01419 return 0;
01420
01421 }
01422
01423
01424 static long at2_queued_cb(SMSCConn *conn)
01425 {
01426 long ret;
01427 PrivAT2data *privdata = conn->data;
01428
01429 if (conn->status == SMSCCONN_DEAD)
01430 return -1;
01431
01432 ret = gw_prioqueue_len(privdata->outgoing_queue);
01433
01434
01435 conn->load = ret;
01436 return ret;
01437 }
01438
01439
01440 static void at2_start_cb(SMSCConn *conn)
01441 {
01442 PrivAT2data *privdata = conn->data;
01443
01444 if (conn->status == SMSCCONN_DISCONNECTED)
01445 conn->status = SMSCCONN_ACTIVE;
01446
01447
01448 gwthread_wakeup(privdata->device_thread);
01449 debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name));
01450 }
01451
01452 static int at2_add_msg_cb(SMSCConn *conn, Msg *sms)
01453 {
01454 PrivAT2data *privdata = conn->data;
01455 Msg *copy;
01456
01457 copy = msg_duplicate(sms);
01458 gw_prioqueue_produce(privdata->outgoing_queue, copy);
01459 gwthread_wakeup(privdata->device_thread);
01460 return 0;
01461 }
01462
01463
01464 int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg)
01465 {
01466 PrivAT2data *privdata;
01467 Octstr *modem_type_string;
01468 long portno;
01469
01470 privdata = gw_malloc(sizeof(PrivAT2data));
01471 privdata->outgoing_queue = gw_prioqueue_create(sms_priority_compare);
01472 privdata->pending_incoming_messages = gwlist_create();
01473
01474 privdata->configfile = cfg_get_configfile(cfg);
01475
01476 privdata->device = cfg_get(cfg, octstr_imm("device"));
01477 if (privdata->device == NULL) {
01478 error(0, "AT2[-]: 'device' missing in at2 configuration.");
01479 goto error;
01480 }
01481
01482 if (octstr_str_compare(privdata->device, "rawtcp") == 0) {
01483 privdata->rawtcp_host = cfg_get(cfg, octstr_imm("host"));
01484 if (privdata->rawtcp_host == NULL) {
01485 error(0, "AT2[-]: 'host' missing in at2 rawtcp configuration.");
01486 goto error;
01487 }
01488 if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
01489 error(0, "AT2[-]: 'port' missing in at2 rawtcp configuration.");
01490 goto error;
01491 }
01492 privdata->rawtcp_port = portno;
01493 privdata->is_serial = 0;
01494 privdata->use_telnet = 0;
01495 }
01496 else if (octstr_str_compare(privdata->device, "telnet") == 0) {
01497 privdata->rawtcp_host = cfg_get(cfg, octstr_imm("host"));
01498 if (privdata->rawtcp_host == NULL) {
01499 error(0, "AT2[-]: 'host' missing in at2 telnet configuration.");
01500 goto error;
01501 }
01502 if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
01503 error(0, "AT2[-]: 'port' missing in at2 telnet configuration.");
01504 goto error;
01505 }
01506 privdata->rawtcp_port = portno;
01507 privdata->is_serial = 0;
01508 privdata->use_telnet = 1;
01509 }else {
01510 privdata->is_serial = 1;
01511 privdata->use_telnet = 0;
01512 }
01513
01514 privdata->name = cfg_get(cfg, octstr_imm("smsc-id"));
01515 if (privdata->name == NULL) {
01516 privdata->name = octstr_duplicate(privdata->device);
01517 }
01518
01519 privdata->speed = 0;
01520 cfg_get_integer(&privdata->speed, cfg, octstr_imm("speed"));
01521
01522 privdata->keepalive = 0;
01523 cfg_get_integer(&privdata->keepalive, cfg, octstr_imm("keepalive"));
01524
01525 cfg_get_bool(&privdata->sms_memory_poll_interval, cfg, octstr_imm("sim-buffering"));
01526 if (privdata->sms_memory_poll_interval) {
01527 if (privdata->keepalive)
01528 privdata->sms_memory_poll_interval = privdata->keepalive;
01529 else
01530 privdata->sms_memory_poll_interval = AT2_DEFAULT_SMS_POLL_INTERVAL;
01531 }
01532
01533 privdata->my_number = cfg_get(cfg, octstr_imm("my-number"));
01534 privdata->sms_center = cfg_get(cfg, octstr_imm("sms-center"));
01535 privdata->username = cfg_get(cfg, octstr_imm("smsc-username"));
01536 privdata->password = cfg_get(cfg, octstr_imm("smsc-password"));
01537 privdata->login_prompt = cfg_get(cfg, octstr_imm("login-prompt"));
01538 privdata->password_prompt = cfg_get(cfg, octstr_imm("password-prompt"));
01539 modem_type_string = cfg_get(cfg, octstr_imm("modemtype"));
01540
01541 privdata->modem = NULL;
01542
01543 if (modem_type_string != NULL) {
01544 if (octstr_compare(modem_type_string, octstr_imm("auto")) == 0 ||
01545 octstr_compare(modem_type_string, octstr_imm("autodetect")) == 0)
01546 O_DESTROY(modem_type_string);
01547 }
01548
01549 if (octstr_len(modem_type_string) == 0) {
01550 info(0, "AT2[%s]: configuration doesn't show modemtype. will autodetect",
01551 octstr_get_cstr(privdata->name));
01552 } else {
01553 info(0, "AT2[%s]: configuration shows modemtype <%s>",
01554 octstr_get_cstr(privdata->name),
01555 octstr_get_cstr(modem_type_string));
01556 privdata->modem = at2_read_modems(privdata, privdata->configfile,
01557 modem_type_string, 0);
01558 if (privdata->modem == NULL) {
01559 info(0, "AT2[%s]: modemtype not found, revert to autodetect",
01560 octstr_get_cstr(privdata->name));
01561 } else {
01562 info(0, "AT2[%s]: read modem definition for <%s>",
01563 octstr_get_cstr(privdata->name),
01564 octstr_get_cstr(privdata->modem->name));
01565 }
01566 O_DESTROY(modem_type_string);
01567 }
01568
01569 privdata->ilb = octstr_create("");
01570 privdata->fd = -1;
01571 privdata->lines = NULL;
01572 privdata->pin = cfg_get(cfg, octstr_imm("pin"));
01573 privdata->pin_ready = 0;
01574 privdata->conn = conn;
01575 privdata->phase2plus = 0;
01576 privdata->validityperiod = cfg_get(cfg, octstr_imm("validityperiod"));
01577 if (cfg_get_integer((long *) &privdata->max_error_count, cfg, octstr_imm("max-error-count")) == -1)
01578 privdata->max_error_count = -1;
01579
01580 conn->data = privdata;
01581 conn->name = octstr_format("AT2[%s]", octstr_get_cstr(privdata->name));
01582 conn->status = SMSCCONN_CONNECTING;
01583
01584 privdata->shutdown = 0;
01585
01586 conn->status = SMSCCONN_CONNECTING;
01587 conn->connect_time = time(NULL);
01588
01589 if ((privdata->device_thread = gwthread_create(at2_device_thread, conn)) == -1) {
01590 privdata->shutdown = 1;
01591 goto error;
01592 }
01593
01594 conn->shutdown = at2_shutdown_cb;
01595 conn->queued = at2_queued_cb;
01596 conn->start_conn = at2_start_cb;
01597 conn->send_msg = at2_add_msg_cb;
01598 return 0;
01599
01600 error:
01601 error(0, "AT2[%s]: Failed to create at2 smsc connection",
01602 octstr_len(privdata->name) ? octstr_get_cstr(privdata->name) : "");
01603 if (privdata != NULL) {
01604 gw_prioqueue_destroy(privdata->outgoing_queue, NULL);
01605 }
01606 gw_free(privdata);
01607 conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
01608 conn->status = SMSCCONN_DEAD;
01609 info(0, "AT2[%s]: exiting", octstr_get_cstr(privdata->name));
01610 return -1;
01611 }
01612
01613
01614 static int at2_pdu_extract(PrivAT2data *privdata, Octstr **pdu, Octstr *line, Octstr *smsc_number)
01615 {
01616 Octstr *buffer;
01617 long len = 0;
01618 int pos = 0;
01619 int tmp;
01620 Octstr *numtmp;
01621 Octstr *tmp2;
01622
01623 buffer = octstr_duplicate(line);
01624
01625
01626 if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1)
01627 pos += 5;
01628 else {
01629 if ((pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) != -1)
01630 pos += 5;
01631 else if ((pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) != -1) {
01632
01633 if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1)
01634 pos++;
01635 else
01636 goto nomsg;
01637 } else
01638 goto nomsg;
01639
01640
01641 tmp = octstr_search(buffer, octstr_imm(","), pos);
01642 if (!privdata->modem->broken && tmp == -1)
01643 goto nomsg;
01644 if (tmp != -1)
01645 pos = tmp + 1;
01646 }
01647
01648
01649 pos = octstr_parse_long(&len, buffer, pos, 10);
01650 if (pos == -1)
01651 goto nomsg;
01652
01653
01654 while (isspace(octstr_get_char(buffer, pos)))
01655 pos++;
01656
01657 octstr_truncate(smsc_number,0);
01658
01659
01660 if (!privdata->modem->no_smsc) {
01661 tmp = at2_hexchar(octstr_get_char(buffer, pos)) * 16
01662 + at2_hexchar(octstr_get_char(buffer, pos + 1));
01663 if (tmp < 0)
01664 goto nomsg;
01665
01666 numtmp = octstr_create_from_data(octstr_get_cstr(buffer)+pos+2,tmp * 2);
01667 octstr_hex_to_binary(numtmp);
01668 tmp2 = gsm2number(numtmp);
01669 debug("bb.smsc.at2", 0, "AT2[%s]: received message from SMSC: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(tmp2));
01670 octstr_destroy(numtmp);
01671 octstr_append(smsc_number,tmp2);
01672 octstr_destroy(tmp2);
01673 pos += 2 + tmp * 2;
01674 }
01675
01676
01677 if (!privdata->modem->broken && octstr_len(buffer) < len * 2 + pos)
01678 goto nomsg;
01679
01680 if (privdata->modem->broken && octstr_len(buffer) < len * 2)
01681 goto nomsg;
01682
01683
01684 *pdu = octstr_copy(buffer, pos, len * 2);
01685
01686 octstr_destroy(buffer);
01687 return 1;
01688
01689 nomsg:
01690 octstr_destroy(buffer);
01691 return 0;
01692 }
01693
01694 static unsigned char nibble2hex(unsigned char b)
01695 {
01696 if(b < 0x0A)
01697 return '0'+ b;
01698 else
01699 return 'A'+ b - 0x0A;
01700 }
01701
01702 static Octstr *gsm2number(Octstr *pdu)
01703 {
01704 Octstr *tmp = NULL;
01705 unsigned char c;
01706 unsigned char a;
01707 unsigned char b;
01708 int ton;
01709 int npi;
01710 int len;
01711 int pos;
01712
01713 pos=0;
01714 len = octstr_len(pdu);
01715 if(len<= 0)
01716 return octstr_create("");
01717
01718 ton = octstr_get_char(pdu,pos++);
01719 npi = ton & 0x0F;
01720 ton = (ton >> 4) & 0x07;
01721
01722 switch(ton)
01723 {
01724 case 0:
01725 tmp = octstr_create("");
01726 break;
01727 case 1:
01728 tmp = octstr_create("+");
01729 break;
01730 case 2:
01731 tmp = octstr_create("0");
01732 break;
01733 case 3:
01734 default:
01735 tmp = octstr_create("");
01736 break;
01737 }
01738 while(--len > 0)
01739 {
01740 c = octstr_get_char(pdu,pos++);
01741 a = c & 0x0F;
01742 b = ((c & 0xF0) >> 4);
01743
01744 if((b == 0x0F) && (len < 2))
01745 {
01746 octstr_append_char(tmp, nibble2hex(a));
01747 }
01748 else
01749 {
01750 octstr_append_char(tmp, nibble2hex(a));
01751 octstr_append_char(tmp, nibble2hex(b));
01752 }
01753 }
01754 return tmp;
01755 }
01756
01757 static int at2_hexchar(int hexc)
01758 {
01759 hexc = toupper(hexc) - 48;
01760 return (hexc > 9) ? hexc - 7 : hexc;
01761 }
01762
01763
01764 static Msg *at2_pdu_decode(Octstr *data, PrivAT2data *privdata)
01765 {
01766 int type;
01767 Msg *msg = NULL;
01768
01769
01770 type = octstr_get_char(data, 1) & 3;
01771
01772 switch (type) {
01773
01774 case AT_DELIVER_SM:
01775 msg = at2_pdu_decode_deliver_sm(data, privdata);
01776 break;
01777 case AT_STATUS_REPORT_SM:
01778 msg = at2_pdu_decode_report_sm(data, privdata);
01779 break;
01780
01781
01782 }
01783
01784 return msg;
01785 }
01786
01787
01788 static Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata)
01789 {
01790 int len, pos, i, ntype;
01791 int udhi, dcs, udhlen, pid;
01792 Octstr *origin = NULL;
01793 Octstr *udh = NULL;
01794 Octstr *text = NULL, *tmpstr;
01795 Octstr *pdu = NULL;
01796 Msg *message = NULL;
01797 struct universaltime mtime;
01798 long stime;
01799 int timezone;
01800
01801
01802
01803
01804
01805
01806
01807 pdu = at2_convertpdu(data);
01808
01809
01810 udhi = (octstr_get_char(pdu, 0) & 64) >> 6;
01811
01812
01813 len = octstr_get_char(pdu, 1);
01814 if (len > 20)
01815 goto msg_error;
01816 ntype = octstr_get_char(pdu, 2);
01817
01818 pos = 3;
01819 if ((ntype & 0xD0) == 0xD0) {
01820
01821 origin = octstr_create("");
01822 tmpstr = octstr_copy(pdu, 3, len);
01823 at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0);
01824 octstr_destroy(tmpstr);
01825 debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>",
01826 octstr_get_cstr(privdata->name), octstr_get_cstr(origin));
01827 pos += (len + 1) / 2;
01828 } else {
01829 origin = octstr_create("");
01830 if ((ntype & 0x90) == 0x90) {
01831
01832 octstr_append_char(origin, '+');
01833 }
01834 for (i = 0; i < len; i += 2, pos++) {
01835 octstr_append_char(origin, (octstr_get_char(pdu, pos) & 15) + 48);
01836 if (i + 1 < len)
01837 octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48);
01838 }
01839 debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>",
01840 octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""),
01841 octstr_get_cstr(origin));
01842 }
01843
01844 if (pos > octstr_len(pdu))
01845 goto msg_error;
01846
01847
01848 pid = octstr_get_char(pdu, pos);
01849 pos++;
01850
01851
01852 dcs = octstr_get_char(pdu, pos);
01853 pos++;
01854
01855
01856 mtime.year = swap_nibbles(octstr_get_char(pdu, pos));
01857 pos++;
01858 mtime.year += (mtime.year < 70 ? 2000 : 1900);
01859 mtime.month = swap_nibbles(octstr_get_char(pdu, pos));
01860 mtime.month--;
01861 pos++;
01862 mtime.day = swap_nibbles(octstr_get_char(pdu, pos));
01863 pos++;
01864 mtime.hour = swap_nibbles(octstr_get_char(pdu, pos));
01865 pos++;
01866 mtime.minute = swap_nibbles(octstr_get_char(pdu, pos));
01867 pos++;
01868 mtime.second = swap_nibbles(octstr_get_char(pdu, pos));
01869 pos++;
01870
01871
01872
01873
01874
01875
01876 timezone = swap_nibbles(octstr_get_char(pdu, pos));
01877 pos++;
01878 timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127);
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890 mtime.hour -= timezone / 4;
01891 mtime.minute -= 15 * (timezone % 4);
01892
01893 stime = date_convert_universal(&mtime);
01894
01895
01896
01897
01898 len = octstr_get_char(pdu, pos);
01899 pos++;
01900
01901 debug("bb.smsc.at2", 0, "AT2[%s]: User data length read as (%d)",
01902 octstr_get_cstr(privdata->name), len);
01903
01904
01905 udhlen = 0;
01906 if (udhi && len > 0) {
01907 udhlen = octstr_get_char(pdu, pos);
01908 pos++;
01909 if (udhlen + 1 > len)
01910 goto msg_error;
01911 udh = octstr_copy(pdu, pos-1, udhlen+1);
01912 pos += udhlen;
01913 len -= udhlen + 1;
01914 } else if (len <= 0)
01915 udhi = 0;
01916
01917 debug("bb.smsc.at2", 0, "AT2[%s]: Udh decoding done len=%d udhi=%d udhlen=%d udh='%s'",
01918 octstr_get_cstr(privdata->name), len, udhi, udhlen, (udh ? octstr_get_cstr(udh) : ""));
01919
01920 if (pos > octstr_len(pdu) || len < 0)
01921 goto msg_error;
01922
01923
01924 message = msg_create(sms);
01925 if (!dcs_to_fields(&message, dcs)) {
01926
01927 debug("bb.smsc.at2", 0, "AT2[%s]: Invalid DCS", octstr_get_cstr(privdata->name));
01928 dcs_to_fields(&message, 0);
01929 }
01930
01931 message->sms.pid = pid;
01932
01933
01934 tmpstr = octstr_copy(pdu, pos, len);
01935 if (message->sms.coding == DC_8BIT || message->sms.coding == DC_UCS2) {
01936 text = octstr_duplicate(tmpstr);
01937 } else {
01938 int offset = 0;
01939 text = octstr_create("");
01940 if (udhi && message->sms.coding == DC_7BIT) {
01941 int nbits;
01942 nbits = (udhlen + 1) * 8;
01943
01944 offset = (((nbits / 7) + 1) * 7 - nbits) % 7;
01945 }
01946 at2_decode7bituncompressed(tmpstr, len, text, offset);
01947 }
01948
01949 message->sms.sender = origin;
01950 if (octstr_len(privdata->my_number)) {
01951 message->sms.receiver = octstr_duplicate(privdata->my_number);
01952 } else {
01953
01954 message->sms.receiver = octstr_create_from_data("1234", 4);
01955 }
01956 if (udhi) {
01957 message->sms.udhdata = udh;
01958 }
01959 message->sms.msgdata = text;
01960 message->sms.time = stime;
01961
01962
01963 octstr_destroy(pdu);
01964 octstr_destroy(tmpstr);
01965
01966 return message;
01967
01968 msg_error:
01969 error(1, "AT2[%s]: Invalid DELIVER-SMS pdu!", octstr_get_cstr(privdata->name));
01970 O_DESTROY(udh);
01971 O_DESTROY(origin);
01972 O_DESTROY(text);
01973 O_DESTROY(pdu);
01974 return NULL;
01975 }
01976
01977
01978 static Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata)
01979 {
01980 Msg *dlrmsg = NULL;
01981 Octstr *pdu, *msg_id, *tmpstr = NULL, *receiver = NULL;
01982 int type, tp_mr, len, ntype, pos;
01983
01984
01985
01986
01987
01988
01989 pdu = at2_convertpdu(data);
01990
01991
01992 tp_mr = octstr_get_char(pdu, 1);
01993 msg_id = octstr_format("%d", tp_mr);
01994 debug("bb.smsc.at2", 0, "AT2[%s]: got STATUS-REPORT for message <%d>:",
01995 octstr_get_cstr(privdata->name), tp_mr);
01996
01997
01998 len = octstr_get_char(pdu, 2);
01999 ntype = octstr_get_char(pdu, 3);
02000
02001 pos = 4;
02002 if ((ntype & 0xD0) == 0xD0) {
02003
02004 receiver = octstr_create("");
02005 tmpstr = octstr_copy(pdu, pos, (len + 1) / 2);
02006 at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, receiver, 0);
02007 octstr_destroy(tmpstr);
02008 debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric receiver <%s>",
02009 octstr_get_cstr(privdata->name), octstr_get_cstr(receiver));
02010 pos += (len + 1) / 2;
02011 } else {
02012 int i;
02013 receiver = octstr_create("");
02014 if ((ntype & 0x90) == 0x90) {
02015
02016 octstr_append_char(receiver, '+');
02017 }
02018 for (i = 0; i < len; i += 2, pos++) {
02019 octstr_append_char(receiver, (octstr_get_char(pdu, pos) & 15) + 48);
02020 if (i + 1 < len)
02021 octstr_append_char(receiver, (octstr_get_char(pdu, pos) >> 4) + 48);
02022 }
02023 debug("bb.smsc.at2", 0, "AT2[%s]: Numeric receiver %s <%s>",
02024 octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""),
02025 octstr_get_cstr(receiver));
02026 }
02027
02028 pos += 14;
02029
02030 if ((type = octstr_get_char(pdu, pos)) == -1 ) {
02031 error(1, "AT2[%s]: STATUS-REPORT pdu too short to have TP-Status field !",
02032 octstr_get_cstr(privdata->name));
02033 goto error;
02034 }
02035
02036
02037
02038
02039
02040
02041
02042
02043 type = type & 0xE0;
02044 switch (type) {
02045 case 0x00:
02046
02047 type = DLR_SUCCESS;
02048 tmpstr = octstr_create("Success");
02049 break;
02050 case 0x20:
02051
02052 type = DLR_BUFFERED;
02053 tmpstr = octstr_create("Buffered");
02054 break;
02055 case 0x40:
02056 case 0x60:
02057 default:
02058
02059
02060
02061 type = DLR_FAIL;
02062 tmpstr = octstr_create("Failed");
02063 break;
02064 }
02065
02066
02067
02068
02069
02070
02071 if ((dlrmsg = dlr_find(privdata->conn->id, msg_id, receiver, type)) == NULL) {
02072 debug("bb.smsc.at2", 1, "AT2[%s]: Received delivery notification but can't find that ID in the DLR storage",
02073 octstr_get_cstr(privdata->name));
02074 goto error;
02075 }
02076
02077
02078 dlrmsg->sms.msgdata = octstr_duplicate(tmpstr);
02079
02080 error:
02081 O_DESTROY(tmpstr);
02082 O_DESTROY(pdu);
02083 O_DESTROY(receiver);
02084 O_DESTROY(msg_id);
02085 return dlrmsg;
02086 }
02087
02088 static Octstr *at2_convertpdu(Octstr *pdutext)
02089 {
02090 Octstr *pdu;
02091 int i;
02092 int len = octstr_len(pdutext);
02093
02094 pdu = octstr_create("");
02095 for (i = 0; i < len; i += 2) {
02096 octstr_append_char(pdu, at2_hexchar(octstr_get_char(pdutext, i)) * 16
02097 + at2_hexchar(octstr_get_char(pdutext, i + 1)));
02098 }
02099 return pdu;
02100 }
02101
02102
02103 static int at2_rmask[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
02104 static int at2_lmask[8] = { 0, 128, 192, 224, 240, 248, 252, 254 };
02105
02106 static void at2_decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset)
02107 {
02108 unsigned char septet, octet, prevoctet;
02109 int i;
02110 int r = 1;
02111 int c = 7;
02112 int pos = 0;
02113
02114
02115 if (offset > 0) {
02116 unsigned char *ip;
02117 for (i = 0, ip = (unsigned char *)octstr_get_cstr(input); i < octstr_len(input); i++) {
02118 if (i == octstr_len(input) - 1)
02119 *ip = *ip >> offset;
02120 else
02121 *ip = (*ip >> offset) | (*(ip + 1) << (8 - offset));
02122 ip++;
02123 }
02124 }
02125 octet = octstr_get_char(input, pos);
02126 prevoctet = 0;
02127 for (i = 0; i < len; i++) {
02128 septet = ((octet & at2_rmask[c]) << (r - 1)) + prevoctet;
02129 octstr_append_char(decoded, septet);
02130
02131 prevoctet = (octet & at2_lmask[r]) >> c;
02132
02133
02134 if ((r == 7) && (i < len - 1)) {
02135 i++;
02136 octstr_append_char(decoded, prevoctet);
02137 prevoctet = 0;
02138 }
02139
02140 r = (r > 6) ? 1 : r + 1;
02141 c = (c < 2) ? 7 : c - 1;
02142
02143 pos++;
02144 octet = octstr_get_char(input, pos);
02145 }
02146 charset_gsm_to_utf8(decoded);
02147 }
02148
02149
02150 static void at2_send_messages(PrivAT2data *privdata)
02151 {
02152 Msg *msg;
02153
02154 if (privdata->modem->enable_mms &&
02155 gw_prioqueue_len(privdata->outgoing_queue) > 1)
02156 at2_send_modem_command(privdata, "AT+CMMS=2", 0, 0);
02157
02158 if ((msg = gw_prioqueue_remove(privdata->outgoing_queue)))
02159 at2_send_one_message(privdata, msg);
02160 }
02161
02162
02163 static void at2_send_one_message(PrivAT2data *privdata, Msg *msg)
02164 {
02165 char command[500];
02166 int ret = -1;
02167 char sc[3];
02168
02169 if (octstr_len(privdata->my_number)) {
02170 octstr_destroy(msg->sms.sender);
02171 msg->sms.sender = octstr_duplicate(privdata->my_number);
02172 }
02173
02174
02175
02176
02177
02178
02179
02180 sc[0] = '\0';
02181
02182 if (!privdata->modem->no_smsc)
02183 strcpy(sc, "00");
02184
02185 if (msg_type(msg) == sms) {
02186 Octstr *pdu;
02187
02188 if ((pdu = at2_pdu_encode(msg, privdata)) == NULL) {
02189 error(2, "AT2[%s]: Error encoding PDU!",octstr_get_cstr(privdata->name));
02190 return;
02191 }
02192
02193 int msg_id = -1;
02194
02195
02196
02197 sprintf(command, "AT+CMGS=%ld", octstr_len(pdu) / 2);
02198
02199 ret = at2_send_modem_command(privdata, command, 5, 1);
02200 debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d",
02201 octstr_get_cstr(privdata->name), ret);
02202
02203 if (ret == 1) {
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216 if (octstr_compare(privdata->modem->id, octstr_imm("nokiaphone")) != 0) {
02217
02218 sprintf(command, "%s%s", sc, octstr_get_cstr(pdu));
02219 at2_write(privdata, command);
02220 at2_write_ctrlz(privdata);
02221
02222 } else {
02223
02224
02225 sprintf(command, "%s%s%c", sc, octstr_get_cstr(pdu), 0x1A);
02226
02227
02228
02229 if (strlen(command) > 18) {
02230 char chop[20];
02231 int len = strlen(command);
02232 int pos = 0;
02233 int ret = 18;
02234
02235 while (pos < len) {
02236 if (pos + ret > len)
02237 ret = len - pos;
02238 memcpy(chop, command + pos, ret);
02239 pos += ret;
02240 chop[ret] = '\0';
02241 at2_write(privdata, chop);
02242 gwthread_sleep((double) 10/1000);
02243 }
02244 } else {
02245 at2_write(privdata, command);
02246 }
02247 }
02248
02249
02250 ret = at2_wait_modem_command(privdata, 20, 0, &msg_id);
02251 debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d",
02252 octstr_get_cstr(privdata->name), ret);
02253
02254 if (ret != 0) {
02255 bb_smscconn_send_failed(privdata->conn, msg,
02256 SMSCCONN_FAILED_TEMPORARILY, octstr_create("ERROR"));
02257 }else{
02258
02259 if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) {
02260 if (msg_id == -1)
02261 error(0,"AT2[%s]: delivery notification requested, but I have no message ID!",
02262 octstr_get_cstr(privdata->name));
02263 else {
02264 Octstr *dlrmsgid = octstr_format("%d", msg_id);
02265
02266 dlr_add(privdata->conn->id, dlrmsgid, msg);
02267
02268 O_DESTROY(dlrmsgid);
02269
02270 }
02271 }
02272
02273 bb_smscconn_sent(privdata->conn, msg, NULL);
02274 }
02275 }
02276 O_DESTROY(pdu);
02277 }
02278 }
02279
02280
02281 static Octstr *at2_pdu_encode(Msg *msg, PrivAT2data *privdata)
02282 {
02283
02284
02285
02286
02287 Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create("");
02288 int len, setvalidity = 0;
02289
02290
02291
02292
02293
02294
02295 octstr_append_char(buffer,
02296 ((msg->sms.rpi > 0 ? 1 : 0) << 7)
02297 | ((octstr_len(msg->sms.udhdata) ? 1 : 0) << 6)
02298 | ((DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask) ? 1 : 0) << 5)
02299 | 16
02300 | 1
02301 );
02302
02303
02304 octstr_append_char(buffer, 0);
02305
02306
02307 if ((temp = at2_format_address_field(msg->sms.receiver)) == NULL)
02308 goto error;
02309 octstr_append(buffer, temp);
02310 O_DESTROY(temp);
02311
02312 octstr_append_char(buffer, (msg->sms.pid == -1 ? 0 : msg->sms.pid) );
02313 octstr_append_char(buffer, fields_to_dcs(msg,
02314 (msg->sms.alt_dcs != -1 ? msg->sms.alt_dcs : privdata->conn->alt_dcs)));
02315
02316
02317
02318
02319
02320
02321 if (msg->sms.validity >= 0) {
02322 if (msg->sms.validity > 635040)
02323 setvalidity = 255;
02324 if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040)
02325 setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1;
02326 if (msg->sms.validity > 43200 && msg->sms.validity < 50400)
02327 setvalidity = 197;
02328 if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200)
02329 setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1;
02330 if (msg->sms.validity > 1440 && msg->sms.validity < 2880)
02331 setvalidity = 168;
02332 if (msg->sms.validity >= 750 && msg->sms.validity <= 1440)
02333 setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1;
02334 if (msg->sms.validity > 720 && msg->sms.validity < 750)
02335 setvalidity = 144;
02336 if (msg->sms.validity >= 5 && msg->sms.validity <= 720)
02337 setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1;
02338 if (msg->sms.validity < 5)
02339 setvalidity = 0;
02340 } else
02341 setvalidity = (privdata->validityperiod != NULL ?
02342 atoi(octstr_get_cstr(privdata->validityperiod)) : 167);
02343
02344 if (setvalidity >= 0 && setvalidity <= 143)
02345 debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d minutes",
02346 octstr_get_cstr(privdata->name), (setvalidity + 1)*5);
02347 else if (setvalidity >= 144 && setvalidity <= 167)
02348 debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %3.1f hours",
02349 octstr_get_cstr(privdata->name), ((float)(setvalidity - 143) / 2) + 12);
02350 else if (setvalidity >= 168 && setvalidity <= 196)
02351 debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d days",
02352 octstr_get_cstr(privdata->name), (setvalidity - 166));
02353 else
02354 debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d weeks",
02355 octstr_get_cstr(privdata->name), (setvalidity - 192));
02356 octstr_append_char(buffer, setvalidity);
02357
02358
02359 len = sms_msgdata_len(msg);
02360
02361 if (octstr_len(msg->sms.udhdata)) {
02362 if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
02363 len += octstr_len(msg->sms.udhdata);
02364 if (len > SMS_8BIT_MAX_LEN) {
02365 octstr_delete(msg->sms.msgdata, SMS_8BIT_MAX_LEN - octstr_len(msg->sms.udhdata), 9999);
02366 len = SMS_8BIT_MAX_LEN;
02367 }
02368 } else {
02369
02370
02371
02372
02373
02374
02375 int temp_len;
02376 len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7));
02377 if (len > SMS_7BIT_MAX_LEN) {
02378 octstr_delete(msg->sms.msgdata, SMS_7BIT_MAX_LEN - temp_len, 9999);
02379 len = SMS_7BIT_MAX_LEN;
02380 }
02381 }
02382 }
02383
02384 octstr_append_char(buffer,len);
02385
02386 if (octstr_len(msg->sms.udhdata))
02387 octstr_append(buffer, msg->sms.udhdata);
02388
02389
02390 if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
02391 octstr_append(buffer, msg->sms.msgdata);
02392 } else {
02393 int offset = 0;
02394
02395
02396
02397
02398
02399 if (octstr_len(msg->sms.udhdata)) {
02400 int nbits = octstr_len(msg->sms.udhdata) * 8;
02401 offset = (((nbits / 7) + 1) * 7 - nbits) % 7;
02402 }
02403
02404 charset_utf8_to_gsm(msg->sms.msgdata);
02405
02406 if ((temp = at2_encode7bituncompressed(msg->sms.msgdata, offset)) != NULL)
02407 octstr_append(buffer, temp);
02408 O_DESTROY(temp);
02409 }
02410
02411
02412 pdu = at2_encode8bituncompressed(buffer);
02413 O_DESTROY(buffer);
02414
02415 return pdu;
02416
02417 error:
02418 O_DESTROY(temp);
02419 O_DESTROY(buffer);
02420 O_DESTROY(pdu);
02421 return NULL;
02422 }
02423
02424
02425 static Octstr *at2_encode7bituncompressed(Octstr *source, int offset)
02426 {
02427 int LSBmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
02428 int MSBmask[8] = { 0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x7E, 0x7F };
02429 int destRemain = (int)ceil ((octstr_len(source) * 7.0) / 8.0);
02430 int i = (offset?8-offset:7), iStore = offset;
02431 int posT, posS;
02432 Octstr *target = octstr_create("");
02433 int target_chr = 0, source_chr;
02434
02435
02436 for (posS = 0, posT = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) {
02437
02438
02439 target_chr |= (source_chr & LSBmask[i]) << iStore;
02440
02441 if (iStore != 0) {
02442 destRemain--;
02443 octstr_append_char(target, target_chr);
02444 target_chr = 0;
02445 }
02446
02447
02448 target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8;
02449
02450 iStore = (--iStore < 0 ? 7 : iStore);
02451
02452 if (iStore != 0)
02453 i = (++i > 7 ? 1 : i);
02454 }
02455
02456
02457 if (destRemain > 0)
02458 octstr_append_char(target, target_chr);
02459
02460 return target;
02461 }
02462
02463
02464 static Octstr *at2_encode8bituncompressed(Octstr *input)
02465 {
02466 int len, i;
02467 Octstr *out = octstr_create("");
02468
02469 len = octstr_len(input);
02470
02471 for (i = 0; i < len; i++) {
02472
02473 octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0xF0) >> 4));
02474 octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0x0F)));
02475 }
02476 return out;
02477 }
02478
02479
02480 static int at2_numtext(int num)
02481 {
02482 return (num > 9) ? (num + 55) : (num + 48);
02483 }
02484
02485
02486 static int at2_detect_speed(PrivAT2data *privdata)
02487 {
02488 int i;
02489 int autospeeds[] = {
02490 #ifdef B115200
02491 115200,
02492 #endif
02493 #ifdef B57600
02494 57600,
02495 #endif
02496 38400, 19200, 9600 };
02497
02498 debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ",
02499 octstr_get_cstr(privdata->name));
02500
02501 for (i = 0; i < (sizeof(autospeeds) / sizeof(int)); i++) {
02502 if(at2_test_speed(privdata, autospeeds[i]) == 0) {
02503 privdata->speed = autospeeds[i];
02504 break;
02505 }
02506 }
02507 if (privdata->speed == 0) {
02508 info(0, "AT2[%s]: cannot detect speed", octstr_get_cstr(privdata->name));
02509 return -1;
02510 }
02511 info(0, "AT2[%s]: detect speed is %ld", octstr_get_cstr(privdata->name), privdata->speed);
02512 return 0;
02513 }
02514
02515
02516 static int at2_test_speed(PrivAT2data *privdata, long speed)
02517 {
02518 int res;
02519
02520 if (at2_open_device(privdata) == -1)
02521 return -1;
02522
02523 at2_read_buffer(privdata);
02524 at2_set_speed(privdata, speed);
02525
02526 res = at2_send_modem_command(privdata, "", 1, 0);
02527 res = at2_send_modem_command(privdata, "AT", 0, 0);
02528
02529 if (res != 0)
02530 res = at2_send_modem_command(privdata, "AT", 0, 0);
02531 if (res != 0)
02532 res = at2_send_modem_command(privdata, "AT", 0, 0);
02533
02534 at2_close_device(privdata);
02535
02536 return res;
02537 }
02538
02539
02540 static int at2_detect_modem_type(PrivAT2data *privdata)
02541 {
02542 int res;
02543 ModemDef *modem;
02544 int i;
02545
02546 debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem type", octstr_get_cstr(privdata->name));
02547
02548 if (at2_open_device(privdata) == -1)
02549 return -1;
02550
02551 at2_set_speed(privdata, privdata->speed);
02552
02553 res = at2_send_modem_command(privdata, "", 1, 0);
02554 res = at2_send_modem_command(privdata, "AT", 0, 0);
02555
02556 if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1)
02557 return -1;
02558 if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1)
02559 return -1;
02560
02561 at2_flush_buffer(privdata);
02562
02563 if (at2_send_modem_command(privdata, "ATI", 0, 0) == -1)
02564 return -1;
02565
02566
02567 i = 1;
02568 while ((modem = at2_read_modems(privdata, privdata->configfile, NULL, i++)) != NULL) {
02569
02570 if (octstr_len(modem->detect_string) == 0) {
02571 at2_destroy_modem(modem);
02572 continue;
02573 }
02574
02575
02576
02577
02578
02579
02580 if (octstr_search(privdata->lines, modem->detect_string, 0) != -1) {
02581 if (octstr_len(modem->detect_string2) == 0) {
02582 debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>",
02583 octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string),
02584 octstr_get_cstr(modem->name));
02585 privdata->modem = modem;
02586 break;
02587 } else {
02588 if (octstr_search(privdata->lines, modem->detect_string2, 0) != -1) {
02589 debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s> plus <%s>, using modem "
02590 "definition <%s>", octstr_get_cstr(privdata->name),
02591 octstr_get_cstr(modem->detect_string),
02592 octstr_get_cstr(modem->detect_string2),
02593 octstr_get_cstr(modem->name));
02594 privdata->modem = modem;
02595 break;
02596 }
02597 }
02598 } else {
02599
02600 at2_destroy_modem(modem);
02601 }
02602 }
02603
02604 if (privdata->modem == NULL) {
02605 debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic",
02606 octstr_get_cstr(privdata->name));
02607 if ((modem = at2_read_modems(privdata, privdata->configfile, octstr_imm("generic"), 0)) == NULL) {
02608 panic(0, "AT2[%s]: Cannot detect modem and generic not found",
02609 octstr_get_cstr(privdata->name));
02610 } else {
02611 privdata->modem = modem;
02612 }
02613 }
02614
02615
02616 res = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
02617 if (res != 0)
02618
02619 privdata->phase2plus = 0;
02620 else {
02621
02622 Octstr *ts;
02623 int i;
02624 List *vals;
02625
02626 ts = privdata->lines;
02627 privdata->lines = NULL;
02628
02629 i = octstr_search_char(ts, '(', 0);
02630 if (i > 0) {
02631 octstr_delete(ts, 0, i + 1);
02632 }
02633 i = octstr_search_char(ts, ')', 0);
02634 if (i > 0) {
02635 octstr_truncate(ts, i);
02636 }
02637 vals = octstr_split(ts, octstr_imm(","));
02638 octstr_destroy(ts);
02639 ts = gwlist_search(vals, octstr_imm("1"), (void*) octstr_item_match);
02640 if (ts)
02641 privdata->phase2plus = 1;
02642 gwlist_destroy(vals, octstr_destroy_item);
02643 }
02644 if (privdata->phase2plus)
02645 info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name));
02646 at2_close_device(privdata);
02647 return 0;
02648 }
02649
02650
02651 static ModemDef *at2_read_modems(PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber)
02652 {
02653 Cfg *cfg;
02654 List *grplist;
02655 CfgGroup *grp;
02656 Octstr *p;
02657 ModemDef *modem;
02658 int i = 1;
02659
02660
02661
02662
02663 if (octstr_len(id) == 0 && idnumber == 0)
02664 return NULL;
02665
02666 if (idnumber == 0)
02667 debug("bb.smsc.at2", 0, "AT2[%s]: Reading modem definitions from <%s>",
02668 octstr_get_cstr(privdata->name), octstr_get_cstr(file));
02669 cfg = cfg_create(file);
02670
02671 if (cfg_read(cfg) == -1)
02672 panic(0, "Cannot read modem definition file");
02673
02674 grplist = cfg_get_multi_group(cfg, octstr_imm("modems"));
02675 if (idnumber == 0)
02676 debug("bb.smsc.at2", 0, "AT2[%s]: Found <%ld> modems in config",
02677 octstr_get_cstr(privdata->name), gwlist_len(grplist));
02678
02679 if (grplist == NULL)
02680 panic(0, "Where are the modem definitions ?!?!");
02681
02682 grp = NULL;
02683 while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
02684 p = cfg_get(grp, octstr_imm("id"));
02685 if (p == NULL) {
02686 info(0, "Modems group without id, bad");
02687 continue;
02688 }
02689
02690 if (octstr_len(id) != 0 && octstr_compare(p, id) == 0) {
02691 O_DESTROY(p);
02692 break;
02693 }
02694
02695 if (octstr_len(id) == 0 && idnumber == i) {
02696 O_DESTROY(p);
02697 break;
02698 }
02699 O_DESTROY(p);
02700 i++;
02701 grp = NULL;
02702 }
02703 if (grplist != NULL)
02704 gwlist_destroy(grplist, NULL);
02705
02706 if (grp != NULL) {
02707 modem = gw_malloc(sizeof(ModemDef));
02708
02709 modem->id = cfg_get(grp, octstr_imm("id"));
02710
02711 modem->name = cfg_get(grp, octstr_imm("name"));
02712 if (modem->name == NULL)
02713 modem->name = octstr_duplicate(modem->id);
02714
02715 modem->detect_string = cfg_get(grp, octstr_imm("detect-string"));
02716 modem->detect_string2 = cfg_get(grp, octstr_imm("detect-string2"));
02717
02718 modem->init_string = cfg_get(grp, octstr_imm("init-string"));
02719 if (modem->init_string == NULL)
02720 modem->init_string = octstr_create("AT+CNMI=1,2,0,1,0");
02721
02722 modem->reset_string = cfg_get(grp, octstr_imm("reset-string"));
02723
02724 modem->speed = 9600;
02725 cfg_get_integer(&modem->speed, grp, octstr_imm("speed"));
02726
02727 cfg_get_bool(&modem->need_sleep, grp, octstr_imm("need-sleep"));
02728
02729 modem->enable_hwhs = cfg_get(grp, octstr_imm("enable-hwhs"));
02730 if (modem->enable_hwhs == NULL)
02731 modem->enable_hwhs = octstr_create("AT+IFC=2,2");
02732
02733 cfg_get_bool(&modem->no_pin, grp, octstr_imm("no-pin"));
02734
02735 cfg_get_bool(&modem->no_smsc, grp, octstr_imm("no-smsc"));
02736
02737 modem->sendline_sleep = 100;
02738 cfg_get_integer(&modem->sendline_sleep, grp, octstr_imm("sendline-sleep"));
02739
02740 modem->keepalive_cmd = cfg_get(grp, octstr_imm("keepalive-cmd"));
02741 if (modem->keepalive_cmd == NULL)
02742 modem->keepalive_cmd = octstr_create("AT");
02743
02744 modem->message_storage = cfg_get(grp, octstr_imm("message-storage"));
02745
02746 cfg_get_bool(&modem->enable_mms, grp, octstr_imm("enable-mms"));
02747
02748
02749
02750
02751
02752
02753 cfg_get_bool(&modem->broken, grp, octstr_imm("broken"));
02754
02755 cfg_destroy(cfg);
02756 return modem;
02757
02758 } else {
02759 cfg_destroy(cfg);
02760 return NULL;
02761 }
02762 }
02763
02764
02765 static void at2_destroy_modem(ModemDef *modem)
02766 {
02767 if (modem != NULL) {
02768 O_DESTROY(modem->id);
02769 O_DESTROY(modem->name);
02770 O_DESTROY(modem->detect_string);
02771 O_DESTROY(modem->detect_string2);
02772 O_DESTROY(modem->init_string);
02773 O_DESTROY(modem->enable_hwhs);
02774 O_DESTROY(modem->keepalive_cmd);
02775 O_DESTROY(modem->message_storage);
02776 O_DESTROY(modem->reset_string);
02777 gw_free(modem);
02778 }
02779 }
02780
02781
02782 static int swap_nibbles(unsigned char byte)
02783 {
02784 return ( ( byte & 15 ) * 10 ) + ( byte >> 4 );
02785 }
02786
02787
02788 static Octstr *at2_format_address_field(Octstr *msisdn)
02789 {
02790 int ntype = PNT_UNKNOWN;
02791 Octstr *out = octstr_create("");
02792 Octstr *temp = octstr_duplicate(msisdn);
02793
02794 octstr_strip_blanks(temp);
02795
02796
02797
02798
02799
02800 if (strncmp(octstr_get_cstr(msisdn), "+", 1) == 0) {
02801 octstr_delete(temp, 0, 1);
02802 ntype = PNT_INTER;
02803 } else if (strncmp(octstr_get_cstr(msisdn), "00", 2) == 0) {
02804 octstr_delete(temp, 0, 2);
02805 ntype = PNT_INTER;
02806 }
02807
02808
02809 octstr_append_char(out, octstr_len(temp));
02810
02811
02812 octstr_append_char(out, 0x80 |
02813 0x01 |
02814 (ntype == PNT_INTER ? 0x10 : 0x00)
02815 );
02816
02817
02818 while (out != NULL && octstr_len(temp) > 0) {
02819 int digit1, digit2;
02820
02821 digit1 = octstr_get_char(temp,0) - 48;
02822 digit2 = octstr_get_char(temp,1) - '0';
02823 if (digit2 < 0)
02824 digit2 = 0x0F;
02825 if(digit1 >= 0 && digit1 < 16 && digit2 < 16) {
02826 octstr_append_char(out, (digit2 << 4) | digit1);
02827 }
02828 else {
02829 O_DESTROY(out);
02830 out = NULL;
02831 }
02832 octstr_delete(temp, 0, 2);
02833 }
02834
02835 O_DESTROY(temp);
02836 return out;
02837 }
02838
02839
02840 static int at2_set_message_storage(PrivAT2data *privdata, Octstr *memory_name)
02841 {
02842 Octstr *temp;
02843 int ret;
02844
02845 if (!memory_name || !privdata)
02846 return -1;
02847
02848 temp = octstr_format("AT+CPMS=\"%S\"", memory_name);
02849 ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
02850 octstr_destroy(temp);
02851
02852 return !ret ? 0 : -1;
02853 }
02854
02855
02856 static const char *at2_error_string(int code)
02857 {
02858 switch (code) {
02859 case 8:
02860 return "Operator determined barring";
02861 case 10:
02862 return "Call barred";
02863 case 21:
02864 return "Short message transfer rejected";
02865 case 27:
02866 return "Destination out of service";
02867 case 28:
02868 return "Unidentified subscriber";
02869 case 29:
02870 return "Facility rejected";
02871 case 30:
02872 return "Unknown subscriber";
02873 case 38:
02874 return "Network out of order";
02875 case 41:
02876 return "Temporary failure";
02877 case 42:
02878 return "Congestion";
02879 case 47:
02880 return "Resources unavailable, unspecified";
02881 case 50:
02882 return "Requested facility not subscribed";
02883 case 69:
02884 return "Requested facility not implemented";
02885 case 81:
02886 return "Invalid short message transfer reference value";
02887 case 95:
02888 return "Invalid message, unspecified";
02889 case 96:
02890 return "Invalid mandatory information";
02891 case 97:
02892 return "Message type non-existent or not implemented";
02893 case 98:
02894 return "Message not compatible with short message protocol state";
02895 case 99:
02896 return "Information element non-existent or not implemented";
02897 case 111:
02898 return "Protocol error, unspecified";
02899 case 127:
02900 return "Interworking, unspecified";
02901 case 128:
02902 return "Telematic interworking not supported";
02903 case 129:
02904 return "Short message Type 0 not supported";
02905 case 130:
02906 return "Cannot replace short message";
02907 case 143:
02908 return "Unspecified TP-PID error";
02909 case 144:
02910 return "Data coding scheme (alphabet not supported";
02911 case 145:
02912 return "Message class not supported";
02913 case 159:
02914 return "Unspecified TP-DCS error";
02915 case 160:
02916 return "Command cannot be actioned";
02917 case 161:
02918 return "Command unsupported";
02919 case 175:
02920 return "Unspecified TP-Command error";
02921 case 176:
02922 return "TPDU not supported";
02923 case 192:
02924 return "SC busy";
02925 case 193:
02926 return "No SC subscription";
02927 case 194:
02928 return "SC system failure";
02929 case 195:
02930 return "Invalid SME address";
02931 case 196:
02932 return "Destination SME barred";
02933 case 197:
02934 return "SM Rejected-Duplicate SM";
02935 case 198:
02936 return "TP-VPF not supported";
02937 case 199:
02938 return "TP-VP not supported";
02939 case 208:
02940 return "D0 SIM SMS storage full";
02941 case 209:
02942 return "No SMS storage capability in SIM";
02943 case 210:
02944 return "Error in MS";
02945 case 211:
02946 return "D0 SIM SMS storage full";
02947 case 212:
02948 return "SIM Application Toolkit Busy";
02949 case 213:
02950 return "SIM data download error";
02951 case 255:
02952 return "Unspecified error cause";
02953 case 300:
02954 return "ME failure";
02955 case 301:
02956 return "SMS service of ME reserved";
02957 case 302:
02958 return "Operation not allowed";
02959 case 303:
02960 return "Operation not supported";
02961 case 304:
02962 return "Invalid PDU mode parameter";
02963 case 305:
02964 return "Invalid text mode parameter";
02965 case 310:
02966 return "SIM not inserted";
02967 case 311:
02968 return "SIM PIN required";
02969 case 312:
02970 return "PH-SIM PIN required";
02971 case 313:
02972 return "SIM failure";
02973 case 314:
02974 return "SIM busy";
02975 case 315:
02976 return "SIM wrong";
02977 case 316:
02978 return "SIM PUK required";
02979 case 317:
02980 return "SIM PIN2 required";
02981 case 318:
02982 return "SIM PUK2 required";
02983 case 320:
02984 return "Memory failure";
02985 case 321:
02986 return "Invalid memory index -> don't worry, just memory fragmentation.";
02987 case 322:
02988 return "Memory full";
02989 case 330:
02990 return "SMSC address unknown";
02991 case 331:
02992 return "No network service";
02993 case 332:
02994 return "Network timeout";
02995 case 340:
02996 return "NO +CNMA ACK EXPECTED";
02997 case 500:
02998 return "Unknown error. -> maybe Sim storage is full? I'll have a look at it.";
02999 case 512:
03000 return "User abort";
03001 default:
03002 return "Error number unknown. Ask google and add it.";
03003 }
03004 }
03005
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.