smsc_at2.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:70k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * smsc_at2.c
  3.  * 
  4.  * New driver for serial connected AT based
  5.  * devices.
  6.  * 4.9.2001
  7.  * Andreas Fink <afink@smsrelay.com>
  8.  * 
  9.  */
  10. #include <errno.h>
  11. #include <stdarg.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <fcntl.h>
  17. #include <ctype.h>
  18. #include <termios.h>
  19. #include <sys/time.h>
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <netdb.h>
  24. #include <sys/ioctl.h>
  25. #include <time.h>
  26. #include <math.h>
  27. #include "gwlib/gwlib.h"
  28. #include "gwlib/charset.h"
  29. #include "smscconn.h"
  30. #include "smscconn_p.h"
  31. #include "bb_smscconn_cb.h"
  32. #include "msg.h"
  33. #include "sms.h"
  34. #include "dlr.h"
  35. #include "smsc_at2.h"
  36. static int at2_open_device1(PrivAT2data *privdata)
  37. {
  38.     info(0, "AT2[%s]: opening device", octstr_get_cstr(privdata->name));
  39.     privdata->fd = open(octstr_get_cstr(privdata->device), 
  40.                         O_RDWR | O_NONBLOCK | O_NOCTTY);
  41.     if (privdata->fd == -1) {
  42.         error(errno, "AT2[%s]: open failed! ERRNO=%d", octstr_get_cstr(privdata->name), errno);
  43.         privdata->fd = -1;
  44.         return -1;
  45.     }
  46.     debug("bb.smsc.at2", 0, "AT2[%s]: device opened", octstr_get_cstr(privdata->name));
  47.     return 0;
  48. }
  49. int at2_open_device(PrivAT2data *privdata)
  50. {
  51.     struct termios tios;
  52.     int ret;
  53.     if ((ret = at2_open_device1(privdata)) != 0)
  54.         return ret;
  55.     tcgetattr(privdata->fd, &tios);
  56.     kannel_cfmakeraw(&tios);
  57.                       
  58.     tios.c_iflag |= IGNBRK; /* ignore break & parity errors */
  59.     tios.c_iflag &= ~INPCK; /* INPCK: disable parity check */
  60.     tios.c_cflag |= HUPCL; /* hangup on close */
  61.     tios.c_cflag |= CREAD; /* enable receiver */
  62.     tios.c_cflag &= ~CSIZE; /* set to 8 bit */
  63.     tios.c_cflag |= CS8;
  64.     tios.c_oflag &= ~ONLCR; /* no NL to CR-NL mapping outgoing */
  65.     tios.c_iflag |= IGNPAR; /* ignore parity */
  66.     tios.c_iflag &= ~INPCK;
  67.     tios.c_cflag |= CRTSCTS; /* enable hardware flow control */
  68.     tios.c_cc[VSUSP] = 0; /* otherwhise we can not send CTRL Z */
  69.     /*
  70.     if ( ModemTypes[privdata->modemid].enable_parity )
  71.      tios.c_cflag ^= PARODD;
  72.     */
  73.     ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */
  74.     if (ret == -1) {
  75.         error(errno, "AT2[%s]: at_data_link: fail to set termios attribute",
  76.               octstr_get_cstr(privdata->name));
  77.     }
  78.     tcflush(privdata->fd, TCIOFLUSH);
  79.          
  80.     /* 
  81.      * Nokia 7110 and 6210 need some time between opening
  82.      * the connection and sending the first AT commands 
  83.      */
  84.     if (privdata->modem->need_sleep)
  85.         sleep(1);
  86.     debug("bb.smsc.at2", 0, "AT2[%s]: device opened", octstr_get_cstr(privdata->name));
  87.     return 0;
  88. }
  89. void at2_close_device(PrivAT2data *privdata)
  90. {
  91.     info(0, "AT2[%s]: closing device", octstr_get_cstr(privdata->name));
  92.     close(privdata->fd);
  93.     privdata->fd = -1;
  94. }
  95. void at2_read_buffer(PrivAT2data *privdata)
  96. {
  97.     char buf[MAX_READ + 1];
  98.     int s, ret;
  99.     int count;
  100.     fd_set read_fd;
  101.     struct timeval tv;
  102.     if (privdata->fd == -1) {
  103.         error(errno, "AT2[%s]: at2_read_buffer: fd = -1. Can not read", 
  104.               octstr_get_cstr(privdata->name));
  105.         return ;
  106.     }
  107.     count = MAX_READ;
  108. #ifdef SSIZE_MAX
  109.     if (count > SSIZE_MAX)
  110.         count = SSIZE_MAX;
  111. #endif
  112.     tv.tv_sec = 0;
  113.     tv.tv_usec = 1000;
  114.     FD_ZERO(&read_fd);
  115.     FD_SET(privdata->fd, &read_fd);
  116.     ret = select(privdata->fd + 1, &read_fd, NULL, NULL, &tv);
  117.     if (ret == -1) {
  118.         if (!(errno == EINTR || errno == EAGAIN))
  119.             error(errno, "AT2[%s]: error on select", octstr_get_cstr(privdata->name));
  120.         return;
  121.     }
  122.     s = read(privdata->fd, buf, count);
  123.     if (s > 0)
  124.         octstr_append_data(privdata->ilb, buf, s);
  125. }
  126. Octstr *at2_wait_line(PrivAT2data *privdata, time_t timeout, int gt_flag)
  127. {
  128.     Octstr *line;
  129.     time_t end_time;
  130.     time_t cur_time;
  131.     time(&end_time);
  132.     if (timeout == 0)
  133.         timeout = 3;
  134.     end_time += timeout;
  135.     if (privdata->lines != NULL)
  136.         octstr_destroy(privdata->lines);
  137.     privdata->lines = octstr_create("");
  138.     while (time(&cur_time) <= end_time) {
  139.         line = at2_read_line(privdata, gt_flag);
  140.         if (line)
  141.             return line;
  142.     }
  143.     return NULL;
  144. }
  145. Octstr *at2_read_line(PrivAT2data *privdata, int gt_flag)
  146. {
  147.     int eol;
  148.     int gtloc;
  149.     int len;
  150.     Octstr *line;
  151.     Octstr *buf2;
  152.     int i;
  153.     at2_read_buffer(privdata);
  154.     len = octstr_len(privdata->ilb);
  155.     if (len == 0)
  156.         return NULL;
  157.     if (gt_flag)
  158.         /* looking for > if needed */
  159.         gtloc = octstr_search_char(privdata->ilb, '>', 0); 
  160.     else
  161.         gtloc = -1;
  162.     /*   
  163.     if (gt_flag && (gtloc != -1))
  164.         debug("bb.smsc.at2", 0, "in at2_read_line with gt_flag=1, gtloc=%d, ilb=%s",
  165.               gtloc, octstr_get_cstr(privdata->ilb));
  166.     */
  167.     eol = octstr_search_char(privdata->ilb, 'r', 0); /* looking for CR */
  168.     if ( (gtloc != -1) && ( (eol == -1) || (eol > gtloc) ) )
  169.         eol = gtloc;
  170.     if (eol == -1)
  171.         return NULL;
  172.     line = octstr_copy(privdata->ilb, 0, eol);
  173.     buf2 = octstr_copy(privdata->ilb, eol + 1, len);
  174.     octstr_destroy(privdata->ilb);
  175.     privdata->ilb = buf2;
  176.     /* remove any non printable chars (including linefeed for example) */
  177.     for (i = 0; i < octstr_len(line); i++) {
  178.         if (octstr_get_char(line, i) < 32)
  179.             octstr_set_char(line, i, ' ');
  180.     }
  181.     octstr_strip_blanks(line);
  182.     /* empty line, skipping */
  183.     if ((strcmp(octstr_get_cstr(line), "") == 0) && ( gt_flag == 0)) 
  184.     {
  185.         octstr_destroy(line);
  186.         return NULL;
  187.     }
  188.     if ((gt_flag) && (gtloc != -1)) {
  189.         /* got to re-add it again as the parser needs to see it */
  190.         octstr_append_cstr(line, ">"); 
  191.     }
  192.     debug("bb.smsc.at2", 0, "AT2[%s]: <-- %s", octstr_get_cstr(privdata->name), 
  193.           octstr_get_cstr(line));
  194.     return line;
  195. }
  196. int at2_write_line(PrivAT2data *privdata, char *line)
  197. {
  198.     int count;
  199.     int s = 0;
  200.     int write_count = 0;
  201.     Octstr *linestr = NULL;
  202.     linestr = octstr_format("%sr", line);
  203.     debug("bb.smsc.at2", 0, "AT2[%s]: --> %s^M", octstr_get_cstr(privdata->name), line);
  204.     count = octstr_len(linestr);
  205.     while (1) {
  206. errno = 0;
  207. s = write(privdata->fd, octstr_get_cstr(linestr), count);
  208. if (s < 0 && errno == EAGAIN && write_count < RETRY_SEND) {
  209.     gwthread_sleep(1);
  210.     ++write_count;
  211. } else
  212.     break;
  213.     };
  214.     O_DESTROY(linestr);
  215.     if (s < 0) {
  216.         debug("bb.smsc.at2", 0, "AT2[%s]: write failed with errno %d", 
  217.               octstr_get_cstr(privdata->name), errno);
  218.         return s;
  219.     }
  220.     tcdrain(privdata->fd);
  221.     gwthread_sleep((double) (privdata->modem == NULL ? 
  222.         100 : privdata->modem->sendline_sleep) / 1000);
  223.     return s;
  224. }
  225. int at2_write_ctrlz(PrivAT2data *privdata)
  226. {
  227.     int s;
  228.     char *ctrlz = "32" ;
  229.     int write_count = 0;
  230.     
  231.     debug("bb.smsc.at2", 0, "AT2[%s]: --> ^Z", octstr_get_cstr(privdata->name));
  232.     while (1) {
  233. errno = 0;
  234. s = write(privdata->fd, ctrlz, 1);
  235. if (s < 0 && errno == EAGAIN && write_count < RETRY_SEND) {
  236.     gwthread_sleep(1);
  237.     ++write_count;
  238. } else
  239.     break;
  240.     };
  241.     if (s < 0) {
  242.         debug("bb.smsc.at2", 0, "AT2[%s]: write failed with errno %d", 
  243.               octstr_get_cstr(privdata->name), errno);
  244.         return s;
  245.     }
  246.     tcdrain(privdata->fd);
  247.     gwthread_sleep((double) privdata->modem->sendline_sleep / 1000);
  248.     return s;
  249. }
  250.       
  251. int at2_write(PrivAT2data *privdata, char *line)
  252. {
  253.     int count;
  254.     int s;
  255.     count = strlen(line);
  256.     debug("bb.smsc.at2", 0, "AT2[%s]: --> %s", octstr_get_cstr(privdata->name), line);
  257.     s = write(privdata->fd, line, count);
  258.     tcdrain(privdata->fd);
  259.     return s;
  260. }
  261. void at2_flush_buffer(PrivAT2data *privdata)
  262. {
  263.     at2_read_buffer(privdata);
  264.     octstr_destroy(privdata->ilb);
  265.     privdata->ilb = octstr_create("");
  266. }
  267. int at2_init_device(PrivAT2data *privdata)
  268. {
  269.     int res;
  270.     int ret;
  271.     Octstr *setpin;
  272.     info(0, "AT2[%s]: init device", octstr_get_cstr(privdata->name));
  273.     at2_set_speed(privdata, privdata->speed);
  274.     res = at2_send_modem_command(privdata, "AT", 0, 0);
  275.     if (res == -1) {
  276.         /* 
  277.          * first try failed, maybe we need another one 
  278.          * after just having changed the speed 
  279.          */
  280.         res = at2_send_modem_command(privdata, "AT", 0, 0);
  281.     }
  282.     if (res == -1) {
  283.         error(0, "AT2[%s]: no answer from modem", octstr_get_cstr(privdata->name));
  284.         return -1;
  285.     }
  286.     at2_flush_buffer(privdata);
  287.     if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1)
  288.         return -1;
  289.     if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1)
  290.         return -1;
  291.     at2_flush_buffer(privdata);
  292.     /* enable hardware handshake */
  293.     if (octstr_len(privdata->modem->enable_hwhs)) {
  294.         if (at2_send_modem_command(privdata, 
  295.             octstr_get_cstr(privdata->modem->enable_hwhs), 0, 0) == -1)
  296.             info(0, "AT2[%s]: cannot enable hardware handshake", 
  297.                  octstr_get_cstr(privdata->name));
  298.     }
  299.     /*
  300.      * Check does the modem require a PIN and, if so, send it.
  301.      * This is not supported by the Nokia Premicell 
  302.      */
  303.     if (!privdata->modem->no_pin) {
  304.         ret = at2_send_modem_command(privdata, "AT+CPIN?", 10, 0);
  305.         if (!privdata->pin_ready) {
  306.             if (ret == 2) {
  307.                 if (privdata->pin == NULL)
  308.                     return -1;
  309.                 setpin = octstr_format("AT+CPIN=%s", octstr_get_cstr(privdata->pin));
  310.                 ret = at2_send_modem_command(privdata, octstr_get_cstr(setpin), 0, 0);
  311.                 octstr_destroy(setpin);
  312.                 if (ret != 0 )
  313.                     return -1;
  314.             } else if (ret == -1)
  315.                 return -1;
  316.         }
  317.         /* 
  318.          * we have to wait until +CPIN: READY appears before issuing
  319.          * the next command. 10 sec should be suficient 
  320.          */
  321.         if (!privdata->pin_ready) {
  322.             at2_wait_modem_command(privdata, 10, 0, NULL);
  323.             if (!privdata->pin_ready) {
  324.                 at2_send_modem_command(privdata, "AT+CPIN?", 10, 0);
  325.                 if (!privdata->pin_ready) {
  326.                     return -1; /* give up */
  327.                 }
  328.             }
  329.         }
  330.     }
  331.     /* 
  332.      * Set the GSM SMS message center address if supplied 
  333.      */
  334.     if (octstr_len(privdata->sms_center)) {
  335.         Octstr *temp;
  336.         temp = octstr_create("AT+CSCA=");
  337.         octstr_append_char(temp, 34);
  338.         octstr_append(temp, privdata->sms_center);
  339.         octstr_append_char(temp, 34);
  340.         /* 
  341.          * XXX If some modem don't process the +, remove it and add ",145"
  342.          * and ",129" to national numbers
  343.          */
  344.         ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
  345.         octstr_destroy(temp);
  346.         if (ret == -1)
  347.             return -1;
  348.         if (ret > 0) {
  349.             info(0, "AT2[%s]: Cannot set SMS message center, continuing", 
  350.                  octstr_get_cstr(privdata->name));
  351.         }
  352.     }
  353.     /* Set the modem to PDU mode and autodisplay of new messages */
  354.     ret = at2_send_modem_command(privdata, "AT+CMGF=0", 0, 0);
  355.     if (ret != 0 )
  356.         return -1;
  357.     /* lets see if it supports GSM SMS 2+ mode */
  358.     ret = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
  359.     if (ret != 0) {
  360.         /* if it doesnt even understand the command, I'm sure it wont support it */
  361.         privdata->phase2plus = 0; 
  362.     } else {
  363.         /* we have to take a part a string like +CSMS: (0,1,128) */
  364.         Octstr *ts;
  365.         int i;
  366.         List *vals;
  367.         ts = privdata->lines;
  368.         privdata->lines = NULL;
  369.         i = octstr_search_char(ts, '(', 0);
  370.         if (i > 0) {
  371.             octstr_delete(ts, 0, i + 1);
  372.         }
  373.         i = octstr_search_char(ts, ')', 0);
  374.         if (i > 0) {
  375.             octstr_truncate(ts, i);
  376.         }
  377.         vals = octstr_split(ts, octstr_imm(","));
  378.         octstr_destroy(ts);
  379.         ts = list_search(vals, octstr_imm("1"), (void*) octstr_item_match);
  380.         if (ts)
  381.             privdata->phase2plus = 1;
  382.         list_destroy(vals, octstr_destroy_item);
  383.     }
  384.     if (privdata->phase2plus) {
  385.         info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name));
  386.         ret = at2_send_modem_command(privdata, "AT+CSMS=1", 0, 0);
  387.         if (ret != 0)
  388.             return -1;
  389.     }
  390.     /* send init string */
  391.     ret = at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->init_string), 0, 0);
  392.     if (ret != 0)
  393.         return -1;
  394.     if (privdata->sms_memory_poll_interval && privdata->modem->message_storage) {
  395.         /* set message storage location for "SIM buffering" using the CPMS command */
  396.         Octstr *temp;
  397.         temp = octstr_create("AT+CPMS=");
  398.         octstr_append_char(temp, 34);
  399.         octstr_append(temp, privdata->modem->message_storage);
  400.         octstr_append_char(temp, 34);
  401.         ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
  402.         octstr_destroy(temp);
  403.         if (ret != 0)
  404.             return -1;
  405.     }
  406.     info(0, "AT2[%s]: AT SMSC successfully opened.", octstr_get_cstr(privdata->name));
  407.     return 0;
  408. }
  409. int at2_send_modem_command(PrivAT2data *privdata, char *cmd, time_t timeout, int gt_flag)
  410. {
  411.     at2_write_line(privdata, cmd);
  412.     return at2_wait_modem_command(privdata, timeout, gt_flag, NULL);
  413. }
  414. int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag, 
  415.                            int *output)
  416. {
  417.     Octstr *line = NULL;
  418.     Octstr *line2 = NULL;
  419.     Octstr *pdu = NULL;
  420.     int ret;
  421.     time_t end_time;
  422.     time_t cur_time;
  423.     Msg *msg;
  424.     int len;
  425.     int cmgr_flag = 0;
  426.     time(&end_time);
  427.     if (timeout == 0)
  428.         timeout = 3;
  429.     end_time += timeout;
  430.     if (privdata->lines != NULL)
  431.         octstr_destroy(privdata->lines);
  432.     privdata->lines = octstr_create("");
  433.     while (time(&cur_time) <= end_time) {
  434.         O_DESTROY(line);
  435.         line = at2_read_line(privdata, gt_flag);
  436.         if (line) {
  437.             octstr_append(privdata->lines, line);
  438.             octstr_append_cstr(privdata->lines, "n");
  439.             if (octstr_search(line, octstr_imm("SIM PIN"), 0) != -1) {
  440.                 ret = 2;
  441.                 goto end;
  442.             }
  443.             if (octstr_search(line, octstr_imm("OK"), 0) != -1) {
  444.                 ret = 0;
  445.                 goto end;
  446.             }
  447.             if ((gt_flag ) && (octstr_search(line, octstr_imm(">"), 0) != -1)) {
  448.                 ret = 1;
  449.                 goto end;
  450.             }
  451.             if (octstr_search(line, octstr_imm("RING"), 0) != -1) {
  452.                 at2_write_line(privdata, "ATH0");
  453.                 continue;
  454.             }
  455.             if (octstr_search(line, octstr_imm("+CPIN: READY"), 0) != -1) {
  456.                 privdata->pin_ready = 1;
  457.                 continue;
  458.             }
  459.             if ( -1 != octstr_search(line, octstr_imm("+CMS ERROR"), 0)) {
  460.                 error(0, "AT2[%s]: CMS ERROR: %s", octstr_get_cstr(privdata->name), 
  461.                       octstr_get_cstr(line));
  462.                 ret = 1;
  463.                 goto end;
  464.             }
  465.             if (octstr_search(line, octstr_imm("+CMT:"), 0) != -1 ||
  466. octstr_search(line, octstr_imm("+CDS:"), 0) != -1 ||
  467.                 ((octstr_search(line, octstr_imm("+CMGR:"), 0) != -1) && (cmgr_flag = 1)) ) {
  468.                 line2 = at2_wait_line(privdata, 1, 0);
  469.                 if (line2 == NULL) {
  470.                     error(0, "AT2[%s]: got +CMT but waiting for next line timed out", 
  471.                           octstr_get_cstr(privdata->name));
  472.                 } else {
  473.                     octstr_append_cstr(line, "n");
  474.                     octstr_append(line, line2);
  475.                     O_DESTROY(line2);
  476.                     at2_pdu_extract(privdata, &pdu, line);
  477.                     if (pdu == NULL) {
  478.                         error(0, "AT2[%s]: got +CMT but pdu_extract failed", 
  479.                               octstr_get_cstr(privdata->name));
  480.                     } else {
  481.                         /* count message even if I can't decode it */
  482.                         if (output)
  483.                             ++(*output);
  484.                         msg = at2_pdu_decode(pdu, privdata);
  485.                         if (msg != NULL) {
  486.                             msg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
  487.                             bb_smscconn_receive(privdata->conn, msg);
  488.                         }
  489.                         if (!cmgr_flag) {
  490.                             if (privdata->phase2plus)
  491.                                 at2_write_line(privdata, "AT+CNMA");
  492.                         }
  493.                         O_DESTROY(pdu);
  494.                     }
  495.                 }
  496.                 continue;
  497.             }
  498.             if ((octstr_search(line, octstr_imm("+CMGS:"),0) != -1) && (output)) {
  499. /* found response to a +CMGS command, read the message id and return it in output */
  500. long temp;
  501. if (octstr_parse_long(&temp, line, octstr_search(line, octstr_imm("+CMGS:"),0)+6,10) == -1)
  502.     error(0,"AT2[%s]: got +CMGS but failed to read message id", octstr_get_cstr(privdata->name));
  503. else
  504.     *output = temp;
  505.             }
  506.             if ( -1 != octstr_search(line, octstr_imm("ERROR"), 0)) {
  507.                 ret = -1;
  508.                 goto end;
  509.             }
  510.         }
  511.     }
  512.     len = octstr_len(privdata->ilb);
  513.     /*
  514.     error(0,"AT2[%s]: timeout. received <%s> until now, buffer size is %d, buf=%s",
  515.           octstr_get_cstr(privdata->name),
  516.           privdata->lines ? octstr_get_cstr(privdata->lines) : "<nothing>", len,
  517.           privdata->ilb ? octstr_get_cstr(privdata->ilb) : "<nothing>");
  518.     */
  519.     O_DESTROY(line);
  520.     O_DESTROY(line2);
  521.     O_DESTROY(pdu);
  522.     return -1; /* timeout */
  523. end:
  524.     octstr_append(privdata->lines, line);
  525.     octstr_append_cstr(privdata->lines, "n");
  526.     O_DESTROY(line);
  527.     O_DESTROY(line2);
  528.     O_DESTROY(pdu);
  529.     return ret;
  530. }
  531. void at2_read_sms_memory(PrivAT2data* privdata)
  532. {
  533.     char cmd[20];
  534.     /* get memory status */
  535.     if (at2_check_sms_memory(privdata) == -1) {
  536.         debug("bb.smsc.at2", 0, "AT2[%s]: memory check error", octstr_get_cstr(privdata->name));
  537.         return ;
  538.     }
  539.     if (privdata->sms_memory_usage) { 
  540.         /*
  541.          * that is - greater then 0, meaning there are some messages to fetch
  542.          * now - I used to just loop over the first input_mem_sms_used locations, 
  543.          * but it doesn't hold, since under load, messages may be received while 
  544.          * we're in the loop, and get stored in locations towards the end of the list, 
  545.          * thus creating 'holes' in the memory. 
  546.          * 
  547.          * There are two ways we can fix this : 
  548.          *   (a) Just read the last message location, delete it and return.
  549.          *       It's not a complete solution since holes can still be created if messages 
  550.          *       are recieved between the memory check and the delete command, 
  551.          *       and anyway - it will slow us down and won't hold well under pressure
  552.          *   (b) Just scan the entire memory each call, bottom to top. 
  553.          *       This will be slow too, but it'll be reliable.
  554.          *
  555.          * We can massivly improve performance by stopping after input_mem_sms_used messages
  556.          * have been read, but send_modem_command returns 0 for no message as well as for a 
  557.          * message read, and the only other way to implement it is by doing memory_check 
  558.          * after each read and stoping when input_mem_sms_used get to 0. This is slow 
  559.          * (modem commands take time) so we improve speed only if there are less then 10 
  560.          * messages in memory.
  561.          *
  562.          * I implemented the alternative - changed at2_wait_modem_command to return the 
  563.          * number of messages it collected.
  564.          */
  565.         int i;
  566.         int message_count = 0; /* cound number of messages collected */
  567.         debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory", 
  568.               octstr_get_cstr(privdata->name), privdata->sms_memory_usage);
  569.         /*
  570.          * loop till end of memory or collected enouch messages
  571.          */
  572.         for (i = 1; i <= privdata->sms_memory_capacity &&
  573.              message_count < privdata->sms_memory_usage; ++i) { 
  574.             int old_message_count = message_count;
  575.             sprintf(cmd, "AT+CMGR=%d", i);
  576.             /* read one message from memory */
  577.             at2_write_line(privdata, cmd);
  578.             if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) {
  579.                 debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", 
  580.                       octstr_get_cstr(privdata->name), i);
  581.                 continue; /* failed to read the message - skip to next message */
  582.             }
  583.             /* no need to delete if no message collected */
  584.             if (old_message_count == message_count) { 
  585.                 debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", 
  586.                       octstr_get_cstr(privdata->name));
  587.                 continue;
  588.             }
  589.             sprintf(cmd, "AT+CMGD=%d", i); /* delete the message we just read */
  590.             /* 
  591.              * 3 seconds is not enough with some modems if the message is large,
  592.              * so we'll give it 7 seconds 
  593.              */
  594.             if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) {  
  595.                 /* 
  596.                  * failed to delete the message, we'll just ignore it for now, 
  597.                  * this is bad, since if the message really didn't get deleted
  598.                  * we'll see it next time around. 
  599.                  */                
  600.                 debug("bb.smsc.at2", 0, "AT2[%s]: failed to delete message %d.", 
  601.                       octstr_get_cstr(privdata->name), i);
  602.                 continue; 
  603.             }
  604.         }
  605.     }
  606.     /*
  607.     at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0);
  608.     */
  609. }
  610. int at2_check_sms_memory(PrivAT2data *privdata)
  611. {
  612.     long values[4]; /* array to put response data in */
  613.     int pos; /* position of parser in data stream */
  614.     int ret;
  615.     Octstr* search_cpms = NULL;
  616.     /* select memory type and get report */
  617.     if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) { 
  618.         debug("bb.smsc.at2.memory_check", 0, "failed to send mem select command to modem %d", ret);
  619.         return -1;
  620.     }
  621.     search_cpms = octstr_create("+CPMS:");
  622.     if ((pos = octstr_search(privdata->lines, search_cpms, 0)) != -1) {
  623.         /* got back a +CPMS response */
  624.         int index = 0; /* index in values array */
  625.         pos += 6; /* position of parser in the stream - start after header */
  626.         /* skip memory indication */
  627.         pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; 
  628.         /* find all the values */
  629.         while (index < 4 && pos < octstr_len(privdata->lines) &&
  630.                (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { 
  631.             ++pos; /* skip number seperator */
  632.             ++index; /* increment array index */
  633.             if (index == 2)
  634.                 /* skip second memory indication */
  635.                 pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; 
  636.         }
  637.         if (index < 4) { 
  638.             /* didn't get all memory data - I don't why, so I'll bail */
  639.             debug("bb.smsc.at2", 0, "AT2[%s]: couldn't parse all memory locations : %d:'%s'.",
  640.                   octstr_get_cstr(privdata->name), index, 
  641.                   &(octstr_get_cstr(privdata->lines)[pos]));
  642.             O_DESTROY(search_cpms);
  643.             return -1;
  644.         }
  645.         privdata->sms_memory_usage = values[0];
  646.         privdata->sms_memory_capacity = values[1];
  647.         /*
  648.         privdata->output_mem_sms_used = values[2];
  649.         privdata->output_mem_sms_capacity = values[3];
  650.         */
  651.         /* everything's cool */
  652.         ret = 0; 
  653.         /*  clear the buffer */
  654.         O_DESTROY(privdata->lines);
  655.     } else {
  656.         debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.", 
  657.               octstr_get_cstr(privdata->name));
  658.         /* didn't get a +CPMS response - this is clearly an error */
  659.         ret = -1; 
  660.     }
  661.     O_DESTROY(search_cpms);
  662.     return ret;
  663. }
  664. void at2_set_speed(PrivAT2data *privdata, int bps)
  665. {
  666.     struct termios tios;
  667.     int ret;
  668.     int speed;
  669.     tcgetattr(privdata->fd, &tios);
  670.     switch (bps) {
  671.     case 300:
  672.         speed = B300;
  673.         break;
  674.     case 1200:
  675.         speed = B1200;
  676.         break;
  677.     case 2400:
  678.         speed = B2400;
  679.         break;
  680.     case 4800:
  681.         speed = B4800;
  682.         break;
  683.     case 9600:
  684.         speed = B9600;
  685.         break;
  686.     case 19200:
  687.         speed = B19200;
  688.         break;
  689.     case 38400:
  690.         speed = B38400;
  691.         break;
  692. #ifdef B57600
  693.     case 57600:
  694.         speed = B57600;
  695.         break;
  696. #endif
  697.     default:
  698.         speed = B9600;
  699.     }
  700.     cfsetospeed(&tios, speed);
  701.     cfsetispeed(&tios, speed);
  702.     ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */
  703.     if (ret == -1) {
  704.         error(errno, "AT2[%s]: at_data_link: fail to set termios attribute",
  705.               octstr_get_cstr(privdata->name));
  706.     }
  707.     tcflush(privdata->fd, TCIOFLUSH);
  708.     info(0, "AT2[%s]: speed set to %d", octstr_get_cstr(privdata->name), bps);
  709. }
  710. void at2_device_thread(void *arg)
  711. {
  712.     SMSCConn *conn = arg;
  713.     PrivAT2data *privdata = conn->data;
  714.     int l, wait = 0;
  715.     long idle_timeout, memory_poll_timeout = 0;
  716.     conn->status = SMSCCONN_CONNECTING;
  717. reconnect:
  718.     do {
  719.         if (wait) {
  720.             if (conn->status == SMSCCONN_ACTIVE) {
  721.                 mutex_lock(conn->flow_mutex);
  722.                 conn->status = SMSCCONN_RECONNECTING;
  723.                 mutex_unlock(conn->flow_mutex);
  724.             }
  725.             info(0, "AT2[%s]: waiting for %d %s before trying to connect again", 
  726.                  octstr_get_cstr(privdata->name), (wait < 60 ? wait : wait / 60),
  727.                  (wait < 60 ? "seconds" : "minutes"));
  728.             gwthread_sleep(wait);
  729.             wait = wait > (privdata->retry ? 3600 : 600) ? 
  730.                 (privdata->retry ? 3600 : 600) : wait * 2;
  731.         } else
  732.             wait = 15;
  733.         /* If modems->speed is defined, try to use it, else autodetect */
  734.         if (privdata->speed == 0 && privdata->modem != NULL && 
  735.     privdata->modem->speed != 0) {
  736.     info(0, "AT2[%s]: trying to use speed <%ld> from modem definition", 
  737.          octstr_get_cstr(privdata->name), privdata->modem->speed);
  738.     if(0 == at2_test_speed(privdata, privdata->modem->speed)) { 
  739. privdata->speed = privdata->modem->speed;
  740. info(0, "AT2[%s]: speed is %ld", 
  741.      octstr_get_cstr(privdata->name), privdata->speed);
  742.     } else {
  743. info(0, "AT2[%s]: speed in modem definition don't work, will autodetect", 
  744.      octstr_get_cstr(privdata->name));
  745.     }
  746. }
  747.         if (privdata->speed == 0) {
  748.     if (at2_detect_speed(privdata) == -1) {
  749. if (!privdata->retry)
  750.     return;
  751. else
  752.     continue;
  753.             }
  754.         }
  755.         if (privdata->modem == NULL) {
  756.             if (at2_detect_modem_type(privdata) == -1) {
  757.                 if (!privdata->retry)
  758.                     return;
  759.                 else
  760.                     continue;
  761.             }
  762.         }
  763.         if (at2_open_device(privdata)) {
  764.             error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed. Terminating", 
  765.                   octstr_get_cstr(privdata->name));
  766.             if (!privdata->retry)
  767.                 return;
  768.             else
  769.                 continue;
  770.         }
  771.         if (at2_init_device(privdata) != 0) {
  772.             error(0, "AT2[%s]: Opening failed. Terminating", octstr_get_cstr(privdata->name));
  773.             if (!privdata->retry) {
  774.                 privdata->shutdown = 1;
  775.                 //return;
  776.             } else
  777.                 continue;
  778.         }
  779.         /* If we got here, then the device is opened */
  780.         break;
  781.     } while (privdata->retry && !privdata->shutdown);
  782.     conn->status = SMSCCONN_ACTIVE;
  783.     bb_smscconn_connected(conn);
  784.     idle_timeout = 0;
  785.     while (!privdata->shutdown) {
  786.         l = list_len(privdata->outgoing_queue);
  787.         if (l > 0) {
  788.             at2_send_messages(privdata);
  789.             idle_timeout = time(NULL);
  790.         } else
  791.             at2_wait_modem_command(privdata, 1, 0, NULL);
  792.         if (privdata->keepalive &&
  793.             idle_timeout + privdata->keepalive < time(NULL)) {
  794.             if (at2_send_modem_command(privdata, 
  795.                 octstr_get_cstr(privdata->modem->keepalive_cmd), 5, 0) < 0) {
  796.                 at2_close_device(privdata);
  797.                 conn->status = SMSCCONN_RECONNECTING;
  798.                 wait = 15;
  799.                 goto reconnect;
  800.             }
  801.             idle_timeout = time(NULL);
  802.         }
  803.         if (privdata->sms_memory_poll_interval &&
  804.             memory_poll_timeout + privdata->sms_memory_poll_interval < time(NULL)) {
  805.             at2_read_sms_memory(privdata);
  806.             memory_poll_timeout = time(NULL);
  807.         }
  808.     }
  809.     at2_close_device(privdata);
  810.     conn->status = SMSCCONN_DISCONNECTED;
  811.     /* maybe some cleanup here? */
  812.     at2_destroy_modem(privdata->modem);
  813.     octstr_destroy(privdata->device);
  814.     octstr_destroy(privdata->ilb);
  815.     octstr_destroy(privdata->lines);
  816.     octstr_destroy(privdata->pin);
  817.     octstr_destroy(privdata->validityperiod);
  818.     octstr_destroy(privdata->my_number);
  819.     octstr_destroy(privdata->sms_center);
  820.     octstr_destroy(privdata->name);
  821.     octstr_destroy(privdata->configfile);
  822.     list_destroy(privdata->outgoing_queue, NULL);
  823.     gw_free(conn->data);
  824.     conn->data = NULL;
  825.     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
  826.     conn->status = SMSCCONN_DEAD;
  827.     bb_smscconn_killed();
  828. }
  829. int at2_shutdown_cb(SMSCConn *conn, int finish_sending)
  830. {
  831.     PrivAT2data *privdata = conn->data;
  832.     debug("bb.sms", 0, "AT2[%s]: Shutting down SMSCConn, %s",
  833.           octstr_get_cstr(privdata->name),
  834.           finish_sending ? "slow" : "instant");
  835.     /* 
  836.      * Documentation claims this would have been done by smscconn.c,
  837.      * but isn't when this code is being written. 
  838.      */
  839.     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
  840.     privdata->shutdown = 1; 
  841.     /* 
  842.      * Separate from why_killed to avoid locking, as
  843.      * why_killed may be changed from outside? 
  844.      */
  845.     if (finish_sending == 0) {
  846.         Msg *msg;
  847.         while ((msg = list_extract_first(privdata->outgoing_queue)) != NULL) {
  848.             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN);
  849.         }
  850.     }
  851.     gwthread_wakeup(privdata->device_thread);
  852.     return 0;
  853. }
  854. long at2_queued_cb(SMSCConn *conn)
  855. {
  856.     long ret;
  857.     PrivAT2data *privdata = conn->data;
  858.     if (conn->status == SMSCCONN_DEAD) /* I'm dead, why would you care ? */
  859. return -1;
  860.     ret = list_len(privdata->outgoing_queue);
  861.     /* use internal queue as load, maybe something else later */
  862.     conn->load = ret;
  863.     return ret;
  864. }
  865. void at2_start_cb(SMSCConn *conn)
  866. {
  867.     PrivAT2data *privdata = conn->data;
  868.     if (conn->status == SMSCCONN_DISCONNECTED)
  869.         conn->status = SMSCCONN_ACTIVE;
  870.     
  871.     /* in case there are messages in the buffer already */
  872.     gwthread_wakeup(privdata->device_thread);
  873.     debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name));
  874. }
  875. int at2_add_msg_cb(SMSCConn *conn, Msg *sms)
  876. {
  877.     PrivAT2data *privdata = conn->data;
  878.     Msg *copy;
  879.     copy = msg_duplicate(sms);
  880.     list_produce(privdata->outgoing_queue, copy);
  881.     gwthread_wakeup(privdata->device_thread);
  882.     return 0;
  883. }
  884. int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg)
  885. {
  886.     PrivAT2data *privdata;
  887.     Octstr *modem_type_string;
  888.     privdata = gw_malloc(sizeof(PrivAT2data));
  889.     privdata->outgoing_queue = list_create();
  890.     privdata->configfile = cfg_get_configfile(cfg);
  891.     privdata->device = cfg_get(cfg, octstr_imm("device"));
  892.     if (privdata->device == NULL) {
  893.         error(0, "AT2[-]: 'device' missing in at2 configuration.");
  894.         goto error;
  895.     }
  896.     privdata->name = cfg_get(cfg, octstr_imm("smsc-id"));
  897.     if (privdata->name == NULL) {
  898.         privdata->name = octstr_duplicate(privdata->device);
  899.     }
  900.     privdata->speed = 0;
  901.     cfg_get_integer(&privdata->speed, cfg, octstr_imm("speed"));
  902.     privdata->keepalive = 0;
  903.     cfg_get_integer(&privdata->keepalive, cfg, octstr_imm("keepalive"));
  904.     cfg_get_bool(&privdata->sms_memory_poll_interval, cfg, octstr_imm("sim-buffering"));
  905.     if (privdata->sms_memory_poll_interval) {
  906.         if (privdata->keepalive)
  907.             privdata->sms_memory_poll_interval = privdata->keepalive;
  908.         else
  909.             privdata->sms_memory_poll_interval = AT2_DEFAULT_SMS_POLL_INTERVAL;
  910.     }
  911.     cfg_get_bool(&privdata->retry, cfg, octstr_imm("retry"));
  912.     privdata->my_number = cfg_get(cfg, octstr_imm("my-number"));
  913.     privdata->sms_center = cfg_get(cfg, octstr_imm("sms-center"));
  914.     modem_type_string = cfg_get(cfg, octstr_imm("modemtype"));
  915.     privdata->modem = NULL;
  916.     if (modem_type_string != NULL) {
  917.         if (octstr_compare(modem_type_string, octstr_imm("auto")) == 0 ||
  918.             octstr_compare(modem_type_string, octstr_imm("autodetect")) == 0)
  919.             O_DESTROY(modem_type_string);
  920.     }
  921.     if (octstr_len(modem_type_string) == 0) {
  922.         info(0, "AT2[%s]: configuration doesn't show modemtype. will autodetect",
  923.              octstr_get_cstr(privdata->name));
  924.     } else {
  925.         info(0, "AT2[%s]: configuration shows modemtype <%s>",
  926.              octstr_get_cstr(privdata->name),
  927.              octstr_get_cstr(modem_type_string));
  928.         privdata->modem = at2_read_modems(privdata, privdata->configfile,
  929.                                           modem_type_string, 0);
  930.         if (privdata->modem == NULL) {
  931.             info(0, "AT2[%s]: modemtype not found, revert to autodetect",
  932.                  octstr_get_cstr(privdata->name));
  933.         } else {
  934.             info(0, "AT2[%s]: read modem definition for <%s>",
  935.                  octstr_get_cstr(privdata->name),
  936.                  octstr_get_cstr(privdata->modem->name));
  937.         }
  938.         O_DESTROY(modem_type_string);
  939.     }
  940.     privdata->ilb = octstr_create("");
  941.     privdata->fd = -1;
  942.     privdata->lines = NULL;
  943.     privdata->pin = cfg_get(cfg, octstr_imm("pin"));
  944.     privdata->pin_ready = 0;
  945.     privdata->conn = conn;
  946.     privdata->phase2plus = 0;
  947.     privdata->validityperiod = cfg_get(cfg, octstr_imm("validityperiod"));
  948.     cfg_get_bool(&privdata->alt_dcs, cfg, octstr_imm("alt-dcs"));
  949.     conn->data = privdata;
  950.     conn->name = octstr_format("AT2[%s]", octstr_get_cstr(privdata->name));
  951.     privdata->shutdown = 0;
  952.     conn->status = SMSCCONN_CONNECTING;
  953.     conn->connect_time = time(NULL);
  954.     if ((privdata->device_thread = gwthread_create(at2_device_thread, conn)) == -1) {
  955.         privdata->shutdown = 1;
  956.         goto error;
  957.     }
  958.     conn->shutdown = at2_shutdown_cb;
  959.     conn->queued = at2_queued_cb;
  960.     conn->start_conn = at2_start_cb;
  961.     conn->send_msg = at2_add_msg_cb;
  962.     return 0;
  963. error:
  964.     error(0, "AT2[%s]: Failed to create at2 smsc connection",
  965.           octstr_len(privdata->name) ? octstr_get_cstr(privdata->name) : "");
  966.     if (privdata != NULL) {
  967.         list_destroy(privdata->outgoing_queue, NULL);
  968.     }
  969.     gw_free(privdata);
  970.     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
  971.     conn->status = SMSCCONN_DEAD;
  972.     info(0, "AT2[%s]: exiting", octstr_get_cstr(privdata->name));
  973.     return -1;
  974. }
  975. int at2_pdu_extract(PrivAT2data *privdata, Octstr **pdu, Octstr *line)
  976. {
  977.     Octstr *buffer;
  978.     long len = 0;
  979.     int pos = 0;
  980.     int tmp;
  981.     buffer = octstr_duplicate(line);
  982.     /* find the beginning of a message from the modem*/
  983.     if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1) 
  984. pos += 5;
  985.     else {
  986. if ((pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) != -1)
  987.     pos += 5;
  988. else if ((pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) != -1) {
  989.     /* skip status field in +CMGR response */
  990.     if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1) 
  991. pos++;
  992.     else
  993. goto nomsg;
  994. } else
  995.     goto nomsg;
  996. /* skip the next comma in CMGR and CMT responses */
  997. tmp = octstr_search(buffer, octstr_imm(","), pos);
  998. if (! privdata->modem->broken && tmp == -1)
  999.     goto nomsg;
  1000. if (tmp != -1)
  1001.     pos = tmp + 1;
  1002.     }
  1003.     /* read the message length */
  1004.     pos = octstr_parse_long(&len, buffer, pos, 10);
  1005.     if (pos == -1)
  1006.         goto nomsg;
  1007.     /* skip the spaces and line return */
  1008.     while (isspace(octstr_get_char(buffer, pos)))
  1009.         pos++;
  1010.     /* skip the SMSC address on some modem types */
  1011.     if (!privdata->modem->no_smsc) {
  1012.         tmp = at2_hexchar(octstr_get_char(buffer, pos)) * 16
  1013.               + at2_hexchar(octstr_get_char(buffer, pos + 1));
  1014.         if (tmp < 0)
  1015.             goto nomsg;
  1016.         tmp = 2 + tmp * 2;
  1017.         pos += tmp;
  1018.     }
  1019.     /* check if the buffer is long enough to contain the full message */
  1020.     if (!privdata->modem->broken && octstr_len(buffer) < len * 2 + pos)
  1021.         goto nomsg;
  1022.     if (privdata->modem->broken && octstr_len(buffer) < len * 2)
  1023.         goto nomsg;
  1024.     /* copy the PDU then remove it from the input buffer*/
  1025.     *pdu = octstr_copy(buffer, pos, len * 2);
  1026.     octstr_destroy(buffer);
  1027.     return 1;
  1028. nomsg:
  1029.     octstr_destroy(buffer);
  1030.     return 0;
  1031. }
  1032. int at2_hexchar(int hexc)
  1033. {
  1034.     hexc = toupper(hexc) - 48;
  1035.     return (hexc > 9) ? hexc - 7 : hexc;
  1036. }
  1037. Msg *at2_pdu_decode(Octstr *data, PrivAT2data *privdata)
  1038. {
  1039.     int type;
  1040.     Msg *msg = NULL;
  1041.     /* Get the PDU type */
  1042.     type = octstr_get_char(data, 1) & 3;
  1043.     switch (type) {
  1044.         case AT_DELIVER_SM:
  1045.             msg = at2_pdu_decode_deliver_sm(data, privdata);
  1046.             break;
  1047.         case AT_STATUS_REPORT_SM:
  1048.     msg = at2_pdu_decode_report_sm(data, privdata);
  1049.     break;
  1050.             /* Add other message types here: */
  1051.     }
  1052.     return msg;
  1053. }
  1054. Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata)
  1055. {
  1056.     int len, pos, i, ntype;
  1057.     int udhi, dcs, udhlen, pid;
  1058.     Octstr *origin = NULL;
  1059.     Octstr *udh = NULL;
  1060.     Octstr *text = NULL, *tmpstr;
  1061.     Octstr *pdu = NULL;
  1062.     Msg *message = NULL;
  1063.     struct universaltime mtime; /* time structure */
  1064.     long stime; /* time in seconds */
  1065.     int timezone; /* timezone in 15 minutes jumps from GMT */
  1066.     /* 
  1067.      * Note: some parts of the PDU are not decoded because they are
  1068.      * not needed for the Msg type. 
  1069.      */
  1070.     /* convert the pdu to binary format for ease of processing */
  1071.     pdu = at2_convertpdu(data);
  1072.     /* UDH Indicator */
  1073.     udhi = (octstr_get_char(pdu, 0) & 64) >> 6;
  1074.     /* originating address */
  1075.     len = octstr_get_char(pdu, 1);
  1076.     ntype = octstr_get_char(pdu, 2);
  1077.     pos = 3;
  1078.     if ((ntype & 0xD0) == 0xD0) {
  1079.         /* Alphanumeric sender */
  1080.         origin = octstr_create("");
  1081.         tmpstr = octstr_copy(pdu, 3, len);
  1082.         at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0);
  1083.         octstr_destroy(tmpstr);
  1084.         debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", 
  1085.               octstr_get_cstr(privdata->name), octstr_get_cstr(origin));
  1086.         pos += (len + 1) / 2;
  1087.     } else {
  1088.         origin = octstr_create("");
  1089.         if ((ntype & 0x90) == 0x90) {
  1090.             /* International number */
  1091.             octstr_append_char(origin, '+');
  1092.         }
  1093.         for (i = 0; i < len; i += 2, pos++) {
  1094.             octstr_append_char(origin, (octstr_get_char(pdu, pos) & 15) + 48);
  1095.             if (i + 1 < len)
  1096.                 octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48);
  1097.         }
  1098.         debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", 
  1099.               octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), 
  1100.               octstr_get_cstr(origin));
  1101.     }
  1102.     /* PID */
  1103.     pid = octstr_get_char(pdu, pos);
  1104.     pos++;
  1105.     /* DCS */
  1106.     dcs = octstr_get_char(pdu, pos);
  1107.     pos++;
  1108.     /* get the timestamp */
  1109.     mtime.year = swap_nibbles(octstr_get_char(pdu, pos));
  1110.     pos++;
  1111.     mtime.year += (mtime.year < 70 ? 2000 : 1900);
  1112.     mtime.month = swap_nibbles(octstr_get_char(pdu, pos)) ;
  1113.     pos++;
  1114.     mtime.day = swap_nibbles(octstr_get_char(pdu, pos));
  1115.     pos++;
  1116.     mtime.hour = swap_nibbles(octstr_get_char(pdu, pos));
  1117.     pos++;
  1118.     mtime.minute = swap_nibbles(octstr_get_char(pdu, pos));
  1119.     pos++;
  1120.     mtime.second = swap_nibbles(octstr_get_char(pdu, pos));
  1121.     pos++;
  1122.     /* 
  1123.      * time zone: 
  1124.      *
  1125.      * time zone is "swapped nibble", with the MSB as the sign (1 is negative).  
  1126.      */
  1127.     timezone = swap_nibbles(octstr_get_char(pdu, pos));
  1128.     pos++;
  1129.     timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127);
  1130.     /* 
  1131.      * Ok, that was the time zone as read from the PDU. Now how to interpert it? 
  1132.      * All the handsets I tested send the timestamp of their local time and the 
  1133.      * timezone as GMT+0. I assume that the timestamp is the handset's local time, 
  1134.      * so we need to apply the timezone in reverse to get GM time: 
  1135.      */
  1136.     /* 
  1137.      * time in PDU is handset's local time and timezone is handset's time zone 
  1138.      * difference from GMT 
  1139.      */
  1140.     mtime.hour -= timezone / 4;
  1141.     mtime.minute -= 15 * (timezone % 4);
  1142.     stime = date_convert_universal(&mtime);
  1143.     /* get data length */
  1144.     len = octstr_get_char(pdu, pos);
  1145.     pos++;
  1146.     /* if there is a UDH */
  1147.     udhlen = 0;
  1148.     if (udhi) {
  1149.         udhlen = octstr_get_char(pdu, pos);
  1150.         pos++;
  1151.         udh = octstr_copy(pdu, pos, udhlen);
  1152.         pos += udhlen;
  1153.         len -= udhlen + 1;
  1154.     }
  1155.     /* build the message */
  1156.     message = msg_create(sms);
  1157.     if (!dcs_to_fields(&message, dcs)) {
  1158.         /* XXX Should reject this message? */
  1159.         debug("bb.smsc.at2", 0, "AT2[%s]: Invalid DCS",
  1160.               octstr_get_cstr(privdata->name));
  1161.         dcs_to_fields(&message, 0);
  1162.     }
  1163.     message->sms.pid = pid;
  1164.     /* deal with the user data -- 7 or 8 bit encoded */
  1165.     tmpstr = octstr_copy(pdu, pos, len);
  1166.     if (message->sms.coding == DC_8BIT || message->sms.coding == DC_UCS2) {
  1167.         text = octstr_duplicate(tmpstr);
  1168.     } else {
  1169.         int offset = 0;
  1170.         text = octstr_create("");
  1171.         if (udhi && message->sms.coding == DC_7BIT) {
  1172.             int nbits;
  1173.             nbits = (udhlen + 1) * 8;
  1174.             /* fill bits for UDH to septet boundary */
  1175.             offset = (((nbits / 7) + 1) * 7 - nbits) % 7;     
  1176.         }
  1177.         at2_decode7bituncompressed(tmpstr, len, text, offset);
  1178.     }
  1179.     message->sms.sender = origin;
  1180.     if (octstr_len(privdata->my_number)) {
  1181.         message->sms.receiver = octstr_duplicate(privdata->my_number);
  1182.     } else {
  1183.         /* Put a dummy address in the receiver for now (SMSC requires one) */
  1184.         message->sms.receiver = octstr_create_from_data("1234", 4);
  1185.     }
  1186.     if (udhi) {
  1187.         message->sms.udhdata = udh;
  1188.     }
  1189.     message->sms.msgdata = text;
  1190.     message->sms.time = stime;
  1191.     /* cleanup */
  1192.     octstr_destroy(pdu);
  1193.     octstr_destroy(tmpstr);
  1194.     return message;
  1195. }
  1196. Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata)
  1197. {
  1198.    Msg* dlrmsg = NULL;
  1199.    Octstr *pdu, *msg_id, *tmpstr = NULL, *receiver = NULL;
  1200.    int type, tp_mr, len, ntype, pos;
  1201.     /*
  1202.      * parse the PDU.
  1203.      */
  1204.     /* convert the pdu to binary format for ease of processing */
  1205.     pdu = at2_convertpdu(data);
  1206.     /* Message reference */
  1207.     tp_mr = octstr_get_char(pdu,1);
  1208.     msg_id = octstr_format("%d",tp_mr);
  1209.     debug("bb.smsc.at2",0,"AT2[%s]: got STATUS-REPORT for message <%d>:", octstr_get_cstr(privdata->name), tp_mr);
  1210.     
  1211.     /* reciver address */
  1212.     len = octstr_get_char(pdu, 2);
  1213.     ntype = octstr_get_char(pdu, 3);
  1214.     pos = 4;
  1215.     if ((ntype & 0xD0) == 0xD0) {
  1216.         /* Alphanumeric sender */
  1217.         receiver = octstr_create("");
  1218.         tmpstr = octstr_copy(pdu, pos, (len+1)/2);
  1219.         at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, receiver, 0);
  1220.         octstr_destroy(tmpstr);
  1221.         debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric receiver <%s>",
  1222.               octstr_get_cstr(privdata->name), octstr_get_cstr(receiver));
  1223.         pos += (len + 1) / 2;
  1224.     } else {
  1225. int i;
  1226.         receiver = octstr_create("");
  1227.         if ((ntype & 0x90) == 0x90) {
  1228.             /* International number */
  1229.             octstr_append_char(receiver, '+');
  1230.         }
  1231.         for (i = 0; i < len; i += 2, pos++) {
  1232.             octstr_append_char(receiver, (octstr_get_char(pdu, pos) & 15) + 48);
  1233.             if (i + 1 < len)
  1234.                 octstr_append_char(receiver, (octstr_get_char(pdu, pos) >> 4) + 48);
  1235.         }
  1236.         debug("bb.smsc.at2", 0, "AT2[%s]: Numeric receiver %s <%s>",
  1237.               octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""),
  1238.               octstr_get_cstr(receiver));
  1239.     }
  1240.     pos += 14; /* skip time stamps for now */
  1241.     if ((type = octstr_get_char(pdu, pos)) == -1 ) {
  1242. error(1,"AT2[%s]: STATUS-REPORT pdu too short to have TP-Status field !",
  1243.     octstr_get_cstr(privdata->name));
  1244. goto error;
  1245.     }
  1246. /* check DLR type:
  1247.  * 3GPP TS 23.040 defines this a bit mapped field with lots of options
  1248.  * most of which are not really intersting to us, as we are only interested
  1249.  * in one of three conditions : failed, held in SC for delivery later, or delivered successfuly
  1250.  * and here's how I suggest to test it (read the 3GPP reference for further detailes) -
  1251.  * we'll test the 6th and 5th bits (7th bit when set making all other values 'reseved' so I want to test it).
  1252.  */
  1253.     type = type & 0xE0; /* filter out everything but the 7th, 6th and 5th bits */
  1254.     switch (type) {
  1255. case 0x00:
  1256.     /* 0 0 : success class */
  1257.     type = DLR_SUCCESS;
  1258.     tmpstr = octstr_create("Success/");
  1259.     break;
  1260. case 0x20:
  1261.     /* 0 1 : buffered class (temporary error) */
  1262.     type = DLR_BUFFERED;
  1263.     tmpstr = octstr_create("Buffered/");
  1264.     break;
  1265. case 0x40:
  1266. case 0x60:
  1267. default:
  1268.     /* 1 0 : failed class */
  1269.     /* 1 1 : failed class (actually, temporary error but timed out) */
  1270.     /* and any other value (can't think of any) is considered failure */
  1271.     type = DLR_FAIL;
  1272.     tmpstr = octstr_create("Failed/");
  1273.     break;
  1274.     }
  1275.     /* Actually, the above implementation is not correct, as the reference says that implementations should consider
  1276.      * any "reserved" values to be "failure", but most reserved values fall into one of the three categories. it will catch
  1277.      * "reserved" values where the first 3 MSBits are not set as "Success" which may not be correct. */
  1278.     if ((dlrmsg = dlr_find(octstr_get_cstr(privdata->conn->id),
  1279.     octstr_get_cstr(msg_id), octstr_get_cstr(receiver), type)) == NULL) {
  1280. debug("bb.smsc.at2",1,"AT2[%s]: Received delivery notification but can't find that ID in the DLR storage",
  1281.     octstr_get_cstr(privdata->name));
  1282.     goto error;
  1283.     }
  1284.     /* Beware DLR URL is now in msg->sms.dlr_url given by dlr_find() */
  1285.     dlrmsg->sms.msgdata = octstr_duplicate(tmpstr);
  1286. error:
  1287.     O_DESTROY(tmpstr);
  1288.     O_DESTROY(pdu);
  1289.     O_DESTROY(receiver);
  1290.     O_DESTROY(msg_id);
  1291.     return dlrmsg;
  1292. }
  1293. Octstr *at2_convertpdu(Octstr *pdutext)
  1294. {
  1295.     Octstr *pdu;
  1296.     int i;
  1297.     int len = octstr_len(pdutext);
  1298.     pdu = octstr_create("");
  1299.     for (i = 0; i < len; i += 2) {
  1300.         octstr_append_char(pdu, at2_hexchar(octstr_get_char(pdutext, i)) * 16
  1301.                            + at2_hexchar(octstr_get_char(pdutext, i + 1)));
  1302.     }
  1303.     return pdu;
  1304. }
  1305. int at2_rmask[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
  1306. int at2_lmask[8] = { 0, 128, 192, 224, 240, 248, 252, 254 };
  1307. void at2_decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset)
  1308. {
  1309.     unsigned char septet, octet, prevoctet;
  1310.     int i;
  1311.     int r = 1;
  1312.     int c = 7;
  1313.     int pos = 0;
  1314.     /* Shift the buffer offset bits to the left */
  1315.     if (offset > 0) {
  1316.         unsigned char *ip;
  1317.         for (i = 0, ip = octstr_get_cstr(input); i < octstr_len(input); i++) {
  1318.             if (i == octstr_len(input) - 1)
  1319.                 *ip = *ip >> offset;
  1320.             else
  1321.                 *ip = (*ip >> offset) | (*(ip + 1) << (8 - offset));
  1322.             ip++;
  1323.         }
  1324.     }
  1325.     octet = octstr_get_char(input, pos);
  1326.     prevoctet = 0;
  1327.     for (i = 0; i < len; i++) {
  1328.         septet = ((octet & at2_rmask[c]) << (r - 1)) + prevoctet;
  1329.         octstr_append_char(decoded, septet);
  1330.         prevoctet = (octet & at2_lmask[r]) >> c;
  1331.         /* When r=7 we have a full character in prevoctet */
  1332.         if ((r == 7) && (i < len - 1)) {
  1333.             i++;
  1334.             octstr_append_char(decoded, prevoctet);
  1335.             prevoctet = 0;
  1336.         }
  1337.         r = (r > 6) ? 1 : r + 1;
  1338.         c = (c < 2) ? 7 : c - 1;
  1339.         pos++;
  1340.         octet = octstr_get_char(input, pos);
  1341.     }
  1342.     charset_gsm_to_latin1(decoded);
  1343. }
  1344. void at2_send_messages(PrivAT2data *privdata)
  1345. {
  1346.     Msg *msg;
  1347.     do {
  1348.         if (privdata->modem->enable_mms && 
  1349. list_len(privdata->outgoing_queue) > 1)
  1350.             at2_send_modem_command(privdata, "AT+CMMS=2", 0, 0);
  1351.         if ((msg = list_extract_first(privdata->outgoing_queue)))
  1352.             at2_send_one_message(privdata, msg);
  1353.     } while (msg);
  1354. }
  1355. void at2_send_one_message(PrivAT2data *privdata, Msg *msg)
  1356. {
  1357.     unsigned char command[500];
  1358.     int ret = -1;
  1359.     char sc[3];
  1360.     int retries = RETRY_SEND;
  1361.     if (octstr_len(privdata->my_number)) {
  1362.         octstr_destroy(msg->sms.sender);
  1363.         msg->sms.sender = octstr_duplicate(privdata->my_number);
  1364.     }
  1365.     /* 
  1366.      * The standard says you should be prepending the PDU with 00 to indicate 
  1367.      * to use the default SC. Some older modems dont expect this so it can be 
  1368.      * disabled 
  1369.      * NB: This extra padding is not counted in the CMGS byte count 
  1370.      */
  1371.     sc[0] = '';
  1372.     if (!privdata->modem->no_smsc)
  1373.         strcpy(sc, "00");
  1374.     if (msg_type(msg) == sms) {
  1375. Octstr* pdu;
  1376. if ((pdu = at2_pdu_encode(msg, privdata)) == NULL) {
  1377.     error(2, "AT2[%s]: Error encoding PDU!",octstr_get_cstr(privdata->name));
  1378.     return;
  1379. }
  1380.         ret = -99;
  1381.         retries = RETRY_SEND;
  1382.         while ((ret != 0) && (retries-- > 0)) {
  1383.     int msg_id = -1;
  1384.             /* 
  1385.              * send the initial command and then wait for > 
  1386.              */
  1387.             sprintf(command, "AT+CMGS=%ld", octstr_len(pdu) / 2);
  1388.             
  1389.             ret = at2_send_modem_command(privdata, command, 5, 1);
  1390.             debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d",
  1391.                   octstr_get_cstr(privdata->name), ret);
  1392.             if (ret != 1) /* > only! */
  1393.                 continue;
  1394.             /* 
  1395.              * ok the > has been see now so we can send the PDU now and a 
  1396.              * control Z but no CR or LF 
  1397.              */
  1398.             sprintf(command, "%s%s", sc, octstr_get_cstr(pdu));
  1399.             at2_write(privdata, command);
  1400.             at2_write_ctrlz(privdata);
  1401.             
  1402.             /* wait 20 secs for modem command */
  1403.             ret = at2_wait_modem_command(privdata, 20, 0, &msg_id);
  1404.             debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d",
  1405.                   octstr_get_cstr(privdata->name), ret);
  1406.             
  1407.             if (ret != 0) /* OK only */
  1408.                 continue;
  1409.     /* gen DLR_SMSC_SUCCESS */
  1410.     if (msg->sms.dlr_mask & DLR_SMSC_SUCCESS)
  1411.     {
  1412. Msg* dlrmsg;
  1413. dlrmsg = msg_create(sms);
  1414. dlrmsg->sms.id = msg->sms.id;
  1415.                 dlrmsg->sms.service = octstr_duplicate(msg->sms.service);
  1416.                 dlrmsg->sms.dlr_mask = DLR_SMSC_SUCCESS;
  1417.                 dlrmsg->sms.sms_type = report;
  1418.                 dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
  1419.                 dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver);
  1420.                 dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender);
  1421.                 dlrmsg->sms.msgdata = octstr_create("ACK");
  1422.                 dlrmsg->sms.dlr_url = octstr_duplicate(msg->sms.dlr_url);
  1423.                 time(&dlrmsg->sms.time);
  1424. debug("bb.smsc.at2",0,"AT2[%s]: sending DLR type ACK", octstr_get_cstr(privdata->name));
  1425. bb_smscconn_receive(privdata->conn, dlrmsg);
  1426.     }
  1427.     /* store DLR message if needed for SMSC generated delivery reports */
  1428.     if (msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) {
  1429. if (msg_id == -1)
  1430.     error(0,"AT2[%s]: delivery notification requested, but I have no message ID!",
  1431. octstr_get_cstr(privdata->name));
  1432.  else {
  1433.             Octstr *dlrmsgid = octstr_format("%d", msg_id);
  1434.             dlr_add(octstr_get_cstr(privdata->conn->id),
  1435.                     octstr_get_cstr(dlrmsgid),
  1436.         octstr_get_cstr(msg->sms.sender),
  1437.         octstr_get_cstr(msg->sms.receiver),
  1438.         octstr_get_cstr(msg->sms.service),
  1439.         octstr_get_cstr(msg->sms.dlr_url),
  1440.         msg->sms.dlr_mask);
  1441.     O_DESTROY(dlrmsgid);
  1442. }
  1443.     }
  1444.             counter_increase(privdata->conn->sent);
  1445.             bb_smscconn_sent(privdata->conn, msg);
  1446.         }
  1447.         if (ret != 0) {
  1448.     /* gen DLR_SMSC_FAIL */
  1449.     if (msg->sms.dlr_mask & DLR_SMSC_FAIL) {
  1450. Msg* dlrmsg;
  1451. dlrmsg = msg_create(sms);
  1452.                 dlrmsg->sms.service = octstr_duplicate(msg->sms.service);
  1453.                 dlrmsg->sms.dlr_mask = DLR_SMSC_FAIL;
  1454.                 dlrmsg->sms.sms_type = report;
  1455.                 dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id);
  1456.                 dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver);
  1457.                 dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender);
  1458.                 dlrmsg->sms.msgdata = octstr_create("NACK");
  1459.                 dlrmsg->sms.dlr_url = octstr_duplicate(msg->sms.dlr_url);
  1460.                 time(&dlrmsg->sms.time);
  1461. debug("bb.smsc.at2",0,"AT2[%s]: sending DLR type NACK", octstr_get_cstr(privdata->name));
  1462. bb_smscconn_receive(privdata->conn, dlrmsg);
  1463.     }
  1464.             /*
  1465.              * no need to do counter_increase(privdata->conn->failed) here, 
  1466.              * since bb_smscconn_send_failed() will inc the counter on 
  1467.              * SMSCCONN_FAILED_MALFORMED
  1468.              */
  1469.             bb_smscconn_send_failed(privdata->conn, msg, SMSCCONN_FAILED_MALFORMED);
  1470.         }
  1471.         O_DESTROY(pdu);
  1472.     }
  1473. }
  1474. Octstr* at2_pdu_encode(Msg *msg, PrivAT2data *privdata)
  1475. {
  1476.     /*
  1477.      * Message coding is done as a binary octet string,
  1478.      * as per 3GPP TS 23.040 specification (GSM 03.40),
  1479.      */
  1480.     Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create("");
  1481.      
  1482.     int len, setvalidity = 0;
  1483.     /* 
  1484.      * message type SUBMIT , bit mapped :
  1485.      * bit7                            ..                                    bit0
  1486.      * TP-RP , TP-UDHI, TP-SRR, TP-VPF(4), TP-VPF(3), TP-RD, TP-MTI(1), TP-MTI(0)
  1487.      */
  1488.     octstr_append_char(buffer,
  1489. ((msg->sms.rpi ? 1 : 0) << 7) /* TP-RP */
  1490. | ((octstr_len(msg->sms.udhdata)  ? 1 : 0) << 6) /* TP-UDHI */
  1491. | (((msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) ? 1 : 0) << 5) /* TP-SRR */
  1492. | 16 /* TP-VP(Rel)*/
  1493. | 1 /* TP-MTI: SUBMIT_SM */
  1494. );
  1495.     /* message reference (0 for now) */
  1496.     octstr_append_char(buffer, 0);
  1497.     /* destination address */
  1498.     if ((temp = at2_format_address_field(msg->sms.receiver)) == NULL)
  1499. goto error;
  1500.     octstr_append(buffer, temp);
  1501.     O_DESTROY(temp);
  1502.     octstr_append_char(buffer, msg->sms.pid); /* protocol identifier */
  1503.     octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */
  1504. (msg->sms.alt_dcs ? 2 - msg->sms.alt_dcs : privdata->alt_dcs)));
  1505.     /* 
  1506.      * Validity-Period (TP-VP)
  1507.      * see GSM 03.40 section 9.2.3.12
  1508.      * defaults to 24 hours = 167 if not set 
  1509.      */
  1510.     if ( msg->sms.validity) {
  1511.         if (msg->sms.validity > 635040)
  1512.             setvalidity = 255;
  1513.         if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040)
  1514.             setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1;
  1515.         if (msg->sms.validity > 43200 && msg->sms.validity < 50400)
  1516.             setvalidity = 197;
  1517.         if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200)
  1518.             setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1;
  1519.         if (msg->sms.validity > 1440 && msg->sms.validity < 2880)
  1520.             setvalidity = 168;
  1521.         if (msg->sms.validity >= 750 && msg->sms.validity <= 1440)
  1522.             setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1;
  1523.         if (msg->sms.validity > 720 && msg->sms.validity < 750)
  1524.             setvalidity = 144;
  1525.         if (msg->sms.validity >= 5 && msg->sms.validity <= 720)
  1526.             setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1;
  1527.         if (msg->sms.validity < 5)
  1528.             setvalidity = 0;
  1529.     } else
  1530.         setvalidity = (privdata->validityperiod != NULL ? 
  1531.             atoi(octstr_get_cstr(privdata->validityperiod)) : 167);
  1532.     if (setvalidity >= 0 && setvalidity <= 143)
  1533.         debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d minutes",
  1534.               octstr_get_cstr(privdata->name), (setvalidity + 1)*5);
  1535.     else if (setvalidity >= 144 && setvalidity <= 167)
  1536.         debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %3.1f hours",
  1537.               octstr_get_cstr(privdata->name), ((float)(setvalidity - 143) / 2) + 12);
  1538.     else if (setvalidity >= 168 && setvalidity <= 196)
  1539.         debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d days",
  1540.               octstr_get_cstr(privdata->name), (setvalidity - 166));
  1541.     else
  1542.         debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d weeks",
  1543.               octstr_get_cstr(privdata->name), (setvalidity - 192));
  1544.     octstr_append_char(buffer, setvalidity);
  1545.     /* user data length - include length of UDH if it exists */
  1546.     len = sms_msgdata_len(msg);
  1547.     if (octstr_len(msg->sms.udhdata)) {
  1548.         if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
  1549.             len += octstr_len(msg->sms.udhdata);
  1550.             if (len > SMS_8BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */
  1551.                 octstr_delete(msg->sms.msgdata, SMS_8BIT_MAX_LEN - octstr_len(msg->sms.udhdata), 9999);
  1552.                 len = SMS_8BIT_MAX_LEN;
  1553.             }
  1554.         } else {
  1555.             /*
  1556.              * The reason we branch here is because UDH data length is determined
  1557.              * in septets if we are in GSM coding, otherwise it's in octets. Adding 6
  1558.              * will ensure that for an octet length of 0, we get septet length 0,
  1559.              * and for octet length 1 we get septet length 2. 
  1560.              */
  1561.             int temp_len;
  1562.             len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7));
  1563.             if (len > SMS_7BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */
  1564.                 octstr_delete(msg->sms.msgdata, SMS_7BIT_MAX_LEN - temp_len, 9999);
  1565.                 len = SMS_7BIT_MAX_LEN;
  1566.             }
  1567.         }
  1568.     }
  1569.     octstr_append_char(buffer,len);
  1570.     if (octstr_len(msg->sms.udhdata)) /* udh */
  1571. octstr_append(buffer, msg->sms.udhdata);
  1572.     /* user data */
  1573.     if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
  1574.         octstr_append(buffer, msg->sms.msgdata);
  1575.     } else {
  1576.         int offset = 0;
  1577.         /*
  1578.          * calculate the number of fill bits needed to align
  1579.          * the 7bit encoded user data on septet boundry
  1580.          */
  1581.         if (octstr_len(msg->sms.udhdata)) { /* Have UDH */
  1582.             int nbits = octstr_len(msg->sms.udhdata) * 8; /* Includes UDH length byte */
  1583.             offset = (((nbits / 7) + 1) * 7 - nbits) % 7; /* Fill bits */
  1584.         }
  1585.         charset_latin1_to_gsm(msg->sms.msgdata);
  1586.         
  1587.         if ((temp = at2_encode7bituncompressed(msg->sms.msgdata, offset)) != NULL)
  1588.     octstr_append(buffer, temp);
  1589.         O_DESTROY(temp);
  1590.     }
  1591.     /* convert PDU to HEX representation suitable for the AT2 command set */
  1592.     pdu = at2_encode8bituncompressed(buffer);
  1593.     O_DESTROY(buffer);
  1594.     return pdu;
  1595. error:
  1596.     O_DESTROY(temp);
  1597.     O_DESTROY(buffer);
  1598.     O_DESTROY(pdu);
  1599.     return NULL;
  1600. }
  1601. Octstr* at2_encode7bituncompressed(Octstr *source, int offset)
  1602. {
  1603.     int LSBmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
  1604.     int MSBmask[8] = { 0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x7E, 0x7F };
  1605.     int destRemain = (int)ceil ((octstr_len(source) * 7.0) / 8.0);
  1606.     int i = (offset?8-offset:7), iStore = offset;
  1607.     int posT, posS;
  1608.     Octstr *target = octstr_create("");
  1609.     int target_chr = 0, source_chr;
  1610.     /* start packing the septet stream into an octet stream */
  1611.     for (posS = 0, posT = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) {
  1612. /* grab least significant bits from current septet and store them packed to the right */
  1613. target_chr |= (source_chr & LSBmask[i]) << iStore;
  1614. /* store current byte if last command filled it */
  1615. if (iStore != 0) {
  1616.     destRemain--;
  1617.     octstr_append_char(target, target_chr);
  1618.     target_chr = 0;
  1619. }
  1620. /* grab most significant bits from current septet and store them packed to the left */
  1621. target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8;
  1622. /* advance target bit index by 7 ( modulo 8 addition ) */
  1623. iStore = (--iStore < 0 ? 7 : iStore);
  1624. if (iStore != 0) /* if just finished packing 8 septets (into 7 octets) don't advance mask index */
  1625.     i = (++i > 7 ? 1 : i); 
  1626.     }
  1627.     /* don't forget to pack the leftovers ;-) */
  1628.     if (destRemain > 0)
  1629. octstr_append_char(target, target_chr);
  1630.     return target;
  1631. }
  1632. Octstr* at2_encode8bituncompressed(Octstr *input)
  1633. {
  1634.     int len, i;
  1635.     Octstr* out = octstr_create("");
  1636.     len = octstr_len(input);
  1637.     for (i = 0; i < len; i++) {
  1638.         /* each character is encoded in its hex representation (2 chars) */
  1639.         octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0xF0) >> 4));
  1640.         octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0x0F)));
  1641.     }
  1642.     return out;
  1643. }
  1644. int at2_numtext(int num)
  1645. {
  1646.     return (num > 9) ? (num + 55) : (num + 48);
  1647. }
  1648. int at2_detect_speed(PrivAT2data *privdata)
  1649. {
  1650.     int i;
  1651. #ifdef B57600
  1652.     int autospeeds[] = { 57600, 38400, 19200, 9600 };
  1653. #else
  1654.     int autospeeds[] = { 38400, 19200, 9600 };
  1655. #endif
  1656.     debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ", 
  1657.           octstr_get_cstr(privdata->name));
  1658.     for (i = 0; i < (sizeof(autospeeds) / sizeof(int)); i++) {
  1659. if(at2_test_speed(privdata, autospeeds[i]) == 0) {
  1660.     privdata->speed = autospeeds[i];
  1661.     break;
  1662. }
  1663.     }
  1664.     if (privdata->speed == 0) {
  1665.         info(0, "AT2[%s]: cannot detect speed", octstr_get_cstr(privdata->name));
  1666.         return -1;
  1667.     }
  1668.     info(0, "AT2[%s]: detect speed is %ld", octstr_get_cstr(privdata->name), privdata->speed);
  1669.     return 0;
  1670. }
  1671. int at2_test_speed(PrivAT2data *privdata, long speed) {
  1672.     int res;
  1673.     if (at2_open_device1(privdata) == -1)
  1674. return -1;
  1675.     at2_set_speed(privdata, speed);
  1676.     /* send a return so the modem can detect the speed */
  1677.     res = at2_send_modem_command(privdata, "", 1, 0); 
  1678.     res = at2_send_modem_command(privdata, "AT", 0, 0);
  1679.     if (res != 0)
  1680. res = at2_send_modem_command(privdata, "AT", 0, 0);
  1681.     if (res != 0)
  1682. res = at2_send_modem_command(privdata, "AT", 0, 0);
  1683.     at2_close_device(privdata);
  1684.     return res;
  1685. }
  1686. int at2_detect_modem_type(PrivAT2data *privdata)
  1687. {
  1688.     int res;
  1689.     ModemDef *modem;
  1690.     int i;
  1691.     debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem type", octstr_get_cstr(privdata->name));
  1692.     if (at2_open_device1(privdata) == -1)
  1693.         return -1;
  1694.     at2_set_speed(privdata, privdata->speed);
  1695.     /* send a return so the modem can detect the speed */
  1696.     res = at2_send_modem_command(privdata, "", 1, 0); 
  1697.     res = at2_send_modem_command(privdata, "AT", 0, 0);
  1698.     if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1)
  1699.         return -1;
  1700.     if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1)
  1701.         return -1;
  1702.     at2_flush_buffer(privdata);
  1703.     if (at2_send_modem_command(privdata, "ATI", 0, 0) == -1)
  1704.         return -1;
  1705.     /* we try to detect the modem automatically */
  1706.     i = 1;
  1707.     while ((modem = at2_read_modems(privdata, privdata->configfile, NULL, i++)) != NULL) {
  1708.         if (octstr_len(modem->detect_string) == 0) {
  1709.             at2_destroy_modem(modem);
  1710.             continue;
  1711.         }
  1712.         /* 
  1713.         debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), 
  1714.               octstr_get_cstr(modem->name)); 
  1715.         */
  1716.         if (octstr_search(privdata->lines, modem->detect_string, 0) != -1) {
  1717.             if (octstr_len(modem->detect_string2) == 0) {
  1718.                 debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>", 
  1719.                       octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), 
  1720.                       octstr_get_cstr(modem->name));
  1721.                 privdata->modem = modem;
  1722.                 break;
  1723.             } else {
  1724.                 if (octstr_search(privdata->lines, modem->detect_string2, 0) != -1) {
  1725.                     debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s> plus <%s>, using modem "
  1726.                           "definition <%s>", octstr_get_cstr(privdata->name), 
  1727.                           octstr_get_cstr(modem->detect_string), 
  1728.                           octstr_get_cstr(modem->detect_string2), 
  1729.                           octstr_get_cstr(modem->name));
  1730.                     privdata->modem = modem;
  1731.                     break;
  1732.                 }
  1733.             }
  1734.         }
  1735.     }
  1736.     if (privdata->modem == NULL) {
  1737.         debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic", 
  1738.               octstr_get_cstr(privdata->name));
  1739.         if ((modem = at2_read_modems(privdata, privdata->configfile, octstr_imm("generic"), 0)) == NULL) {
  1740.             panic(0, "AT2[%s]: Cannot detect modem and generic not found", 
  1741.                   octstr_get_cstr(privdata->name));
  1742.         } else {
  1743.             privdata->modem = modem;
  1744.         }
  1745.     }
  1746.     /* lets see if it supports GSM SMS 2+ mode */
  1747.     res = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
  1748.     if (res != 0)
  1749.         /* if it doesnt even understand the command, I'm sure it won't support it */
  1750.         privdata->phase2plus = 0; 
  1751.     else {
  1752.         /* we have to take a part a string like +CSMS: (0,1,128) */
  1753.         Octstr *ts;
  1754.         int i;
  1755.         List *vals;
  1756.         ts = privdata->lines;
  1757.         privdata->lines = NULL;
  1758.         i = octstr_search_char(ts, '(', 0);
  1759.         if (i > 0) {
  1760.             octstr_delete(ts, 0, i + 1);
  1761.         }
  1762.         i = octstr_search_char(ts, ')', 0);
  1763.         if (i > 0) {
  1764.             octstr_truncate(ts, i);
  1765.         }
  1766.         vals = octstr_split(ts, octstr_imm(","));
  1767.         octstr_destroy(ts);
  1768.         ts = list_search(vals, octstr_imm("1"), (void*) octstr_item_match);
  1769.         if (ts)
  1770.             privdata->phase2plus = 1;
  1771.         list_destroy(vals, octstr_destroy_item);
  1772.     }
  1773.     if (privdata->phase2plus)
  1774.         info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name));
  1775.     at2_close_device(privdata);
  1776.     return 0;
  1777. }
  1778. ModemDef *at2_read_modems(PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber)
  1779. {
  1780.     Cfg *cfg;
  1781.     List *grplist;
  1782.     CfgGroup *grp;
  1783.     Octstr *p;
  1784.     ModemDef *modem;
  1785.     int i = 1;
  1786.     /* 
  1787.      * Use id and idnumber=0 or id=NULL and idnumber > 0 
  1788.      */
  1789.     if (octstr_len(id) == 0 && idnumber == 0)
  1790.         return NULL;
  1791.     if (idnumber == 0)
  1792.         debug("bb.smsc.at2", 0, "AT2[%s]: Reading modem definitions from <%s>", 
  1793.               octstr_get_cstr(privdata->name), octstr_get_cstr(file));
  1794.     cfg = cfg_create(file);
  1795.     if (cfg_read(cfg) == -1)
  1796.         panic(0, "Cannot read modem definition file");
  1797.     grplist = cfg_get_multi_group(cfg, octstr_imm("modems"));
  1798.     if (idnumber == 0)
  1799.         debug("bb.smsc.at2", 0, "AT2[%s]: Found <%ld> modems in config", 
  1800.               octstr_get_cstr(privdata->name), list_len(grplist));
  1801.     if (grplist == NULL)
  1802.         panic(0, "Where are the modem definitions ?!?!");
  1803.     grp = NULL;
  1804.     while (grplist && (grp = list_extract_first(grplist)) != NULL) {
  1805.         p = cfg_get(grp, octstr_imm("id"));
  1806.         if (p == NULL) {
  1807.             info(0, "Modems group without id, bad");
  1808.             continue;
  1809.         }
  1810.         /* Check by id */
  1811.         if (octstr_len(id) != 0 && octstr_compare(p, id) == 0) {
  1812.             O_DESTROY(p);
  1813.             break;
  1814.         }
  1815.         /* Check by idnumber */
  1816.         if (octstr_len(id) == 0 && idnumber == i) {
  1817.             O_DESTROY(p);
  1818.             break;
  1819.         }
  1820.         O_DESTROY(p);
  1821.         i++;
  1822.         grp = NULL;
  1823.     }
  1824.     if (grplist != NULL)
  1825.         list_destroy(grplist, NULL);
  1826.     if (grp != NULL) {
  1827.         modem = gw_malloc(sizeof(ModemDef));
  1828.         modem->id = cfg_get(grp, octstr_imm("id"));
  1829.         modem->name = cfg_get(grp, octstr_imm("name"));
  1830.         if (modem->name == NULL)
  1831.             modem->name = octstr_duplicate(modem->id);
  1832.         modem->detect_string = cfg_get(grp, octstr_imm("detect-string"));
  1833.         modem->detect_string2 = cfg_get(grp, octstr_imm("detect-string2"));
  1834.         modem->init_string = cfg_get(grp, octstr_imm("init-string"));
  1835.         if (modem->init_string == NULL)
  1836.             modem->init_string = octstr_create("AT+CNMI=1,2,0,1,0");
  1837.         modem->speed = 9600;
  1838.         cfg_get_integer(&modem->speed, grp, octstr_imm("speed"));
  1839.         cfg_get_bool(&modem->need_sleep, grp, octstr_imm("need-sleep"));
  1840.         modem->enable_hwhs = cfg_get(grp, octstr_imm("enable-hwhs"));
  1841.         if (modem->enable_hwhs == NULL)
  1842.             modem->enable_hwhs = octstr_create("AT+IFC=2,2");
  1843.         cfg_get_bool(&modem->no_pin, grp, octstr_imm("no-pin"));
  1844.         cfg_get_bool(&modem->no_smsc, grp, octstr_imm("no-smsc"));
  1845.         modem->sendline_sleep = 100;
  1846.         cfg_get_integer(&modem->sendline_sleep, grp, octstr_imm("sendline-sleep"));
  1847.         modem->keepalive_cmd = cfg_get(grp, octstr_imm("keepalive-cmd"));
  1848.         if (modem->keepalive_cmd == NULL)
  1849.             modem->keepalive_cmd = octstr_create("AT");
  1850.         modem->message_storage = cfg_get(grp, octstr_imm("message-storage"));
  1851.         cfg_get_bool(&modem->enable_mms, grp, octstr_imm("enable-mms"));
  1852.         /*
  1853.         if (modem->message_storage == NULL)
  1854.             modem->message_storage = octstr_create("SM");
  1855.         */
  1856.         cfg_get_bool(&modem->broken, grp, octstr_imm("broken"));
  1857.         cfg_destroy(cfg);
  1858.         return modem;
  1859.     } else {
  1860.         cfg_destroy(cfg);
  1861.         return NULL;
  1862.     }
  1863. }
  1864. void at2_destroy_modem(ModemDef *modem)
  1865. {
  1866.     if (modem != NULL) {
  1867.         O_DESTROY(modem->id);
  1868.         O_DESTROY(modem->name);
  1869.         O_DESTROY(modem->detect_string);
  1870.         O_DESTROY(modem->detect_string2);
  1871.         O_DESTROY(modem->init_string);
  1872.         O_DESTROY(modem->enable_hwhs);
  1873.         O_DESTROY(modem->keepalive_cmd);
  1874.         O_DESTROY(modem->message_storage);
  1875.         gw_free(modem);
  1876.     }
  1877. }
  1878. int swap_nibbles(char byte)
  1879. {
  1880.     return ( ( byte & 15 ) * 10 ) + ( byte >> 4 );
  1881. }
  1882. Octstr* at2_format_address_field(Octstr* msisdn)
  1883. {
  1884.     int ntype = PNT_UNKNOWN;
  1885.     Octstr* out = octstr_create("");
  1886.     Octstr* temp = octstr_duplicate(msisdn);
  1887.     octstr_strip_blanks(temp);
  1888.     /*
  1889.      * Check for international numbers
  1890.      * number starting with '+' or '00' are international,
  1891.      * others are national.
  1892.      */
  1893.     if (strncmp(octstr_get_cstr(msisdn), "+", 1) == 0) {
  1894. octstr_delete(temp, 0, 1);
  1895.         ntype = PNT_INTER; /* international */
  1896.     } else if (strncmp(octstr_get_cstr(msisdn), "00", 2) == 0) {
  1897.         octstr_delete(temp, 0, 2);
  1898.         ntype = PNT_INTER; /* international */
  1899.     }
  1900.     /* address length */
  1901.     octstr_append_char(out, octstr_len(temp));
  1902.     /* Type of address : bit mapped values */
  1903.     octstr_append_char(out, 0x80 /* Type-of-address prefix */ |
  1904.     0x01 /* Numbering-plan: MSISDN */ |
  1905.     (ntype == PNT_INTER ? 0x10 : 0x00) /* Type-of-number: International or National */
  1906.     );
  1907.     /* grab the digits from the MSISDN and encode as swapped semi-octets */
  1908.     while (octstr_len(temp)) {
  1909. int digit1, digit2;
  1910. /* get the first two digit */
  1911. digit1 = octstr_get_char(temp,0) - 48;
  1912. if ((digit2 = octstr_get_char(temp,1) - 48) < 0)
  1913.     digit2 = 0x0F;
  1914. octstr_append_char(out, (digit2 << 4) | digit1);
  1915. octstr_delete(temp, 0, 2);
  1916.     }
  1917.     O_DESTROY(temp);
  1918.     return out;
  1919. }