Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

smsc_at.c File Reference

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <time.h>
#include <math.h>
#include "gwlib/gwlib.h"
#include "gwlib/charset.h"
#include "smscconn.h"
#include "smscconn_p.h"
#include "bb_smscconn_cb.h"
#include "msg.h"
#include "sms.h"
#include "dlr.h"
#include "smsc_at.h"

Include dependency graph for smsc_at.c:

Include dependency graph

Go to the source code of this file.

Functions

Octstrgsm2number (Octstr *pdu)
unsigned char nibble2hex (unsigned char b)
void at2_scan_for_telnet_escapes (PrivAT2data *privdata)
int at2_open_device1 (PrivAT2data *privdata)
int at2_login_device (PrivAT2data *privdata)
int at2_open_device (PrivAT2data *privdata)
void at2_close_device (PrivAT2data *privdata)
void at2_read_buffer (PrivAT2data *privdata)
Octstrat2_wait_line (PrivAT2data *privdata, time_t timeout, int gt_flag)
Octstrat2_read_line (PrivAT2data *privdata, int gt_flag)
int at2_write_line (PrivAT2data *privdata, char *line)
int at2_write_ctrlz (PrivAT2data *privdata)
int at2_write (PrivAT2data *privdata, char *line)
void at2_flush_buffer (PrivAT2data *privdata)
int at2_init_device (PrivAT2data *privdata)
int at2_send_modem_command (PrivAT2data *privdata, char *cmd, time_t timeout, int gt_flag)
int at2_wait_modem_command (PrivAT2data *privdata, time_t timeout, int gt_flag, int *output)
int at2_read_delete_message (PrivAT2data *privdata, int message_number)
void at2_read_pending_incoming_messages (PrivAT2data *privdata)
int at2_read_sms_memory (PrivAT2data *privdata)
int at2_check_sms_memory (PrivAT2data *privdata)
void at2_set_speed (PrivAT2data *privdata, int bps)
void at2_device_thread (void *arg)
int at2_shutdown_cb (SMSCConn *conn, int finish_sending)
long at2_queued_cb (SMSCConn *conn)
void at2_start_cb (SMSCConn *conn)
int at2_add_msg_cb (SMSCConn *conn, Msg *sms)
int smsc_at2_create (SMSCConn *conn, CfgGroup *cfg)
int at2_pdu_extract (PrivAT2data *privdata, Octstr **pdu, Octstr *line, Octstr *smsc_number)
int at2_hexchar (int hexc)
Msgat2_pdu_decode (Octstr *data, PrivAT2data *privdata)
Msgat2_pdu_decode_deliver_sm (Octstr *data, PrivAT2data *privdata)
Msgat2_pdu_decode_report_sm (Octstr *data, PrivAT2data *privdata)
Octstrat2_convertpdu (Octstr *pdutext)
void at2_decode7bituncompressed (Octstr *input, int len, Octstr *decoded, int offset)
void at2_send_messages (PrivAT2data *privdata)
void at2_send_one_message (PrivAT2data *privdata, Msg *msg)
Octstrat2_pdu_encode (Msg *msg, PrivAT2data *privdata)
Octstrat2_encode7bituncompressed (Octstr *source, int offset)
Octstrat2_encode8bituncompressed (Octstr *input)
int at2_numtext (int num)
int at2_detect_speed (PrivAT2data *privdata)
int at2_test_speed (PrivAT2data *privdata, long speed)
int at2_detect_modem_type (PrivAT2data *privdata)
ModemDefat2_read_modems (PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber)
void at2_destroy_modem (ModemDef *modem)
int swap_nibbles (unsigned char byte)
Octstrat2_format_address_field (Octstr *msisdn)
int at2_set_message_storage (PrivAT2data *privdata, Octstr *memory_name)
const char * at2_error_string (int code)

Variables

int at2_rmask [8] = { 0, 1, 3, 7, 15, 31, 63, 127 }
int at2_lmask [8] = { 0, 128, 192, 224, 240, 248, 252, 254 }


Function Documentation

int at2_add_msg_cb SMSCConn conn,
Msg sms
[static]
 

Definition at line 1452 of file smsc_at.c.

References smscconn::data, PrivAT2data::device_thread, gw_prioqueue_produce, gwthread_wakeup(), msg_duplicate(), PrivAT2data::outgoing_queue, sms, and SMSCConn.

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 }

Here is the call graph for this function:

int at2_check_sms_memory PrivAT2data privdata  )  [static]
 

Definition at line 1100 of file smsc_at.c.

References at2_send_modem_command(), debug(), PrivAT2data::lines, PrivAT2data::name, O_DESTROY, octstr_create, octstr_get_cstr, octstr_imm(), octstr_len(), octstr_parse_long(), octstr_search(), PrivAT2data::sms_memory_capacity, and PrivAT2data::sms_memory_usage.

01101 {
01102     long values[4]; /* array to put response data in */
01103     int pos; /* position of parser in data stream */
01104     int ret;
01105     Octstr *search_cpms = NULL;
01106 
01107     /* select memory type and get report */
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         /* got back a +CPMS response */
01117         int index = 0; /* index in values array */
01118         pos += 6; /* position of parser in the stream - start after header */
01119 
01120         /* skip memory indication */
01121         pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; 
01122 
01123         /* find all the values */
01124         while (index < 4 && pos < octstr_len(privdata->lines) &&
01125                (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { 
01126             ++pos; /* skip number seperator */
01127             ++index; /* increment array index */
01128             if (index == 2)
01129                 /* skip second memory indication */
01130                 pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; 
01131         }
01132 
01133         if (index < 4) { 
01134             /* didn't get all memory data - I don't why, so I'll bail */
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         privdata->output_mem_sms_used = values[2];
01146         privdata->output_mem_sms_capacity = values[3];
01147         */
01148 
01149         /* everything's cool */
01150         ret = 0; 
01151 
01152         /*  clear the buffer */
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         /* didn't get a +CPMS response - this is clearly an error */
01160         ret = -1; 
01161     }
01162 
01163     O_DESTROY(search_cpms);
01164     return ret;
01165 }

Here is the call graph for this function:

void at2_close_device PrivAT2data privdata  )  [static]
 

Definition at line 278 of file smsc_at.c.

References PrivAT2data::fd, PrivAT2data::ilb, info(), PrivAT2data::name, octstr_create, octstr_destroy(), octstr_get_cstr, PrivAT2data::phase2plus, and PrivAT2data::pin_ready.

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 }

Here is the call graph for this function:

Octstr* at2_convertpdu Octstr pdutext  )  [static]
 

Definition at line 2088 of file smsc_at.c.

References at2_hexchar(), octstr_append_char(), octstr_create, octstr_get_char(), octstr_len(), and pdu.

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 }

Here is the call graph for this function:

void at2_decode7bituncompressed Octstr input,
int  len,
Octstr decoded,
int  offset
[static]
 

Definition at line 2106 of file smsc_at.c.

References at2_lmask, at2_rmask, charset_gsm_to_utf8(), octstr_append_char(), octstr_get_char(), octstr_get_cstr, and octstr_len().

02107 {
02108     unsigned char septet, octet, prevoctet;
02109     int i;
02110     int r = 1;
02111     int c = 7;
02112     int pos = 0;
02113 
02114     /* Shift the buffer offset bits to the left */
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         /* When r=7 we have a full character in prevoctet */
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 }

Here is the call graph for this function:

void at2_destroy_modem ModemDef modem  )  [static]
 

Definition at line 2765 of file smsc_at.c.

References ModemDef::detect_string, ModemDef::detect_string2, ModemDef::enable_hwhs, ModemDef::id, ModemDef::init_string, ModemDef::keepalive_cmd, ModemDef::message_storage, ModemDef::name, O_DESTROY, and ModemDef::reset_string.

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 }

int at2_detect_modem_type PrivAT2data privdata  )  [static]
 

Definition at line 2540 of file smsc_at.c.

References at2_close_device(), at2_destroy_modem(), at2_flush_buffer(), at2_open_device(), at2_read_modems(), at2_send_modem_command(), at2_set_speed(), PrivAT2data::configfile, debug(), ModemDef::detect_string, ModemDef::detect_string2, gwlist_destroy(), gwlist_search(), info(), PrivAT2data::lines, PrivAT2data::modem, ModemDef::name, PrivAT2data::name, octstr_delete(), octstr_destroy(), octstr_destroy_item(), octstr_get_cstr, octstr_imm(), octstr_item_match(), octstr_len(), octstr_search(), octstr_search_char(), octstr_split(), octstr_truncate(), panic, PrivAT2data::phase2plus, res, and PrivAT2data::speed.

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     /* send a return so the modem can detect the speed */
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     /* we try to detect the modem automatically */
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         debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), 
02577               octstr_get_cstr(modem->name)); 
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             /* Destroy modem */
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     /* lets see if it supports GSM SMS 2+ mode */
02616     res = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
02617     if (res != 0)
02618         /* if it doesnt even understand the command, I'm sure it won't support it */
02619         privdata->phase2plus = 0; 
02620     else {
02621         /* we have to take a part a string like +CSMS: (0,1,128) */
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 }

Here is the call graph for this function:

int at2_detect_speed PrivAT2data privdata  )  [static]
 

Definition at line 2486 of file smsc_at.c.

References at2_test_speed(), debug(), info(), PrivAT2data::name, octstr_get_cstr, and PrivAT2data::speed.

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 }

Here is the call graph for this function:

void at2_device_thread void *  arg  )  [static]
 

Definition at line 1228 of file smsc_at.c.

References at2_close_device(), at2_destroy_modem(), at2_detect_modem_type(), at2_detect_speed(), at2_init_device(), at2_login_device(), at2_open_device(), at2_read_pending_incoming_messages(), at2_read_sms_memory(), at2_send_messages(), at2_send_modem_command(), at2_test_speed(), at2_wait_modem_command(), bb_smscconn_connected(), bb_smscconn_killed(), PrivAT2data::configfile, smscconn::connect_time, smscconn::data, PrivAT2data::device, error(), PrivAT2data::fd, smscconn::flow_mutex, gw_prioqueue_destroy(), gw_prioqueue_len(), gwlist_destroy(), gwlist_len(), gwthread_sleep(), PrivAT2data::ilb, info(), PrivAT2data::keepalive, ModemDef::keepalive_cmd, PrivAT2data::lines, smscconn::log_idx, log_thread_to(), PrivAT2data::max_error_count, PrivAT2data::modem, mutex_lock, mutex_unlock, PrivAT2data::my_number, PrivAT2data::name, octstr_destroy(), octstr_destroy_item(), octstr_get_cstr, PrivAT2data::outgoing_queue, PrivAT2data::pending_incoming_messages, PrivAT2data::pin, smscconn::reconnect_delay, ModemDef::reset_string, PrivAT2data::shutdown, PrivAT2data::sms_center, PrivAT2data::sms_memory_poll_interval, SMSCConn, ModemDef::speed, PrivAT2data::speed, smscconn::status, PrivAT2data::validityperiod, and smscconn::why_killed.

Referenced by smsc_at2_create().

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     /* Make sure we log into our own log-file if defined */
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         /* If modems->speed is defined, try to use it, else autodetect */
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         /* If we got here, then the device is opened */
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         /* read error, so re-connect */
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     /* maybe some cleanup here? */
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 }

Here is the call graph for this function:

Octstr* at2_encode7bituncompressed Octstr source,
int  offset
[static]
 

Definition at line 2425 of file smsc_at.c.

References octstr_append_char(), octstr_create, octstr_get_char(), and octstr_len().

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     /* start packing the septet stream into an octet stream */
02436     for (posS = 0, posT = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) {
02437         /* grab least significant bits from current septet and 
02438          * store them packed to the right */
02439         target_chr |= (source_chr & LSBmask[i]) << iStore;
02440         /* store current byte if last command filled it */
02441         if (iStore != 0) {
02442             destRemain--;
02443             octstr_append_char(target, target_chr);
02444             target_chr = 0;
02445         }
02446         /* grab most significant bits from current septet and 
02447          * store them packed to the left */
02448         target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8;
02449         /* advance target bit index by 7 (modulo 8 addition ) */
02450         iStore = (--iStore < 0 ? 7 : iStore);
02451         /* if just finished packing 8 septets (into 7 octets) don't advance mask index */
02452         if (iStore != 0) 
02453             i = (++i > 7 ? 1 : i); 
02454     }
02455 
02456     /* don't forget to pack the leftovers ;-) */
02457     if (destRemain > 0)
02458         octstr_append_char(target, target_chr);
02459 
02460     return target;
02461 }

Here is the call graph for this function:

Octstr* at2_encode8bituncompressed Octstr input  )  [static]
 

Definition at line 2464 of file smsc_at.c.

References at2_numtext(), octstr_append_char(), octstr_create, octstr_get_char(), and octstr_len().

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         /* each character is encoded in its hex representation (2 chars) */
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 }

Here is the call graph for this function:

const char* at2_error_string int  code  )  [static]
 

Definition at line 2856 of file smsc_at.c.

Referenced by at2_wait_modem_command().

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 }

void at2_flush_buffer PrivAT2data privdata  )  [static]
 

Definition at line 548 of file smsc_at.c.

References at2_read_buffer(), PrivAT2data::ilb, octstr_create, and octstr_destroy().

00549 {
00550     at2_read_buffer(privdata);
00551     octstr_destroy(privdata->ilb);
00552     privdata->ilb = octstr_create("");
00553 }

Here is the call graph for this function:

Octstr* at2_format_address_field Octstr msisdn  )  [static]
 

Definition at line 2788 of file smsc_at.c.

References O_DESTROY, octstr_append_char(), octstr_create, octstr_delete(), octstr_duplicate, octstr_get_char(), octstr_get_cstr, octstr_len(), octstr_strip_blanks(), and PNT_INTER.

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      * Check for international numbers
02797      * number starting with '+' or '00' are international,
02798      * others are national.
02799      */
02800     if (strncmp(octstr_get_cstr(msisdn), "+", 1) == 0) {
02801     octstr_delete(temp, 0, 1);
02802         ntype = PNT_INTER; /* international */
02803     } else if (strncmp(octstr_get_cstr(msisdn), "00", 2) == 0) {
02804         octstr_delete(temp, 0, 2);
02805         ntype = PNT_INTER; /* international */
02806     }
02807 
02808     /* address length */
02809     octstr_append_char(out, octstr_len(temp));
02810 
02811     /* Type of address : bit mapped values */
02812     octstr_append_char(out, 0x80 /* Type-of-address prefix */ |
02813                 0x01 /* Numbering-plan: MSISDN */ |
02814                 (ntype == PNT_INTER ? 0x10 : 0x00) /* Type-of-number: International or National */
02815                 );
02816 
02817     /* grab the digits from the MSISDN and encode as swapped semi-octets */
02818     while (out != NULL && octstr_len(temp) > 0) {
02819     int digit1, digit2;
02820     /* get the first two digit */
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 }

Here is the call graph for this function:

int at2_hexchar int  hexc  )  [static]
 

Definition at line 1757 of file smsc_at.c.

01758 {
01759     hexc = toupper(hexc) - 48;
01760     return (hexc > 9) ? hexc - 7 : hexc;
01761 }

int at2_init_device PrivAT2data privdata  )  [static]
 

Definition at line 556 of file smsc_at.c.

References at2_flush_buffer(), at2_send_modem_command(), at2_set_message_storage(), at2_set_speed(), at2_wait_modem_command(), ModemDef::enable_hwhs, error(), gwlist_destroy(), gwlist_search(), gwthread_sleep(), info(), ModemDef::init_string, PrivAT2data::lines, ModemDef::message_storage, PrivAT2data::modem, PrivAT2data::name, ModemDef::no_pin, octstr_append(), octstr_append_char(), octstr_create, octstr_delete(), octstr_destroy(), octstr_destroy_item(), octstr_format(), octstr_get_cstr, octstr_imm(), octstr_item_match(), octstr_len(), octstr_search_char(), octstr_split(), octstr_truncate(), PrivAT2data::phase2plus, PrivAT2data::pin, PrivAT2data::pin_ready, PrivAT2data::sms_center, PrivAT2data::sms_memory_poll_interval, and PrivAT2data::speed.

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     /* sleep 10 ms in order to get device some time to accept speed */
00565     gwthread_sleep(0.10);
00566 
00567     /* reset the modem */
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     /* check if the modem responded */
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     /* check if the modem responded */
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     /* enable hardware handshake */
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      * Check does the modem require a PIN and, if so, send it.
00620      * This is not supported by the Nokia Premicell 
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          * we have to wait until +CPIN: READY appears before issuing
00640          * the next command. 10 sec should be suficient 
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; /* give up */
00648                 }
00649             }
00650         }
00651     }
00652     /* 
00653      * Set the GSM SMS message center address if supplied 
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          * XXX If some modem don't process the +, remove it and add ",145"
00663          * and ",129" to national numbers
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     /* Set the modem to PDU mode and autodisplay of new messages */
00676     ret = at2_send_modem_command(privdata, "AT+CMGF=0", 0, 0);
00677     if (ret != 0 )
00678         return -1;
00679 
00680     /* lets see if it supports GSM SMS 2+ mode */
00681     ret = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0);
00682     if (ret != 0) {
00683         /* if it doesnt even understand the command, I'm sure it wont support it */
00684         privdata->phase2plus = 0; 
00685     } else {
00686         /* we have to take a part a string like +CSMS: (0,1,128) */
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     /* send init string */
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         /* set message storage location for "SIM buffering" using the CPMS command */
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 }

Here is the call graph for this function:

int at2_login_device PrivAT2data privdata  )  [static]
 

Definition at line 201 of file smsc_at.c.

References at2_read_buffer(), at2_send_modem_command(), at2_wait_modem_command(), gwthread_sleep(), info(), PrivAT2data::name, octstr_get_cstr, octstr_len(), PrivAT2data::password, and PrivAT2data::username.

Referenced by at2_device_thread().

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);  /* wait for Password: prompt */
00211         at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0); /* wait for OK: */
00212         at2_send_modem_command(privdata, "AT", 2,0); /* wait for OK: */
00213     }
00214     else if((octstr_len(privdata->username) > 0 ) && (octstr_len(privdata->password)> 0)) {
00215         at2_wait_modem_command(privdata, 10, 2, NULL);  /* wait for Login: prompt */
00216         at2_send_modem_command(privdata, octstr_get_cstr(privdata->username), 10,3); /* wait fo Password: */
00217         at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0); /* wait for OK: */
00218         at2_send_modem_command(privdata, "AT", 2,0); /* wait for OK: */
00219     }
00220 
00221     return 0;
00222 }

Here is the call graph for this function:

int at2_numtext int  num  )  [static]
 

Definition at line 2480 of file smsc_at.c.

02481 {
02482     return (num > 9) ? (num + 55) : (num + 48);
02483 }

int at2_open_device PrivAT2data privdata  )  [static]
 

Definition at line 225 of file smsc_at.c.

References at2_open_device1(), debug(), error(), PrivAT2data::fd, PrivAT2data::is_serial, kannel_cfmakeraw(), PrivAT2data::modem, PrivAT2data::name, ModemDef::need_sleep, and octstr_get_cstr.

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; /* ignore break & parity errors */
00241     tios.c_iflag &= ~INPCK; /* INPCK: disable parity check */
00242     tios.c_cflag |= HUPCL; /* hangup on close */
00243     tios.c_cflag |= CREAD; /* enable receiver */
00244     tios.c_cflag |= CLOCAL; /* Ignore modem control lines */
00245     tios.c_cflag &= ~CSIZE; /* set to 8 bit */
00246     tios.c_cflag |= CS8;
00247     tios.c_oflag &= ~ONLCR; /* no NL to CR-NL mapping outgoing */
00248     tios.c_iflag |= IGNPAR; /* ignore parity */
00249     tios.c_iflag &= ~INPCK;
00250 #if defined(CRTSCTS)
00251     tios.c_cflag |= CRTSCTS; /* enable hardware flow control */
00252 #endif
00253     tios.c_cc[VSUSP] = 0; /* otherwhise we can not send CTRL Z */
00254 
00255     /*
00256     if ( ModemTypes[privdata->modemid].enable_parity )
00257         tios.c_cflag ^= PARODD;
00258     */
00259 
00260     ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */
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      * Nokia 7110 and 6210 need some time between opening
00269      * the connection and sending the first AT commands 
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 }

Here is the call graph for this function:

int at2_open_device1 PrivAT2data privdata  )  [static]
 

Definition at line 163 of file smsc_at.c.

References at2_close_device(), debug(), PrivAT2data::device, error(), PrivAT2data::fd, gw_assert, info(), PrivAT2data::is_serial, PrivAT2data::name, octstr_get_cstr, octstr_str_compare(), PrivAT2data::rawtcp_host, PrivAT2data::rawtcp_port, tcpip_connect_to_server(), PrivAT2data::use_telnet, and warning().

Referenced by at2_open_device().

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 }

Here is the call graph for this function:

Msg* at2_pdu_decode Octstr data,
PrivAT2data privdata
[static]
 

Definition at line 1764 of file smsc_at.c.

References at2_pdu_decode_deliver_sm(), at2_pdu_decode_report_sm(), AT_DELIVER_SM, AT_STATUS_REPORT_SM, data, octstr_get_char(), and type.

01765 {
01766     int type;
01767     Msg *msg = NULL;
01768 
01769     /* Get the PDU type */
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             /* Add other message types here: */
01782     }
01783 
01784     return msg;
01785 }

Here is the call graph for this function:

Msg* at2_pdu_decode_deliver_sm Octstr data,
PrivAT2data privdata
[static]
 

Definition at line 1788 of file smsc_at.c.

References at2_convertpdu(), at2_decode7bituncompressed(), data, date_convert_universal(), universaltime::day, DC_8BIT, dcs_to_fields(), debug(), error(), universaltime::hour, message, universaltime::minute, universaltime::month, msg_create, PrivAT2data::my_number, PrivAT2data::name, O_DESTROY, octstr_append_char(), octstr_copy, octstr_create, octstr_create_from_data, octstr_destroy(), octstr_duplicate, octstr_get_char(), octstr_get_cstr, octstr_len(), pdu, universaltime::second, sms, swap_nibbles(), text, and universaltime::year.

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; /* time structure */
01798     long stime; /* time in seconds */
01799     int timezone; /* timezone in 15 minutes jumps from GMT */
01800 
01801     /* 
01802      * Note: some parts of the PDU are not decoded because they are
01803      * not needed for the Msg type. 
01804      */
01805 
01806     /* convert the pdu to binary format for ease of processing */
01807     pdu = at2_convertpdu(data);
01808 
01809     /* UDH Indicator */
01810     udhi = (octstr_get_char(pdu, 0) & 64) >> 6;
01811 
01812     /* originating address */
01813     len = octstr_get_char(pdu, 1);
01814     if (len > 20) /* maximum valid number of semi-octets in Address-Value field */
01815         goto msg_error;
01816     ntype = octstr_get_char(pdu, 2);
01817 
01818     pos = 3;
01819     if ((ntype & 0xD0) == 0xD0) {
01820         /* Alphanumeric sender */
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             /* International number */
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     /* PID */
01848     pid = octstr_get_char(pdu, pos);
01849     pos++;
01850 
01851     /* DCS */
01852     dcs = octstr_get_char(pdu, pos);
01853     pos++;
01854 
01855     /* get the timestamp */
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      * time zone: 
01873      *
01874      * time zone is "swapped nibble", with the MSB as the sign (1 is negative).  
01875      */
01876     timezone = swap_nibbles(octstr_get_char(pdu, pos));
01877     pos++;
01878     timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127);
01879     /* 
01880      * Ok, that was the time zone as read from the PDU. Now how to interpert it? 
01881      * All the handsets I tested send the timestamp of their local time and the 
01882      * timezone as GMT+0. I assume that the timestamp is the handset's local time, 
01883      * so we need to apply the timezone in reverse to get GM time: 
01884      */
01885 
01886     /* 
01887      * time in PDU is handset's local time and timezone is handset's time zone 
01888      * difference from GMT 
01889      */
01890     mtime.hour -= timezone / 4;
01891     mtime.minute -= 15 * (timezone % 4);
01892 
01893     stime = date_convert_universal(&mtime);
01894 
01895     /* get data length
01896      * XXX: Is it allowed to have length = 0 ??? (alex)
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     /* if there is a UDH */
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) /* len < 0 is impossible, but sure is sure */
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     /* build the message */
01924     message = msg_create(sms);
01925     if (!dcs_to_fields(&message, dcs)) {
01926         /* XXX Should reject this message? */
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     /* deal with the user data -- 7 or 8 bit encoded */
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             /* fill bits for UDH to septet boundary */
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         /* Put a dummy address in the receiver for now (SMSC requires one) */
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     /* cleanup */
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 }

Here is the call graph for this function:

Msg* at2_pdu_decode_report_sm Octstr data,
PrivAT2data privdata
[static]
 

Definition at line 1978 of file smsc_at.c.

References at2_convertpdu(), at2_decode7bituncompressed(), PrivAT2data::conn, data, debug(), dlr_find(), error(), smscconn::id, PrivAT2data::name, O_DESTROY, octstr_append_char(), octstr_copy, octstr_create, octstr_destroy(), octstr_duplicate, octstr_format(), octstr_get_char(), octstr_get_cstr, pdu, and type.

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      * parse the PDU.
01986      */
01987 
01988     /* convert the pdu to binary format for ease of processing */
01989     pdu = at2_convertpdu(data);
01990 
01991     /* Message reference */
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     /* reciver address */
01998     len = octstr_get_char(pdu, 2);
01999     ntype = octstr_get_char(pdu, 3);
02000 
02001     pos = 4;
02002     if ((ntype & 0xD0) == 0xD0) {
02003         /* Alphanumeric sender */
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             /* International number */
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; /* skip time stamps for now */
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     /* Check DLR type:
02037      * 3GPP TS 23.040 defines this a bit mapped field with lots of options
02038      * most of which are not really intersting to us, as we are only interested
02039      * in one of three conditions : failed, held in SC for delivery later, or delivered successfuly
02040      * and here's how I suggest to test it (read the 3GPP reference for further detailes) -
02041      * we'll test the 6th and 5th bits (7th bit when set making all other values 'reseved' so I want to test it).
02042      */
02043     type = type & 0xE0; /* filter out everything but the 7th, 6th and 5th bits */
02044     switch (type) {
02045         case 0x00:
02046             /* 0 0 : success class */
02047             type = DLR_SUCCESS;
02048             tmpstr = octstr_create("Success");
02049             break;
02050         case 0x20:
02051             /* 0 1 : buffered class (temporary error) */
02052             type = DLR_BUFFERED;
02053             tmpstr = octstr_create("Buffered");
02054             break;
02055         case 0x40:
02056         case 0x60:
02057         default:
02058             /* 1 0 : failed class */
02059             /* 1 1 : failed class (actually, temporary error but timed out) */
02060             /* and any other value (can't think of any) is considered failure */
02061             type = DLR_FAIL;
02062             tmpstr = octstr_create("Failed");
02063             break;
02064     }
02065     /* Actually, the above implementation is not correct, as the reference 
02066      * says that implementations should consider any "reserved" values to be 
02067      * "failure", but most reserved values fall into one of the three 
02068      * categories. It will catch "reserved" values where the first 3 MSBits 
02069      * are not set as "Success" which may not be correct. */
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     /* Beware DLR URL is now in msg->sms.dlr_url given by dlr_find() */
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 }

Here is the call graph for this function:

Octstr* at2_pdu_encode Msg msg,
PrivAT2data privdata
[static]
 

Definition at line 2281 of file smsc_at.c.

References smscconn::alt_dcs, at2_encode7bituncompressed(), at2_encode8bituncompressed(), at2_format_address_field(), charset_utf8_to_gsm(), PrivAT2data::conn, DC_8BIT, debug(), DLR_IS_ENABLED_DEVICE, error(), fields_to_dcs(), PrivAT2data::name, O_DESTROY, octstr_append(), octstr_append_char(), octstr_create, octstr_delete(), octstr_get_cstr, octstr_len(), pdu, SMS_7BIT_MAX_LEN, SMS_8BIT_MAX_LEN, sms_msgdata_len(), and PrivAT2data::validityperiod.

02282 {
02283     /*
02284      * Message coding is done as a binary octet string,
02285      * as per 3GPP TS 23.040 specification (GSM 03.40),
02286      */
02287     Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create("");
02288     int len, setvalidity = 0;
02289 
02290     /* 
02291      * message type SUBMIT , bit mapped :
02292      * bit7                            ..                                    bit0
02293      * TP-RP , TP-UDHI, TP-SRR, TP-VPF(4), TP-VPF(3), TP-RD, TP-MTI(1), TP-MTI(0)
02294      */
02295     octstr_append_char(buffer,
02296         ((msg->sms.rpi > 0 ? 1 : 0) << 7) /* TP-RP */
02297         | ((octstr_len(msg->sms.udhdata)  ? 1 : 0) << 6) /* TP-UDHI */
02298         | ((DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask) ? 1 : 0) << 5) /* TP-SRR */
02299         | 16 /* TP-VP(Rel)*/
02300         | 1 /* TP-MTI: SUBMIT_SM */
02301     );
02302 
02303     /* message reference (0 for now) */
02304     octstr_append_char(buffer, 0);
02305 
02306     /* destination address */
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) ); /* protocol identifier */
02313     octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */
02314         (msg->sms.alt_dcs != -1 ? msg->sms.alt_dcs : privdata->conn->alt_dcs)));
02315 
02316     /* 
02317      * Validity-Period (TP-VP)
02318      * see GSM 03.40 section 9.2.3.12
02319      * defaults to 24 hours = 167 if not set 
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     /* user data length - include length of UDH if it exists */
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) { /* truncate user data to allow UDH to fit */
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              * The reason we branch here is because UDH data length is determined
02371              * in septets if we are in GSM coding, otherwise it's in octets. Adding 6
02372              * will ensure that for an octet length of 0, we get septet length 0,
02373              * and for octet length 1 we get septet length 2. 
02374              */
02375             int temp_len;
02376             len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7));
02377             if (len > SMS_7BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */
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)) /* udh */
02387         octstr_append(buffer, msg->sms.udhdata);
02388 
02389     /* user data */
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          * calculate the number of fill bits needed to align
02397          * the 7bit encoded user data on septet boundry
02398          */
02399         if (octstr_len(msg->sms.udhdata)) { /* Have UDH */
02400             int nbits = octstr_len(msg->sms.udhdata) * 8; /* Includes UDH length byte */
02401             offset = (((nbits / 7) + 1) * 7 - nbits) % 7; /* Fill bits */
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     /* convert PDU to HEX representation suitable for the AT2 command set */
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 }

Here is the call graph for this function:

int at2_pdu_extract PrivAT2data privdata,
Octstr **  pdu,
Octstr line,
Octstr smsc_number
[static]
 

Definition at line 1614 of file smsc_at.c.

References at2_hexchar(), ModemDef::broken, debug(), gsm2number(), PrivAT2data::modem, PrivAT2data::name, ModemDef::no_smsc, octstr_append(), octstr_copy, octstr_create_from_data, octstr_destroy(), octstr_duplicate, octstr_get_char(), octstr_get_cstr, octstr_hex_to_binary(), octstr_imm(), octstr_len(), octstr_parse_long(), octstr_search(), octstr_truncate(), and pdu.

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     /* find the beginning of a message from the modem*/
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             /* skip status field in +CMGR response */
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         /* skip the next comma in CMGR and CMT responses */
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     /* read the message length */
01649     pos = octstr_parse_long(&len, buffer, pos, 10);
01650     if (pos == -1)
01651         goto nomsg;
01652 
01653     /* skip the spaces and line return */
01654     while (isspace(octstr_get_char(buffer, pos)))
01655         pos++;
01656 
01657     octstr_truncate(smsc_number,0);
01658 
01659     /* skip the SMSC address on some modem types */
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);    /* we now have the hexchars of the SMSC in GSM encoding */
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     /* check if the buffer is long enough to contain the full message */
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     /* copy the PDU then remove it from the input buffer*/
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 }

Here is the call graph for this function:

long at2_queued_cb SMSCConn conn  )  [static]
 

Definition at line 1424 of file smsc_at.c.

References smscconn::data, gw_prioqueue_len(), smscconn::load, PrivAT2data::outgoing_queue, SMSCConn, and smscconn::status.

01425 {
01426     long ret;
01427     PrivAT2data *privdata = conn->data;
01428 
01429     if (conn->status == SMSCCONN_DEAD) /* I'm dead, why would you care ? */
01430         return -1;
01431 
01432     ret = gw_prioqueue_len(privdata->outgoing_queue);
01433 
01434     /* use internal queue as load, maybe something else later */
01435     conn->load = ret;
01436     return ret;
01437 }

Here is the call graph for this function:

void at2_read_buffer PrivAT2data privdata  )  [static]
 

Definition at line 291 of file smsc_at.c.

References at2_close_device(), at2_scan_for_telnet_escapes(), error(), PrivAT2data::fd, PrivAT2data::ilb, MAX_READ, PrivAT2data::name, octstr_append_data(), octstr_get_cstr, and PrivAT2data::use_telnet.

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 }

Here is the call graph for this function:

int at2_read_delete_message PrivAT2data privdata,
int  message_number
[static]
 

Definition at line 910 of file smsc_at.c.

References at2_send_modem_command(), at2_wait_modem_command(), at2_write_line(), debug(), error(), PrivAT2data::name, and octstr_get_cstr.

00911 {
00912     char cmd[20];
00913     int message_count = 0;
00914 
00915     sprintf(cmd, "AT+CMGR=%d", message_number);
00916     /* read one message from memory */
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; /* failed to read the message - skip to next message */
00922     }
00923 
00924     /* no need to delete if no message collected */
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); /* delete the message we just read */
00932     /* 
00933     * 3 seconds (default timeout of send_modem_command()) is not enough with some
00934     * modems if the message is large, so we'll give it 7 seconds 
00935     */
00936     if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) {  
00937         /* 
00938          * failed to delete the message, we'll just ignore it for now, 
00939          * this is bad, since if the message really didn't get deleted
00940          * we'll see it next time around. 
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 }

Here is the call graph for this function:

Octstr* at2_read_line PrivAT2data privdata,
int  gt_flag
[static]
 

Definition at line 362 of file smsc_at.c.

References at2_read_buffer(), at2_scan_for_telnet_escapes(), debug(), PrivAT2data::ilb, PrivAT2data::login_prompt, PrivAT2data::name, octstr_append_cstr(), octstr_copy, octstr_destroy(), octstr_get_char(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_search(), octstr_search_char(), octstr_set_char(), octstr_strip_blanks(), PrivAT2data::password, PrivAT2data::password_prompt, and PrivAT2data::username.

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         /* looking for > if needed */
00379         gtloc = octstr_search_char(privdata->ilb, '>', 0); 
00380     }
00381     else if((gt_flag == 2) && (privdata->username)) { /* looking for "Login" */
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)) {/* looking for 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     if (gt_flag && (gtloc != -1))
00407         debug("bb.smsc.at2", 0, "in at2_read_line with gt_flag=1, gtloc=%d, ilb=%s",
00408               gtloc, octstr_get_cstr(privdata->ilb));
00409     */
00410 
00411     eol = octstr_search_char(privdata->ilb, '\r', 0); /* looking for CR */
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     /* remove any non printable chars (including linefeed for example) */
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     /* empty line, skipping */
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         /* got to re-add it again as the parser needs to see it */
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 }

Here is the call graph for this function:

ModemDef* at2_read_modems PrivAT2data privdata,
Octstr file,
Octstr id,
int  idnumber
[static]
 

Definition at line 2651 of file smsc_at.c.

References ModemDef::broken, cfg_create(), cfg_destroy(), cfg_get, cfg_get_bool(), cfg_get_integer(), cfg_get_multi_group(), cfg_read(), debug(), ModemDef::detect_string, ModemDef::detect_string2, ModemDef::enable_hwhs, ModemDef::enable_mms, file, gwlist_destroy(), gwlist_extract_first(), gwlist_len(), ModemDef::id, info(), ModemDef::init_string, ModemDef::keepalive_cmd, ModemDef::message_storage, ModemDef::name, PrivAT2data::name, ModemDef::need_sleep, ModemDef::no_pin, ModemDef::no_smsc, O_DESTROY, octstr_compare(), octstr_create, octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), panic, ModemDef::reset_string, ModemDef::sendline_sleep, and ModemDef::speed.

02652 {
02653     Cfg *cfg;
02654     List *grplist;
02655     CfgGroup *grp;
02656     Octstr *p;
02657     ModemDef *modem;
02658     int i = 1;
02659 
02660     /* 
02661      * Use id and idnumber=0 or id=NULL and idnumber > 0 
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         /* Check by id */
02690         if (octstr_len(id) != 0 && octstr_compare(p, id) == 0) {
02691             O_DESTROY(p);
02692             break;
02693         }
02694         /* Check by idnumber */
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         if (modem->message_storage == NULL)
02750             modem->message_storage = octstr_create("SM");
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 }

Here is the call graph for this function:

void at2_read_pending_incoming_messages PrivAT2data privdata  )  [static]
 

Definition at line 956 of file smsc_at.c.

References at2_read_delete_message(), at2_set_message_storage(), error(), gwlist_extract_first(), gwlist_len(), info(), location, ModemDef::message_storage, PrivAT2data::modem, PrivAT2data::name, O_DESTROY, octstr_compare(), octstr_copy, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_parse_long(), octstr_search_char(), and PrivAT2data::pending_incoming_messages.

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         /* message memory starts after the first quote in the string */
00970         if ((pos = octstr_search_char(line, '"', 0)) != -1) {
00971             /* grab memory storage name */
00972             int next_quote = octstr_search_char(line, '"', ++pos);
00973             if (next_quote == -1) { /* no second qoute - this line must be broken somehow */
00974                 O_DESTROY(line);
00975                 continue;
00976             }
00977 
00978             /* store notification storage location for reference */
00979             cmti_storage = octstr_copy(line, pos, next_quote - pos);
00980         } else
00981             /* reset pos for the next lookup which would start from the beginning if no memory
00982              * location was found */
00983             pos = 0; 
00984 
00985         /* if no message storage is set in configuration - set now */
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         /* find the message id from the line, which should appear after the first comma */
00995         if ((pos = octstr_search_char(line, ',', pos)) == -1) { /* this CMTI notification is probably broken */
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             /* there was an error parsing the message id. next! */
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         /* check if we need to change storage location before issuing the read command */
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     /* set prefered message storage back to what configured */
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 }

Here is the call graph for this function:

int at2_read_sms_memory PrivAT2data privdata  )  [static]
 

Definition at line 1037 of file smsc_at.c.

References at2_check_sms_memory(), at2_read_delete_message(), at2_read_pending_incoming_messages(), debug(), gwlist_len(), PrivAT2data::name, octstr_get_cstr, PrivAT2data::pending_incoming_messages, PrivAT2data::sms_memory_capacity, and PrivAT2data::sms_memory_usage.

01038 {
01039     /* get memory status */
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          * that is - greater then 0, meaning there are some messages to fetch
01048          * now - I used to just loop over the first input_mem_sms_used locations, 
01049          * but it doesn't hold, since under load, messages may be received while 
01050          * we're in the loop, and get stored in locations towards the end of the list, 
01051          * thus creating 'holes' in the memory. 
01052          * 
01053          * There are two ways we can fix this : 
01054          *   (a) Just read the last message location, delete it and return.
01055          *       It's not a complete solution since holes can still be created if messages 
01056          *       are received between the memory check and the delete command, 
01057          *       and anyway - it will slow us down and won't hold well under pressure
01058          *   (b) Just scan the entire memory each call, bottom to top. 
01059          *       This will be slow too, but it'll be reliable.
01060          *
01061          * We can massivly improve performance by stopping after input_mem_sms_used messages
01062          * have been read, but send_modem_command returns 0 for no message as well as for a 
01063          * message read, and the only other way to implement it is by doing memory_check 
01064          * after each read and stoping when input_mem_sms_used get to 0. This is slow 
01065          * (modem commands take time) so we improve speed only if there are less then 10 
01066          * messages in memory.
01067          *
01068          * I implemented the alternative - changed at2_wait_modem_command to return the 
01069          * number of messages it collected.
01070          */
01071         int i;
01072         int message_count = 0; /* cound number of messages collected */
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          * loop till end of memory or collected enouch messages
01079          */
01080         for (i = 1; i <= privdata->sms_memory_capacity &&
01081              message_count < privdata->sms_memory_usage; ++i) { 
01082 
01083             /* if (meanwhile) there are pending CMTI notifications, process these first
01084              * to not let CMTI and sim buffering sit in each others way */
01085             while (gwlist_len(privdata->pending_incoming_messages) > 0) {
01086                 at2_read_pending_incoming_messages(privdata);
01087             }
01088             /* read the message and delete it */
01089             message_count += at2_read_delete_message(privdata, i);
01090         }
01091     }
01092     
01093     /*
01094     at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0);
01095     */
01096     return 0;
01097 }

Here is the call graph for this function:

void at2_scan_for_telnet_escapes PrivAT2data privdata  )  [static]
 

Definition at line 102 of file smsc_at.c.

References PrivAT2data::fd, PrivAT2data::ilb, octstr_binary_to_hex(), octstr_delete(), octstr_destroy(), octstr_duplicate, octstr_get_char(), octstr_len(), and octstr_search_char().

Referenced by at2_read_buffer(), and at2_read_line().

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:    /* do! */
00136             answer[0] = 0xFF; /* escape */
00137             answer[1] = 0xFC; /* wont do any option*/
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:   /* do you support option b ? */
00145             octstr_delete(privdata->ilb,pos,3);
00146             len -=3;
00147             break;
00148             break;
00149         case 0xFB:    /* will */
00150             octstr_delete(privdata->ilb,pos,3);
00151             len -=3;
00152             break;
00153         case 0xFC:    /* wont */
00154             octstr_delete(privdata->ilb,pos,3);
00155             len -=3;
00156             break;
00157         }
00158         start = pos;
00159     }
00160     
00161 }

Here is the call graph for this function:

void at2_send_messages PrivAT2data privdata  )  [static]
 

Definition at line 2150 of file smsc_at.c.

References at2_send_modem_command(), at2_send_one_message(), ModemDef::enable_mms, gw_prioqueue_len(), gw_prioqueue_remove(), PrivAT2data::modem, and PrivAT2data::outgoing_queue.

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 }

Here is the call graph for this function:

int at2_send_modem_command PrivAT2data privdata,
char *  cmd,
time_t  timeout,
int  gt_flag
[static]
 

Definition at line 732 of file smsc_at.c.

References at2_wait_modem_command(), and at2_write_line().

00733 {
00734     at2_write_line(privdata, cmd);
00735     return at2_wait_modem_command(privdata, timeout, gt_flag, NULL);
00736 }

Here is the call graph for this function:

void at2_send_one_message PrivAT2data privdata,
Msg msg
[static]
 

Definition at line 2163 of file smsc_at.c.

References at2_pdu_encode(), at2_send_modem_command(), at2_wait_modem_command(), at2_write(), at2_write_ctrlz(), bb_smscconn_send_failed(), bb_smscconn_sent(), PrivAT2data::conn, debug(), dlr_add(), DLR_IS_ENABLED_DEVICE, error(), gwthread_sleep(), smscconn::id, ModemDef::id, PrivAT2data::modem, msg_type, PrivAT2data::my_number, PrivAT2data::name, ModemDef::no_smsc, O_DESTROY, octstr_compare(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_len(), pdu, and SMSCCONN_FAILED_TEMPORARILY.

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      * The standard says you should be prepending the PDU with 00 to indicate 
02176      * to use the default SC. Some older modems dont expect this so it can be 
02177      * disabled 
02178      * NB: This extra padding is not counted in the CMGS byte count 
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          * send the initial command and then wait for > 
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) {/* > only! */
02204 
02205             /* 
02206              * Ok the > has been see now so we can send the PDU now and a 
02207              * control Z but no CR or LF 
02208              * 
02209              * We will handle the 'nokiaphone' types a bit differently, since
02210              * they have a generic error in accepting PDUs that are "too big".
02211              * Which means, PDU that are longer then 18 bytes get truncated by
02212              * the phone modems. We'll buffer the PDU output in a loop.
02213              * All other types will get handled as used to be.
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                 /* include the CTRL-Z in the PDU string */
02225                 sprintf(command, "%s%s%c", sc, octstr_get_cstr(pdu), 0x1A);
02226 
02227                 /* chop PDU into 18-byte-at-a-time pieces to prevent choking 
02228                  * of certain GSM Phones (e.g. Nokia 6310, 6230 etc.) */
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             /* wait 20 secs for modem command */
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                 /* store DLR message if needed for SMSC generated delivery reports */
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 }

Here is the call graph for this function:

int at2_set_message_storage PrivAT2data privdata,
Octstr memory_name
[static]
 

Definition at line 2840 of file smsc_at.c.

References at2_send_modem_command(), octstr_destroy(), octstr_format(), and octstr_get_cstr.

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 }

Here is the call graph for this function:

void at2_set_speed PrivAT2data privdata,
int  bps
[static]
 

Definition at line 1168 of file smsc_at.c.

References error(), PrivAT2data::fd, info(), PrivAT2data::is_serial, PrivAT2data::name, and octstr_get_cstr.

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); /* apply changes now */
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 }

Here is the call graph for this function:

int at2_shutdown_cb SMSCConn conn,
int  finish_sending
[static]
 

Definition at line 1394 of file smsc_at.c.

References bb_smscconn_send_failed(), smscconn::data, debug(), PrivAT2data::device_thread, gw_prioqueue_remove(), gwthread_wakeup(), PrivAT2data::name, octstr_get_cstr, PrivAT2data::outgoing_queue, PrivAT2data::shutdown, SMSCConn, SMSCCONN_FAILED_SHUTDOWN, and smscconn::why_killed.

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      * Documentation claims this would have been done by smscconn.c,
01404      * but isn't when this code is being written. 
01405      */
01406     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01407     privdata->shutdown = 1; 
01408     /* 
01409      * Separate from why_killed to avoid locking, as
01410      * why_killed may be changed from outside? 
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 }

Here is the call graph for this function:

void at2_start_cb SMSCConn conn  )  [static]
 

Definition at line 1440 of file smsc_at.c.

References smscconn::data, debug(), PrivAT2data::device_thread, gwthread_wakeup(), PrivAT2data::name, octstr_get_cstr, SMSCConn, and smscconn::status.

01441 {
01442     PrivAT2data *privdata = conn->data;
01443 
01444     if (conn->status == SMSCCONN_DISCONNECTED)
01445         conn->status = SMSCCONN_ACTIVE;
01446     
01447     /* in case there are messages in the buffer already */
01448     gwthread_wakeup(privdata->device_thread);
01449     debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name));
01450 }

Here is the call graph for this function:

int at2_test_speed PrivAT2data privdata,
long  speed
[static]
 

Definition at line 2516 of file smsc_at.c.

References at2_close_device(), at2_open_device(), at2_read_buffer(), at2_send_modem_command(), at2_set_speed(), and res.

02517 {
02518     int res;
02519 
02520     if (at2_open_device(privdata) == -1)
02521         return -1;
02522 
02523     at2_read_buffer(privdata); /* give telnet escape sequences a chance */
02524     at2_set_speed(privdata, speed);
02525     /* send a return so the modem can detect the speed */
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 }

Here is the call graph for this function:

Octstr* at2_wait_line PrivAT2data privdata,
time_t  timeout,
int  gt_flag
[static]
 

Definition at line 340 of file smsc_at.c.

References at2_read_line(), end_time, PrivAT2data::lines, octstr_create, and octstr_destroy().

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 }

Here is the call graph for this function:

int at2_wait_modem_command PrivAT2data privdata,
time_t  timeout,
int  gt_flag,
int *  output
[static]
 

Definition at line 739 of file smsc_at.c.

References at2_error_string(), at2_pdu_decode(), at2_pdu_extract(), at2_read_line(), at2_wait_line(), at2_write_line(), bb_smscconn_receive(), PrivAT2data::conn, debug(), end_time, error(), PrivAT2data::fd, gwlist_append(), smscconn::id, PrivAT2data::ilb, PrivAT2data::lines, PrivAT2data::name, O_DESTROY, octstr_append(), octstr_append_cstr(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), octstr_parse_long(), octstr_search(), pdu, PrivAT2data::pending_incoming_messages, PrivAT2data::phase2plus, and PrivAT2data::pin_ready.

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                  * we received an incoming message indication
00808                  * put it in the pending_incoming_messages queue for later retrieval 
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                         /* count message even if I can't decode it */
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                  * found response to a +CMGS command, read the message id 
00863                  * and return it in output 
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             /* finally check if we received a generic error */
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     error(0,"AT2[%s]: timeout. received <%s> until now, buffer size is %d, buf=%s",
00889           octstr_get_cstr(privdata->name),
00890           privdata->lines ? octstr_get_cstr(privdata->lines) : "<nothing>", len,
00891           privdata->ilb ? octstr_get_cstr(privdata->ilb) : "<nothing>");
00892     */
00893     O_DESTROY(line);
00894     O_DESTROY(line2);
00895     O_DESTROY(pdu);
00896     O_DESTROY(smsc_number);
00897     return -1; /* timeout */
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 }

Here is the call graph for this function:

int at2_write PrivAT2data privdata,
char *  line
[static]
 

Definition at line 515 of file smsc_at.c.

References debug(), error(), PrivAT2data::fd, gwthread_sleep(), PrivAT2data::modem, PrivAT2data::name, octstr_get_cstr, and ModemDef::sendline_sleep.

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 }

Here is the call graph for this function:

int at2_write_ctrlz PrivAT2data privdata  )  [static]
 

Definition at line 486 of file smsc_at.c.

References debug(), error(), PrivAT2data::fd, gwthread_sleep(), PrivAT2data::modem, PrivAT2data::name, octstr_get_cstr, and ModemDef::sendline_sleep.

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 }

Here is the call graph for this function:

int at2_write_line PrivAT2data privdata,
char *  line
[static]
 

Definition at line 447 of file smsc_at.c.

References debug(), error(), PrivAT2data::fd, gwthread_sleep(), PrivAT2data::modem, PrivAT2data::name, O_DESTROY, octstr_format(), octstr_get_cstr, octstr_len(), and ModemDef::sendline_sleep.

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 }

Here is the call graph for this function:

Octstr * gsm2number Octstr pdu  )  [static]
 

Definition at line 1702 of file smsc_at.c.

References nibble2hex(), octstr_append_char(), octstr_create, octstr_get_char(), octstr_len(), and pdu.

Referenced by at2_pdu_extract().

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: /* unknown */
01725         tmp = octstr_create("");
01726         break;
01727     case 1: /* international */
01728         tmp = octstr_create("+");
01729         break;
01730     case 2: /* national */
01731         tmp = octstr_create("0");
01732         break;
01733     case 3: /* network-specific */
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 }

Here is the call graph for this function:

unsigned char nibble2hex unsigned char  b  )  [static]
 

Definition at line 1694 of file smsc_at.c.

Referenced by gsm2number().

01695 {
01696     if(b < 0x0A)
01697         return '0'+ b;
01698     else
01699         return 'A'+ b - 0x0A;
01700 }

int smsc_at2_create SMSCConn conn,
CfgGroup cfg
 

Definition at line 1464 of file smsc_at.c.

References at2_device_thread(), at2_read_modems(), cfg_get, cfg_get_bool(), cfg_get_configfile(), cfg_get_integer(), PrivAT2data::configfile, PrivAT2data::conn, smscconn::connect_time, smscconn::data, PrivAT2data::device, PrivAT2data::device_thread, error(), PrivAT2data::fd, gw_prioqueue_create(), gw_prioqueue_destroy(), gwlist_create, gwthread_create, PrivAT2data::ilb, info(), PrivAT2data::is_serial, PrivAT2data::keepalive, PrivAT2data::lines, PrivAT2data::login_prompt, PrivAT2data::max_error_count, PrivAT2data::modem, PrivAT2data::my_number, PrivAT2data::name, ModemDef::name, smscconn::name, O_DESTROY, octstr_compare(), octstr_create, octstr_duplicate, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_str_compare(), PrivAT2data::outgoing_queue, PrivAT2data::password, PrivAT2data::password_prompt, PrivAT2data::pending_incoming_messages, PrivAT2data::phase2plus, PrivAT2data::pin, PrivAT2data::pin_ready, smscconn::queued, PrivAT2data::rawtcp_host, PrivAT2data::rawtcp_port, smscconn::send_msg, PrivAT2data::shutdown, smscconn::shutdown, PrivAT2data::sms_center, PrivAT2data::sms_memory_poll_interval, sms_priority_compare(), SMSCConn, PrivAT2data::speed, smscconn::start_conn, smscconn::status, PrivAT2data::use_telnet, PrivAT2data::username, PrivAT2data::validityperiod, and smscconn::why_killed.

Referenced by smscconn_create().

01465 {
01466     PrivAT2data *privdata;
01467     Octstr *modem_type_string;
01468     long portno;   /* has to be long because of cfg_get_integer */
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 }

Here is the call graph for this function:

int swap_nibbles unsigned char  byte  )  [static]
 

Definition at line 2782 of file smsc_at.c.

02783 {
02784     return ( ( byte & 15 ) * 10 ) + ( byte >> 4 );
02785 }


Variable Documentation

int at2_lmask[8] = { 0, 128, 192, 224, 240, 248, 252, 254 } [static]
 

Definition at line 2104 of file smsc_at.c.

Referenced by at2_decode7bituncompressed().

int at2_rmask[8] = { 0, 1, 3, 7, 15, 31, 63, 127 } [static]
 

Definition at line 2103 of file smsc_at.c.

Referenced by at2_decode7bituncompressed().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.