diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
commit | f721e3ac031f892af46f255a47d7f54a91317b30 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /telephony | |
parent | bae1bc39312d5019bd9a5b8d840a529213a69a17 (diff) | |
download | external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.zip external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.gz external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'telephony')
-rw-r--r-- | telephony/Jamfile | 13 | ||||
-rw-r--r-- | telephony/android_modem.c | 1870 | ||||
-rw-r--r-- | telephony/android_modem.h | 137 | ||||
-rw-r--r-- | telephony/gsm.c | 1220 | ||||
-rw-r--r-- | telephony/gsm.h | 196 | ||||
-rw-r--r-- | telephony/modem_driver.c | 148 | ||||
-rw-r--r-- | telephony/modem_driver.h | 29 | ||||
-rw-r--r-- | telephony/remote_call.c | 430 | ||||
-rw-r--r-- | telephony/remote_call.h | 55 | ||||
-rw-r--r-- | telephony/sim_card.c | 439 | ||||
-rw-r--r-- | telephony/sim_card.h | 54 | ||||
-rw-r--r-- | telephony/simulator.c | 195 | ||||
-rw-r--r-- | telephony/sms.c | 1655 | ||||
-rw-r--r-- | telephony/sms.h | 117 | ||||
-rw-r--r-- | telephony/sysdeps.h | 80 | ||||
-rw-r--r-- | telephony/sysdeps_posix.c | 645 | ||||
-rw-r--r-- | telephony/sysdeps_qemu.c | 376 | ||||
-rw-r--r-- | telephony/test1.c | 49 | ||||
-rw-r--r-- | telephony/test2.c | 215 |
19 files changed, 0 insertions, 7923 deletions
diff --git a/telephony/Jamfile b/telephony/Jamfile deleted file mode 100644 index 0f2b7b9..0000000 --- a/telephony/Jamfile +++ /dev/null @@ -1,13 +0,0 @@ -Main telephony : telephony.c ; - -Library sysdeps : sysdeps_posix.c ; -Library android_modem : android_modem.c sim_card.c ; - -for prog in test1 test2 { - Main $(prog) : $(prog).c ; - LinkLibraries $(prog) : sysdeps ; -} - -Main simulator : simulator.c ; -LinkLibraries simulator : sysdeps android_modem ; - diff --git a/telephony/android_modem.c b/telephony/android_modem.c deleted file mode 100644 index 79e93b2..0000000 --- a/telephony/android_modem.c +++ /dev/null @@ -1,1870 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "android/android.h" -#include "android_modem.h" -#include "android/utils/debug.h" -#include "android/utils/timezone.h" -#include "android/utils/system.h" -#include "sim_card.h" -#include "sysdeps.h" -#include <memory.h> -#include <stdarg.h> -#include <time.h> -#include <assert.h> -#include <stdio.h> -#include "sms.h" -#include "remote_call.h" - -#define DEBUG 1 - -#if 1 -# define D_ACTIVE VERBOSE_CHECK(modem) -#else -# define D_ACTIVE DEBUG -#endif - -#if 1 -# define R_ACTIVE VERBOSE_CHECK(radio) -#else -# define R_ACTIVE DEBUG -#endif - -#if DEBUG -# define D(...) do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0) -# define R(...) do { if (R_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0) -#else -# define D(...) ((void)0) -# define R(...) ((void)0) -#endif - -#define CALL_DELAY_DIAL 1000 -#define CALL_DELAY_ALERT 1000 - -/* the Android GSM stack checks that the operator's name has changed - * when roaming is on. If not, it will not update the Roaming status icon - * - * this means that we need to emulate two distinct operators: - * - the first one for the 'home' registration state, must also correspond - * to the emulated user's IMEI - * - * - the second one for the 'roaming' registration state, must have a - * different name and MCC/MNC - */ - -#define OPERATOR_HOME_INDEX 0 -#define OPERATOR_HOME_MCC 310 -#define OPERATOR_HOME_MNC 260 -#define OPERATOR_HOME_NAME "Android" -#define OPERATOR_HOME_MCCMNC STRINGIFY(OPERATOR_HOME_MCC) \ - STRINGIFY(OPERATOR_HOME_MNC) - -#define OPERATOR_ROAMING_INDEX 1 -#define OPERATOR_ROAMING_MCC 310 -#define OPERATOR_ROAMING_MNC 295 -#define OPERATOR_ROAMING_NAME "TelKila" -#define OPERATOR_ROAMING_MCCMNC STRINGIFY(OPERATOR_ROAMING_MCC) \ - STRINGIFY(OPERATOR_ROAMING_MNC) - -#if DEBUG -static const char* quote( const char* line ) -{ - static char temp[1024]; - const char* hexdigits = "0123456789abcdef"; - char* p = temp; - int c; - - while ((c = *line++) != 0) { - c &= 255; - if (c >= 32 && c < 127) { - *p++ = c; - } - else if (c == '\r') { - memcpy( p, "<CR>", 4 ); - p += 4; - } - else if (c == '\n') { - memcpy( p, "<LF>", 4 );strcat( p, "<LF>" ); - p += 4; - } - else { - p[0] = '\\'; - p[1] = 'x'; - p[2] = hexdigits[ (c) >> 4 ]; - p[3] = hexdigits[ (c) & 15 ]; - p += 4; - } - } - *p = 0; - return temp; -} -#endif - -extern AGprsNetworkType -android_parse_network_type( const char* speed ) -{ - const struct { const char* name; AGprsNetworkType type; } types[] = { - { "gprs", A_GPRS_NETWORK_GPRS }, - { "edge", A_GPRS_NETWORK_EDGE }, - { "umts", A_GPRS_NETWORK_UMTS }, - { "hsdpa", A_GPRS_NETWORK_UMTS }, /* not handled yet by Android GSM framework */ - { "full", A_GPRS_NETWORK_UMTS }, - { NULL, 0 } - }; - int nn; - - for (nn = 0; types[nn].name; nn++) { - if ( !strcmp(speed, types[nn].name) ) - return types[nn].type; - } - /* not found, be conservative */ - return A_GPRS_NETWORK_GPRS; -} - -/* 'mode' for +CREG/+CGREG commands */ -typedef enum { - A_REGISTRATION_UNSOL_DISABLED = 0, - A_REGISTRATION_UNSOL_ENABLED = 1, - A_REGISTRATION_UNSOL_ENABLED_FULL = 2 -} ARegistrationUnsolMode; - -/* Operator selection mode, see +COPS commands */ -typedef enum { - A_SELECTION_AUTOMATIC, - A_SELECTION_MANUAL, - A_SELECTION_DEREGISTRATION, - A_SELECTION_SET_FORMAT, - A_SELECTION_MANUAL_AUTOMATIC -} AOperatorSelection; - -/* Operator status, see +COPS commands */ -typedef enum { - A_STATUS_UNKNOWN = 0, - A_STATUS_AVAILABLE, - A_STATUS_CURRENT, - A_STATUS_DENIED -} AOperatorStatus; - -typedef struct { - AOperatorStatus status; - char name[3][16]; -} AOperatorRec, *AOperator; - -typedef struct AVoiceCallRec { - ACallRec call; - SysTimer timer; - AModem modem; - char is_remote; -} AVoiceCallRec, *AVoiceCall; - -#define MAX_OPERATORS 4 - -typedef enum { - A_DATA_IP = 0, - A_DATA_PPP -} ADataType; - -#define A_DATA_APN_SIZE 32 - -typedef struct { - int id; - int active; - ADataType type; - char apn[ A_DATA_APN_SIZE ]; - -} ADataContextRec, *ADataContext; - -/* the spec says that there can only be a max of 4 contexts */ -#define MAX_DATA_CONTEXTS 4 -#define MAX_CALLS 4 - -#define A_MODEM_SELF_SIZE 3 - -typedef struct AModemRec_ -{ - /* Radio state */ - ARadioState radio_state; - int area_code; - int cell_id; - int base_port; - - /* SMS */ - int wait_sms; - - /* SIM card */ - ASimCard sim; - - /* voice and data network registration */ - ARegistrationUnsolMode voice_mode; - ARegistrationState voice_state; - ARegistrationUnsolMode data_mode; - ARegistrationState data_state; - AGprsNetworkType data_network; - - /* operator names */ - AOperatorSelection oper_selection_mode; - ANameIndex oper_name_index; - int oper_index; - int oper_count; - AOperatorRec operators[ MAX_OPERATORS ]; - - /* data connection contexts */ - ADataContextRec data_contexts[ MAX_DATA_CONTEXTS ]; - - /* active calls */ - AVoiceCallRec calls[ MAX_CALLS ]; - int call_count; - - /* unsolicited callback */ /* XXX: TODO: use this */ - AModemUnsolFunc unsol_func; - void* unsol_opaque; - - SmsReceiver sms_receiver; - - int out_size; - char out_buff[1024]; - -} AModemRec; - - -static void -amodem_unsol( AModem modem, const char* format, ... ) -{ - if (modem->unsol_func) { - va_list args; - va_start(args, format); - vsnprintf( modem->out_buff, sizeof(modem->out_buff), format, args ); - va_end(args); - - modem->unsol_func( modem->unsol_opaque, modem->out_buff ); - } -} - -void -amodem_receive_sms( AModem modem, SmsPDU sms ) -{ -#define SMS_UNSOL_HEADER "+CMT: 0\r\n" - - if (modem->unsol_func) { - int len, max; - char* p; - - strcpy( modem->out_buff, SMS_UNSOL_HEADER ); - p = modem->out_buff + (sizeof(SMS_UNSOL_HEADER)-1); - max = sizeof(modem->out_buff) - 3 - (sizeof(SMS_UNSOL_HEADER)-1); - len = smspdu_to_hex( sms, p, max ); - if (len > max) /* too long */ - return; - p[len] = '\r'; - p[len+1] = '\n'; - p[len+2] = 0; - - R( "SMS>> %s\n", p ); - - modem->unsol_func( modem->unsol_opaque, modem->out_buff ); - } -} - -static const char* -amodem_printf( AModem modem, const char* format, ... ) -{ - va_list args; - va_start(args, format); - vsnprintf( modem->out_buff, sizeof(modem->out_buff), format, args ); - va_end(args); - - return modem->out_buff; -} - -static void -amodem_begin_line( AModem modem ) -{ - modem->out_size = 0; -} - -static void -amodem_add_line( AModem modem, const char* format, ... ) -{ - va_list args; - va_start(args, format); - modem->out_size += vsnprintf( modem->out_buff + modem->out_size, - sizeof(modem->out_buff) - modem->out_size, - format, args ); - va_end(args); -} - -static const char* -amodem_end_line( AModem modem ) -{ - modem->out_buff[ modem->out_size ] = 0; - return modem->out_buff; -} - -static void -amodem_reset( AModem modem ) -{ - modem->radio_state = A_RADIO_STATE_OFF; - modem->wait_sms = 0; - - modem->oper_name_index = 2; - modem->oper_selection_mode = A_SELECTION_AUTOMATIC; - modem->oper_index = 0; - modem->oper_count = 2; - - modem->area_code = -1; - modem->cell_id = -1; - - strcpy( modem->operators[0].name[0], OPERATOR_HOME_NAME ); - strcpy( modem->operators[0].name[1], OPERATOR_HOME_NAME ); - strcpy( modem->operators[0].name[2], OPERATOR_HOME_MCCMNC ); - - modem->operators[0].status = A_STATUS_AVAILABLE; - - strcpy( modem->operators[1].name[0], OPERATOR_ROAMING_NAME ); - strcpy( modem->operators[1].name[1], OPERATOR_ROAMING_NAME ); - strcpy( modem->operators[1].name[2], OPERATOR_ROAMING_MCCMNC ); - - modem->operators[1].status = A_STATUS_AVAILABLE; - - modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED_FULL; - modem->voice_state = A_REGISTRATION_HOME; - modem->data_mode = A_REGISTRATION_UNSOL_ENABLED_FULL; - modem->data_state = A_REGISTRATION_HOME; - modem->data_network = A_GPRS_NETWORK_UMTS; -} - -static AModemRec _android_modem[1]; - -AModem -amodem_create( int base_port, AModemUnsolFunc unsol_func, void* unsol_opaque ) -{ - AModem modem = _android_modem; - - amodem_reset( modem ); - modem->base_port = base_port; - modem->unsol_func = unsol_func; - modem->unsol_opaque = unsol_opaque; - - modem->sim = asimcard_create(); - - return modem; -} - -void -amodem_destroy( AModem modem ) -{ - asimcard_destroy( modem->sim ); - modem->sim = NULL; -} - - -static int -amodem_has_network( AModem modem ) -{ - return !(modem->radio_state == A_RADIO_STATE_OFF || - modem->oper_index < 0 || - modem->oper_index >= modem->oper_count || - modem->oper_selection_mode == A_SELECTION_DEREGISTRATION ); -} - - -ARadioState -amodem_get_radio_state( AModem modem ) -{ - return modem->radio_state; -} - -void -amodem_set_radio_state( AModem modem, ARadioState state ) -{ - modem->radio_state = state; -} - -ASimCard -amodem_get_sim( AModem modem ) -{ - return modem->sim; -} - -ARegistrationState -amodem_get_voice_registration( AModem modem ) -{ - return modem->voice_state; -} - -void -amodem_set_voice_registration( AModem modem, ARegistrationState state ) -{ - modem->voice_state = state; - - if (state == A_REGISTRATION_HOME) - modem->oper_index = OPERATOR_HOME_INDEX; - else if (state == A_REGISTRATION_ROAMING) - modem->oper_index = OPERATOR_ROAMING_INDEX; - - switch (modem->voice_mode) { - case A_REGISTRATION_UNSOL_ENABLED: - amodem_unsol( modem, "+CREG: %d,%d\r", - modem->voice_mode, modem->voice_state ); - break; - - case A_REGISTRATION_UNSOL_ENABLED_FULL: - amodem_unsol( modem, "+CREG: %d,%d, \"%04x\", \"%04x\"\r", - modem->voice_mode, modem->voice_state, - modem->area_code, modem->cell_id ); - break; - default: - ; - } -} - -ARegistrationState -amodem_get_data_registration( AModem modem ) -{ - return modem->data_state; -} - -void -amodem_set_data_registration( AModem modem, ARegistrationState state ) -{ - modem->data_state = state; - - switch (modem->data_mode) { - case A_REGISTRATION_UNSOL_ENABLED: - amodem_unsol( modem, "+CGREG: %d,%d\r", - modem->data_mode, modem->data_state ); - break; - - case A_REGISTRATION_UNSOL_ENABLED_FULL: - amodem_unsol( modem, "+CGREG: %d,%d,\"%04x\",\"%04x\",\"%04x\"\r", - modem->data_mode, modem->data_state, - modem->area_code, modem->cell_id, - modem->data_network ); - break; - - default: - ; - } -} - -void -amodem_set_data_network_type( AModem modem, AGprsNetworkType type ) -{ - modem->data_network = type; - amodem_set_data_registration( modem, modem->data_state ); -} - -int -amodem_get_operator_name ( AModem modem, ANameIndex index, char* buffer, int buffer_size ) -{ - AOperator oper; - int len; - - if ( (unsigned)modem->oper_index >= (unsigned)modem->oper_count || - (unsigned)index > 2 ) - return 0; - - oper = modem->operators + modem->oper_index; - len = strlen(oper->name[index]) + 1; - - if (buffer_size > len) - buffer_size = len; - - if (buffer_size > 0) { - memcpy( buffer, oper->name[index], buffer_size-1 ); - buffer[buffer_size] = 0; - } - return len; -} - -/* reset one operator name from a user-provided buffer, set buffer_size to -1 for zero-terminated strings */ -void -amodem_set_operator_name( AModem modem, ANameIndex index, const char* buffer, int buffer_size ) -{ - AOperator oper; - int avail; - - if ( (unsigned)modem->oper_index >= (unsigned)modem->oper_count || - (unsigned)index > 2 ) - return; - - oper = modem->operators + modem->oper_index; - - avail = sizeof(oper->name[0]); - if (buffer_size < 0) - buffer_size = strlen(buffer); - if (buffer_size > avail-1) - buffer_size = avail-1; - memcpy( oper->name[index], buffer, buffer_size ); - oper->name[index][buffer_size] = 0; -} - -/** CALLS - **/ -int -amodem_get_call_count( AModem modem ) -{ - return modem->call_count; -} - -ACall -amodem_get_call( AModem modem, int index ) -{ - if ((unsigned)index >= (unsigned)modem->call_count) - return NULL; - - return &modem->calls[index].call; -} - -static AVoiceCall -amodem_alloc_call( AModem modem ) -{ - AVoiceCall call = NULL; - int count = modem->call_count; - - if (count < MAX_CALLS) { - int id; - - /* find a valid id for this call */ - for (id = 0; id < modem->call_count; id++) { - int found = 0; - int nn; - for (nn = 0; nn < count; nn++) { - if ( modem->calls[nn].call.id == (id+1) ) { - found = 1; - break; - } - } - if (!found) - break; - } - call = modem->calls + count; - call->call.id = id + 1; - call->modem = modem; - - modem->call_count += 1; - } - return call; -} - - -static void -amodem_free_call( AModem modem, AVoiceCall call ) -{ - int nn; - - if (call->timer) { - sys_timer_destroy( call->timer ); - call->timer = NULL; - } - - if (call->is_remote) { - remote_call_cancel( call->call.number, modem->base_port ); - call->is_remote = 0; - } - - for (nn = 0; nn < modem->call_count; nn++) { - if ( modem->calls + nn == call ) - break; - } - assert( nn < modem->call_count ); - - memmove( modem->calls + nn, - modem->calls + nn + 1, - (modem->call_count - 1 - nn)*sizeof(*call) ); - - modem->call_count -= 1; -} - - -static AVoiceCall -amodem_find_call( AModem modem, int id ) -{ - int nn; - - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall call = modem->calls + nn; - if (call->call.id == id) - return call; - } - return NULL; -} - -static void -amodem_send_calls_update( AModem modem ) -{ - /* despite its name, this really tells the system that the call - * state has changed */ - amodem_unsol( modem, "RING\r" ); -} - - -int -amodem_add_inbound_call( AModem modem, const char* number ) -{ - AVoiceCall vcall = amodem_alloc_call( modem ); - ACall call = &vcall->call; - int len; - - if (call == NULL) - return -1; - - call->dir = A_CALL_INBOUND; - call->state = A_CALL_INCOMING; - call->mode = A_CALL_VOICE; - call->multi = 0; - - vcall->is_remote = (remote_number_string_to_port(number) > 0); - - len = strlen(number); - if (len >= sizeof(call->number)) - len = sizeof(call->number)-1; - - memcpy( call->number, number, len ); - call->number[len] = 0; - - amodem_send_calls_update( modem ); - return 0; -} - -ACall -amodem_find_call_by_number( AModem modem, const char* number ) -{ - AVoiceCall vcall = modem->calls; - AVoiceCall vend = vcall + modem->call_count; - - if (!number) - return NULL; - - for ( ; vcall < vend; vcall++ ) - if ( !strcmp(vcall->call.number, number) ) - return &vcall->call; - - return NULL; -} - - -static void -acall_set_state( AVoiceCall call, ACallState state ) -{ - if (state != call->call.state) - { - if (call->is_remote) - { - const char* number = call->call.number; - int port = call->modem->base_port; - - switch (state) { - case A_CALL_HELD: - remote_call_other( number, port, REMOTE_CALL_HOLD ); - break; - - case A_CALL_ACTIVE: - remote_call_other( number, port, REMOTE_CALL_ACCEPT ); - break; - - default: ; - } - } - call->call.state = state; - } -} - - -int -amodem_update_call( AModem modem, const char* fromNumber, ACallState state ) -{ - AVoiceCall vcall = (AVoiceCall) amodem_find_call_by_number(modem, fromNumber); - - if (vcall == NULL) - return -1; - - acall_set_state( vcall, state ); - amodem_send_calls_update(modem); - return 0; -} - - -int -amodem_disconnect_call( AModem modem, const char* number ) -{ - AVoiceCall vcall = (AVoiceCall) amodem_find_call_by_number(modem, number); - - if (!vcall) - return -1; - - amodem_free_call( modem, vcall ); - amodem_send_calls_update(modem); - return 0; -} - -/** COMMAND HANDLERS - **/ - -static const char* -unknownCommand( const char* cmd, AModem modem ) -{ - modem=modem; - fprintf(stderr, ">>> unknown command '%s'\n", cmd ); - return "ERROR: unknown command\r"; -} - -static const char* -handleRadioPower( const char* cmd, AModem modem ) -{ - if ( !strcmp( cmd, "+CFUN=0" ) ) - { - /* turn radio off */ - modem->radio_state = A_RADIO_STATE_OFF; - } - else if ( !strcmp( cmd, "+CFUN=1" ) ) - { - /* turn radio on */ - modem->radio_state = A_RADIO_STATE_ON; - } - return NULL; -} - -static const char* -handleRadioPowerReq( const char* cmd, AModem modem ) -{ - if (modem->radio_state != A_RADIO_STATE_OFF) - return "+CFUN=1"; - else - return "+CFUN=0"; -} - -static const char* -handleSIMStatusReq( const char* cmd, AModem modem ) -{ - const char* answer = NULL; - - switch (asimcard_get_status(modem->sim)) { - case A_SIM_STATUS_ABSENT: answer = "+CPIN: ABSENT"; break; - case A_SIM_STATUS_READY: answer = "+CPIN: READY"; break; - case A_SIM_STATUS_NOT_READY: answer = "+CMERROR: NOT READY"; break; - case A_SIM_STATUS_PIN: answer = "+CPIN: SIM PIN"; break; - case A_SIM_STATUS_PUK: answer = "+CPIN: SIM PUK"; break; - case A_SIM_STATUS_NETWORK_PERSONALIZATION: answer = "+CPIN: PH-NET PIN"; break; - default: - answer = "ERROR: internal error"; - } - return answer; -} - -static const char* -handleNetworkRegistration( const char* cmd, AModem modem ) -{ - if ( !memcmp( cmd, "+CREG", 5 ) ) { - cmd += 5; - if (cmd[0] == '?') { - return amodem_printf( modem, "+CREG: %d,%d, \"%04x\", \"%04x\"", - modem->voice_mode, modem->voice_state, - modem->area_code, modem->cell_id ); - } else if (cmd[0] == '=') { - switch (cmd[1]) { - case '0': - modem->voice_mode = A_REGISTRATION_UNSOL_DISABLED; - break; - - case '1': - modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED; - break; - - case '2': - modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED_FULL; - break; - - case '?': - return "+CREG: (0-2)"; - - default: - return "ERROR: BAD COMMAND"; - } - } else { - assert( 0 && "unreachable" ); - } - } else if ( !memcmp( cmd, "+CGREG", 6 ) ) { - cmd += 6; - if (cmd[0] == '?') {\ - return amodem_printf( modem, "+CGREG: %d,%d,\"%04x\",\"%04x\",\"%04x\"", - modem->data_mode, modem->data_state, - modem->area_code, modem->cell_id, - modem->data_network ); - } else if (cmd[0] == '=') { - switch (cmd[1]) { - case '0': - modem->data_mode = A_REGISTRATION_UNSOL_DISABLED; - break; - - case '1': - modem->data_mode = A_REGISTRATION_UNSOL_ENABLED; - break; - - case '2': - modem->data_mode = A_REGISTRATION_UNSOL_ENABLED_FULL; - break; - - case '?': - return "+CGREG: (0-2)"; - - default: - return "ERROR: BAD COMMAND"; - } - } else { - assert( 0 && "unreachable" ); - } - } - return NULL; -} - -static const char* -handleSetDialTone( const char* cmd, AModem modem ) -{ - /* XXX: TODO */ - return NULL; -} - -static const char* -handleDeleteSMSonSIM( const char* cmd, AModem modem ) -{ - /* XXX: TODO */ - return NULL; -} - -static const char* -handleSIM_IO( const char* cmd, AModem modem ) -{ - return asimcard_io( modem->sim, cmd ); -} - - -static const char* -handleOperatorSelection( const char* cmd, AModem modem ) -{ - assert( !memcmp( "+COPS", cmd, 5 ) ); - cmd += 5; - if (cmd[0] == '?') { /* ask for current operator */ - AOperator oper = &modem->operators[ modem->oper_index ]; - - if ( !amodem_has_network( modem ) ) - { - /* this error code means "no network" */ - return amodem_printf( modem, "+CME ERROR: 30" ); - } - - oper = &modem->operators[ modem->oper_index ]; - - if ( modem->oper_name_index == 2 ) - return amodem_printf( modem, "+COPS: %d,2,%s", - modem->oper_selection_mode, - oper->name[2] ); - - return amodem_printf( modem, "+COPS: %d,%d,\"%s\"", - modem->oper_selection_mode, - modem->oper_name_index, - oper->name[ modem->oper_name_index ] ); - } - else if (cmd[0] == '=' && cmd[1] == '?') { /* ask for all available operators */ - const char* comma = "+COPS: "; - int nn; - amodem_begin_line( modem ); - for (nn = 0; nn < modem->oper_count; nn++) { - AOperator oper = &modem->operators[nn]; - amodem_add_line( modem, "%s(%d,\"%s\",\"%s\",\"%s\")", comma, - oper->status, oper->name[0], oper->name[1], oper->name[2] ); - comma = ", "; - } - return amodem_end_line( modem ); - } - else if (cmd[0] == '=') { - switch (cmd[1]) { - case '0': - modem->oper_selection_mode = A_SELECTION_AUTOMATIC; - return NULL; - - case '1': - { - int format, nn, len, found = -1; - - if (cmd[2] != ',') - goto BadCommand; - format = cmd[3] - '0'; - if ( (unsigned)format > 2 ) - goto BadCommand; - if (cmd[4] != ',') - goto BadCommand; - cmd += 5; - len = strlen(cmd); - if (*cmd == '"') { - cmd++; - len -= 2; - } - if (len <= 0) - goto BadCommand; - - for (nn = 0; nn < modem->oper_count; nn++) { - AOperator oper = modem->operators + nn; - char* name = oper->name[ format ]; - - if ( !memcpy( name, cmd, len ) && name[len] == 0 ) { - found = nn; - break; - } - } - - if (found < 0) { - /* Selection failed */ - return "+CME ERROR: 529"; - } else if (modem->operators[found].status == A_STATUS_DENIED) { - /* network not allowed */ - return "+CME ERROR: 32"; - } - modem->oper_index = found; - - /* set the voice and data registration states to home or roaming - * depending on the operator index - */ - if (found == OPERATOR_HOME_INDEX) { - modem->voice_state = A_REGISTRATION_HOME; - modem->data_state = A_REGISTRATION_HOME; - } else if (found == OPERATOR_ROAMING_INDEX) { - modem->voice_state = A_REGISTRATION_ROAMING; - modem->data_state = A_REGISTRATION_ROAMING; - } - return NULL; - } - - case '2': - modem->oper_selection_mode = A_SELECTION_DEREGISTRATION; - return NULL; - - case '3': - { - int format; - - if (cmd[2] != ',') - goto BadCommand; - - format = cmd[3] - '0'; - if ( (unsigned)format > 2 ) - goto BadCommand; - - modem->oper_name_index = format; - return NULL; - } - default: - ; - } - } -BadCommand: - return unknownCommand(cmd,modem); -} - -static const char* -handleRequestOperator( const char* cmd, AModem modem ) -{ - AOperator oper; - cmd=cmd; - - if ( !amodem_has_network(modem) ) - return "+CME ERROR: 30"; - - oper = modem->operators + modem->oper_index; - modem->oper_name_index = 2; - return amodem_printf( modem, "+COPS: 0,0,\"%s\"\r" - "+COPS: 0,1,\"%s\"\r" - "+COPS: 0,2,\"%s\"", - oper->name[0], oper->name[1], oper->name[2] ); -} - -static const char* -handleSendSMStoSIM( const char* cmd, AModem modem ) -{ - /* XXX: TODO */ - return "ERROR: unimplemented"; -} - -static const char* -handleSendSMS( const char* cmd, AModem modem ) -{ - modem->wait_sms = 1; - return "> "; -} - -#if 0 -static void -sms_address_dump( SmsAddress address, FILE* out ) -{ - int nn, len = address->len; - - if (address->toa == 0x91) { - fprintf( out, "+" ); - } - for (nn = 0; nn < len; nn += 2) - { - static const char dialdigits[16] = "0123456789*#,N%"; - int c = address->data[nn/2]; - - fprintf( out, "%c", dialdigits[c & 0xf] ); - if (nn+1 >= len) - break; - - fprintf( out, "%c", dialdigits[(c >> 4) & 0xf] ); - } -} - -static void -smspdu_dump( SmsPDU pdu, FILE* out ) -{ - SmsAddressRec address; - unsigned char temp[256]; - int len; - - if (pdu == NULL) { - fprintf( out, "SMS PDU is (null)\n" ); - return; - } - - fprintf( out, "SMS PDU type: " ); - switch (smspdu_get_type(pdu)) { - case SMS_PDU_DELIVER: fprintf(out, "DELIVER"); break; - case SMS_PDU_SUBMIT: fprintf(out, "SUBMIT"); break; - case SMS_PDU_STATUS_REPORT: fprintf(out, "STATUS_REPORT"); break; - default: fprintf(out, "UNKNOWN"); - } - fprintf( out, "\n sender: " ); - if (smspdu_get_sender_address(pdu, &address) < 0) - fprintf( out, "(N/A)" ); - else - sms_address_dump(&address, out); - fprintf( out, "\n receiver: " ); - if (smspdu_get_receiver_address(pdu, &address) < 0) - fprintf(out, "(N/A)"); - else - sms_address_dump(&address, out); - fprintf( out, "\n text: " ); - len = smspdu_get_text_message( pdu, temp, sizeof(temp)-1 ); - if (len > sizeof(temp)-1 ) - len = sizeof(temp)-1; - fprintf( out, "'%.*s'\n", len, temp ); -} -#endif - -static const char* -handleSendSMSText( const char* cmd, AModem modem ) -{ -#if 1 - SmsAddressRec address; - char number[16]; - int numlen; - int len = strlen(cmd); - SmsPDU pdu; - - /* get rid of trailing escape */ - if (len > 0 && cmd[len-1] == 0x1a) - len -= 1; - - pdu = smspdu_create_from_hex( cmd, len ); - if (pdu == NULL) { - D("%s: invalid SMS PDU ?: '%s'\n", __FUNCTION__, cmd); - return "+CMS ERROR: INVALID SMS PDU"; - } - if (smspdu_get_receiver_address(pdu, &address) < 0) { - D("%s: could not get SMS receiver address from '%s'\n", - __FUNCTION__, cmd); - return "+CMS ERROR: BAD SMS RECEIVER ADDRESS"; - } - - do { - int index; - - numlen = sms_address_to_str( &address, number, sizeof(number) ); - if (numlen > sizeof(number)-1) - break; - - number[numlen] = 0; - if ( remote_number_string_to_port( number ) < 0 ) - break; - - if (modem->sms_receiver == NULL) { - modem->sms_receiver = sms_receiver_create(); - if (modem->sms_receiver == NULL) { - D( "%s: could not create SMS receiver\n", __FUNCTION__ ); - break; - } - } - - index = sms_receiver_add_submit_pdu( modem->sms_receiver, pdu ); - if (index < 0) { - D( "%s: could not add submit PDU\n", __FUNCTION__ ); - break; - } - /* the PDU is now owned by the receiver */ - pdu = NULL; - - if (index > 0) { - SmsAddressRec from[1]; - char temp[10]; - SmsPDU* deliver; - int nn; - - sprintf( temp, "%d", modem->base_port ); - sms_address_from_str( from, temp, strlen(temp) ); - - deliver = sms_receiver_create_deliver( modem->sms_receiver, index, from ); - if (deliver == NULL) { - D( "%s: could not create deliver PDUs for SMS index %d\n", - __FUNCTION__, index ); - break; - } - - for (nn = 0; deliver[nn] != NULL; nn++) { - if ( remote_call_sms( number, modem->base_port, deliver[nn] ) < 0 ) { - D( "%s: could not send SMS PDU to remote emulator\n", - __FUNCTION__ ); - break; - } - } - - smspdu_free_list(deliver); - } - - } while (0); - - if (pdu != NULL) - smspdu_free(pdu); - -#elif 1 - SmsAddressRec address; - char number[16]; - int numlen; - int len = strlen(cmd); - SmsPDU pdu; - - /* get rid of trailing escape */ - if (len > 0 && cmd[len-1] == 0x1a) - len -= 1; - - pdu = smspdu_create_from_hex( cmd, len ); - if (pdu == NULL) { - D("%s: invalid SMS PDU ?: '%s'\n", __FUNCTION__, cmd); - return "+CMS ERROR: INVALID SMS PDU"; - } - if (smspdu_get_receiver_address(pdu, &address) < 0) { - D("%s: could not get SMS receiver address from '%s'\n", - __FUNCTION__, cmd); - return "+CMS ERROR: BAD SMS RECEIVER ADDRESS"; - } - do { - numlen = sms_address_to_str( &address, number, sizeof(number) ); - if (numlen > sizeof(number)-1) - break; - - number[numlen] = 0; - if ( remote_number_string_to_port( number ) < 0 ) - break; - - if ( remote_call_sms( number, modem->base_port, pdu ) < 0 ) - { - D("%s: could not send SMS PDU to remote emulator\n", - __FUNCTION__); - return "+CMS ERROR: NO EMULATOR RECEIVER"; - } - } while (0); -#else - fprintf(stderr, "SMS<< %s\n", cmd); - SmsPDU pdu = smspdu_create_from_hex( cmd, strlen(cmd) ); - if (pdu == NULL) { - fprintf(stderr, "invalid SMS PDU ?: '%s'\n", cmd); - } else { - smspdu_dump(pdu, stderr); - } -#endif - return "+CMGS: 0\rOK\r"; -} - -static const char* -handleChangeOrEnterPIN( const char* cmd, AModem modem ) -{ - assert( !memcmp( cmd, "+CPIN=", 6 ) ); - cmd += 6; - - switch (asimcard_get_status(modem->sim)) { - case A_SIM_STATUS_ABSENT: - return "+CME ERROR: SIM ABSENT"; - - case A_SIM_STATUS_NOT_READY: - return "+CME ERROR: SIM NOT READY"; - - case A_SIM_STATUS_READY: - /* this may be a request to change the PIN */ - { - if (strlen(cmd) == 9 && cmd[4] == ',') { - char pin[5]; - memcpy( pin, cmd, 4 ); pin[4] = 0; - - if ( !asimcard_check_pin( modem->sim, pin ) ) - return "+CME ERROR: BAD PIN"; - - memcpy( pin, cmd+5, 4 ); - asimcard_set_pin( modem->sim, pin ); - return "+CPIN: READY"; - } - } - break; - - case A_SIM_STATUS_PIN: /* waiting for PIN */ - if ( asimcard_check_pin( modem->sim, cmd ) ) - return "+CPIN: READY"; - else - return "+CME ERROR: BAD PIN"; - - case A_SIM_STATUS_PUK: - if (strlen(cmd) == 9 && cmd[4] == ',') { - char puk[5]; - memcpy( puk, cmd, 4 ); - puk[4] = 0; - if ( asimcard_check_puk( modem->sim, puk, cmd+5 ) ) - return "+CPIN: READY"; - else - return "+CME ERROR: BAD PUK"; - } - return "+CME ERROR: BAD PUK"; - - default: - return "+CPIN: PH-NET PIN"; - } - - return "+CME ERROR: BAD FORMAT"; -} - - -static const char* -handleListCurrentCalls( const char* cmd, AModem modem ) -{ - int nn; - amodem_begin_line( modem ); - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode == A_CALL_VOICE) - amodem_add_line( modem, "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n", - call->id, call->dir, call->state, call->mode, - call->multi, call->number, 129 ); - } - return amodem_end_line( modem ); -} - -/* retrieve the current time and zone in a format suitable - * for %CTZV: unsolicited message - * "yy/mm/dd,hh:mm:ss(+/-)tz" - * mm is 0-based - * tz is in number of quarter-hours - * - * it seems reference-ril doesn't parse the comma (,) as anything else than a token - * separator, so use a column (:) instead, the Java parsing code won't see a difference - * - */ -static const char* -handleEndOfInit( const char* cmd, AModem modem ) -{ - time_t now = time(NULL); - struct tm utc, local; - long e_local, e_utc; - long tzdiff; - char tzname[64]; - - tzset(); - - utc = *gmtime( &now ); - local = *localtime( &now ); - - e_local = local.tm_min + 60*(local.tm_hour + 24*local.tm_yday); - e_utc = utc.tm_min + 60*(utc.tm_hour + 24*utc.tm_yday); - - if ( utc.tm_year < local.tm_year ) - e_local += 24*60; - else if ( utc.tm_year > local.tm_year ) - e_utc += 24*60; - - tzdiff = e_local - e_utc; /* timezone offset in minutes */ - - /* retrieve a zoneinfo-compatible name for the host timezone - */ - { - char* end = tzname + sizeof(tzname); - char* p = bufprint_zoneinfo_timezone( tzname, end ); - if (p >= end) - strcpy(tzname, "Unknown/Unknown"); - - /* now replace every / in the timezone name by a "!" - * that's because the code that reads the CTZV line is - * dumb and treats a / as a field separator... - */ - p = tzname; - while (1) { - p = strchr(p, '/'); - if (p == NULL) - break; - *p = '!'; - p += 1; - } - } - - /* as a special extension, we append the name of the host's time zone to the - * string returned with %CTZ. the system should contain special code to detect - * and deal with this case (since it normally relied on the operator's country code - * which is hard to simulate on a general-purpose computer - */ - return amodem_printf( modem, "%%CTZV: %02d/%02d/%02d:%02d:%02d:%02d%c%d:%d:%s", - (utc.tm_year + 1900) % 100, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, - (tzdiff >= 0) ? '+' : '-', (tzdiff >= 0 ? tzdiff : -tzdiff) / 15, - (local.tm_isdst > 0), - tzname ); -} - - -static const char* -handleListPDPContexts( const char* cmd, AModem modem ) -{ - int nn; - assert( !memcmp( cmd, "+CGACT?", 7 ) ); - amodem_begin_line( modem ); - for (nn = 0; nn < MAX_DATA_CONTEXTS; nn++) { - ADataContext data = modem->data_contexts + nn; - if (!data->active) - continue; - amodem_add_line( modem, "+CGACT: %d,%d\r", data->id, data->active ); - } - return amodem_end_line( modem ); -} - -static const char* -handleDefinePDPContext( const char* cmd, AModem modem ) -{ - assert( !memcmp( cmd, "+CGDCONT=", 9 ) ); - cmd += 9; - if (cmd[0] == '?') { - int nn; - amodem_begin_line(modem); - for (nn = 0; nn < MAX_DATA_CONTEXTS; nn++) { - ADataContext data = modem->data_contexts + nn; - if (!data->active) - continue; - amodem_add_line( modem, "+CGDCONT: %d,%s,\"%s\",,0,0\r\n", - data->id, - data->type == A_DATA_IP ? "IP" : "PPP", - data->apn ); - } - return amodem_end_line(modem); - } else { - /* template is +CGDCONT=<id>,"<type>","<apn>",,0,0 */ - int id = cmd[0] - '1'; - ADataType type; - char apn[32]; - ADataContext data; - - if ((unsigned)id > 3) - goto BadCommand; - - if ( !memcmp( cmd+1, ",\"IP\",\"", 7 ) ) { - type = A_DATA_IP; - cmd += 8; - } else if ( !memcmp( cmd+1, ",\"PPP\",\"", 8 ) ) { - type = A_DATA_PPP; - cmd += 9; - } else - goto BadCommand; - - { - const char* p = strchr( cmd, '"' ); - int len; - if (p == NULL) - goto BadCommand; - len = (int)( p - cmd ); - if (len > sizeof(apn)-1 ) - len = sizeof(apn)-1; - memcpy( apn, cmd, len ); - apn[len] = 0; - } - - data = modem->data_contexts + id; - - data->id = id + 1; - data->active = 1; - data->type = type; - memcpy( data->apn, apn, sizeof(data->apn) ); - } - return NULL; -BadCommand: - return "ERROR: BAD COMMAND"; -} - - -static const char* -handleStartPDPContext( const char* cmd, AModem modem ) -{ - /* XXX: TODO: handle PDP start appropriately */ - /* for the moment, always return success */ -#if 0 - AVoiceCall vcall = amodem_alloc_call( modem ); - ACall call = (ACall) vcall; - if (call == NULL) { - return "ERROR: TOO MANY CALLS"; - } - call->id = 1; - call->dir = A_CALL_OUTBOUND; - /* XXX: it would be better to delay this */ - call->state = A_CALL_ACTIVE; - call->mode = A_CALL_DATA; - call->multi = 0; - strcpy( call->number, "012345" ); -#endif - return NULL; -} - - -static void -remote_voice_call_event( void* _vcall, int success ) -{ - AVoiceCall vcall = _vcall; - AModem modem = vcall->modem; - - /* NOTE: success only means we could send the "gsm in new" command - * to the remote emulator, nothing more */ - - if (!success) { - /* aargh, the remote emulator probably quitted at that point */ - amodem_free_call(modem, vcall); - amodem_send_calls_update(modem); - } -} - - -static void -voice_call_event( void* _vcall ) -{ - AVoiceCall vcall = _vcall; - ACall call = &vcall->call; - - switch (call->state) { - case A_CALL_DIALING: - call->state = A_CALL_ALERTING; - - if (vcall->is_remote) { - if ( remote_call_dial( call->number, - vcall->modem->base_port, - remote_voice_call_event, vcall ) < 0 ) - { - /* we could not connect, probably because the corresponding - * emulator is not running, so simply destroy this call. - * XXX: should we send some sort of message to indicate BAD NUMBER ? */ - /* it seems the Android code simply waits for changes in the list */ - amodem_free_call( vcall->modem, vcall ); - } - } else { - /* this is not a remote emulator number, so just simulate - * a small ringing delay */ - sys_timer_set( vcall->timer, sys_time_ms() + CALL_DELAY_ALERT, - voice_call_event, vcall ); - } - break; - - case A_CALL_ALERTING: - call->state = A_CALL_ACTIVE; - break; - - default: - assert( 0 && "unreachable event call state" ); - } - amodem_send_calls_update(vcall->modem); -} - - -static const char* -handleDial( const char* cmd, AModem modem ) -{ - AVoiceCall vcall = amodem_alloc_call( modem ); - ACall call = &vcall->call; - int len; - - if (call == NULL) - return "ERROR: TOO MANY CALLS"; - - assert( cmd[0] == 'D' ); - call->dir = A_CALL_OUTBOUND; - call->state = A_CALL_DIALING; - call->mode = A_CALL_VOICE; - call->multi = 0; - - cmd += 1; - len = strlen(cmd); - if (len > 0 && cmd[len-1] == ';') - len--; - if (len >= sizeof(call->number)) - len = sizeof(call->number)-1; - - memcpy( call->number, cmd, len ); - call->number[len] = 0; - - vcall->is_remote = (remote_number_string_to_port(call->number) > 0); - - vcall->timer = sys_timer_create(); - sys_timer_set( vcall->timer, sys_time_ms() + CALL_DELAY_DIAL, - voice_call_event, vcall ); - - return NULL; -} - - -static const char* -handleAnswer( const char* cmd, AModem modem ) -{ - int nn; - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - - if (cmd[0] == 'A') { - if (call->state == A_CALL_INCOMING) { - acall_set_state( vcall, A_CALL_ACTIVE ); - } - else if (call->state == A_CALL_ACTIVE) { - acall_set_state( vcall, A_CALL_HELD ); - } - } else if (cmd[0] == 'H') { - /* ATH: hangup, since user is busy */ - if (call->state == A_CALL_INCOMING) { - amodem_free_call( modem, vcall ); - break; - } - } - } - return NULL; -} - -static const char* -handleHangup( const char* cmd, AModem modem ) -{ - if ( !memcmp(cmd, "+CHLD=", 6) ) { - int nn; - cmd += 6; - switch (cmd[0]) { - case '0': /* release all held, and set busy for waiting calls */ - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_HELD || - call->state == A_CALL_WAITING || - call->state == A_CALL_INCOMING) { - amodem_free_call(modem, vcall); - nn--; - } - } - break; - - case '1': - if (cmd[1] == 0) { /* release all active, accept held one */ - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_ACTIVE) { - amodem_free_call(modem, vcall); - nn--; - } - else if (call->state == A_CALL_HELD || - call->state == A_CALL_WAITING) { - acall_set_state( vcall, A_CALL_ACTIVE ); - } - } - } else { /* release specific call */ - int id = cmd[1] - '0'; - AVoiceCall vcall = amodem_find_call( modem, id ); - if (vcall != NULL) - amodem_free_call( modem, vcall ); - } - break; - - case '2': - if (cmd[1] == 0) { /* place all active on hold, accept held or waiting one */ - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_ACTIVE) { - acall_set_state( vcall, A_CALL_HELD ); - } - else if (call->state == A_CALL_HELD || - call->state == A_CALL_WAITING) { - acall_set_state( vcall, A_CALL_ACTIVE ); - } - } - } else { /* place all active on hold, except a specific one */ - int id = cmd[1] - '0'; - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_ACTIVE && call->id != id) { - acall_set_state( vcall, A_CALL_HELD ); - } - } - } - break; - - case '3': /* add a held call to the conversation */ - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_HELD) { - acall_set_state( vcall, A_CALL_ACTIVE ); - break; - } - } - break; - - case '4': /* connect the two calls */ - for (nn = 0; nn < modem->call_count; nn++) { - AVoiceCall vcall = modem->calls + nn; - ACall call = &vcall->call; - if (call->mode != A_CALL_VOICE) - continue; - if (call->state == A_CALL_HELD) { - acall_set_state( vcall, A_CALL_ACTIVE ); - break; - } - } - break; - } - } - else - return "ERROR: BAD COMMAND"; - - return NULL; -} - - -/* a function used to deal with a non-trivial request */ -typedef const char* (*ResponseHandler)(const char* cmd, AModem modem); - -static const struct { - const char* cmd; /* command coming from libreference-ril.so, if first - character is '!', then the rest is a prefix only */ - - const char* answer; /* default answer, NULL if needs specific handling or - if OK is good enough */ - - ResponseHandler handler; /* specific handler, ignored if 'answer' is not NULL, - NULL if OK is good enough */ -} sDefaultResponses[] = -{ - /* see onRadioPowerOn() */ - { "%CPHS=1", NULL, NULL }, - { "%CTZV=1", NULL, NULL }, - - /* see onSIMReady() */ - { "+CSMS=1", "+CSMS: 1, 1, 1", NULL }, - { "+CNMI=1,2,2,1,1", NULL, NULL }, - - /* see requestRadioPower() */ - { "+CFUN=0", NULL, handleRadioPower }, - { "+CFUN=1", NULL, handleRadioPower }, - - /* see requestOrSendPDPContextList() */ - { "+CGACT?", "", handleListPDPContexts }, - - /* see requestOperator() */ - { "+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", NULL, handleRequestOperator }, - - /* see requestQueryNetworkSelectionMode() */ - { "!+COPS", NULL, handleOperatorSelection }, - - /* see requestGetCurrentCalls() */ - { "+CLCC", NULL, handleListCurrentCalls }, - - /* see requestWriteSmsToSim() */ - { "!+CMGW=", NULL, handleSendSMStoSIM }, - - /* see requestHangup() */ - { "!+CHLD=", NULL, handleHangup }, - - /* see requestSignalStrength() */ - { "+CSQ", "+CSQ: 7,99", NULL }, /* XXX: TODO: implement variable signal strength and error rates */ - - /* see requestRegistrationState() */ - { "!+CREG", NULL, handleNetworkRegistration }, - { "!+CGREG", NULL, handleNetworkRegistration }, - - /* see requestSendSMS() */ - { "!+CMGS=", NULL, handleSendSMS }, - - /* see requestSetupDefaultPDP() */ - { "%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"", NULL, NULL }, - { "%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL, NULL }, - - { "!+CGDCONT=", NULL, handleDefinePDPContext }, - - { "+CGQREQ=1", NULL, NULL }, - { "+CGQMIN=1", NULL, NULL }, - { "+CGEREP=1,0", NULL, NULL }, - { "+CGACT=1,0", NULL, NULL }, - { "D*99***1#", NULL, handleStartPDPContext }, - - /* see requestDial() */ - { "!D", NULL, handleDial }, /* the code says that success/error is ignored, the call state will - be polled through +CLCC instead */ - - /* see requestSMSAcknowledge() */ - { "+CNMA=1", NULL, NULL }, - { "+CNMA=2", NULL, NULL }, - - /* see requestSIM_IO() */ - { "!+CRSM=", NULL, handleSIM_IO }, - - /* see onRequest() */ - { "+CHLD=0", NULL, handleHangup }, - { "+CHLD=1", NULL, handleHangup }, - { "+CHLD=2", NULL, handleHangup }, - { "+CHLD=3", NULL, handleHangup }, - { "A", NULL, handleAnswer }, /* answer the call */ - { "H", NULL, handleAnswer }, /* user is busy */ - { "!+VTS=", NULL, handleSetDialTone }, - { "+CIMI", OPERATOR_HOME_MCCMNC "000000000", NULL }, /* request internation subscriber identification number */ - { "+CGSN", "000000000000000", NULL }, /* request model version */ - { "+CUSD=2",NULL, NULL }, /* Cancel USSD */ - { "+COPS=0", NULL, handleOperatorSelection }, /* set network selection to automatic */ - { "!+CMGD=", NULL, handleDeleteSMSonSIM }, /* delete SMS on SIM */ - { "!+CPIN=", NULL, handleChangeOrEnterPIN }, - - /* see getSIMStatus() */ - { "+CPIN?", NULL, handleSIMStatusReq }, - { "+CNMI?", "+CNMI: 1,2,2,1,1", NULL }, - - /* see isRadioOn() */ - { "+CFUN?", NULL, handleRadioPowerReq }, - - /* see initializeCallback() */ - { "E0Q0V1", NULL, NULL }, - { "S0=0", NULL, NULL }, - { "+CMEE=1", NULL, NULL }, - { "+CREG=2", NULL, handleNetworkRegistration }, - { "+CREG=1", NULL, handleNetworkRegistration }, - { "+CGREG=1", NULL, handleNetworkRegistration }, - { "+CCWA=1", NULL, NULL }, - { "+CMOD=0", NULL, NULL }, - { "+CMUT=0", NULL, NULL }, - { "+CSSN=0,1", NULL, NULL }, - { "+COLP=0", NULL, NULL }, - { "+CSCS=\"HEX\"", NULL, NULL }, - { "+CUSD=1", NULL, NULL }, - { "+CGEREP=1,0", NULL, NULL }, - { "+CMGF=0", NULL, handleEndOfInit }, /* now is a goof time to send the current tme and timezone */ - { "%CPI=3", NULL, NULL }, - { "%CSTAT=1", NULL, NULL }, - - /* end of list */ - {NULL, NULL, NULL} -}; - - -#define REPLY(str) do { const char* s = (str); R(">> %s\n", quote(s)); return s; } while (0) - -const char* amodem_send( AModem modem, const char* cmd ) -{ - const char* answer; - - if ( modem->wait_sms != 0 ) { - modem->wait_sms = 0; - R( "SMS<< %s\n", quote(cmd) ); - answer = handleSendSMSText( cmd, modem ); - REPLY(answer); - } - - /* everything that doesn't start with 'AT' is not a command, right ? */ - if ( cmd[0] != 'A' || cmd[1] != 'T' || cmd[2] == 0 ) { - /* R( "-- %s\n", quote(cmd) ); */ - return NULL; - } - R( "<< %s\n", quote(cmd) ); - - cmd += 2; - - /* TODO: implement command handling */ - { - int nn, found = 0; - - for (nn = 0; ; nn++) { - const char* scmd = sDefaultResponses[nn].cmd; - - if (!scmd) /* end of list */ - break; - - if (scmd[0] == '!') { /* prefix match */ - int len = strlen(++scmd); - - if ( !memcmp( scmd, cmd, len ) ) { - found = 1; - break; - } - } else { /* full match */ - if ( !strcmp( scmd, cmd ) ) { - found = 1; - break; - } - } - } - - if ( !found ) - { - D( "** UNSUPPORTED COMMAND **\n" ); - REPLY( "ERROR: UNSUPPORTED" ); - } - else - { - const char* answer = sDefaultResponses[nn].answer; - ResponseHandler handler = sDefaultResponses[nn].handler; - - if ( answer != NULL ) { - REPLY( amodem_printf( modem, "%s\rOK", answer ) ); - } - - if (handler == NULL) { - REPLY( "OK" ); - } - - answer = handler( cmd, modem ); - if (answer == NULL) - REPLY( "OK" ); - - if ( !memcmp( answer, "> ", 2 ) || - !memcmp( answer, "ERROR", 5 ) || - !memcmp( answer, "+CME ERROR", 6 ) ) - { - REPLY( answer ); - } - - if (answer != modem->out_buff) - REPLY( amodem_printf( modem, "%s\rOK", answer ) ); - - strcat( modem->out_buff, "\rOK" ); - REPLY( answer ); - } - } -} diff --git a/telephony/android_modem.h b/telephony/android_modem.h deleted file mode 100644 index 80d22c5..0000000 --- a/telephony/android_modem.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _android_modem_h_ -#define _android_modem_h_ - -#include "sim_card.h" -#include "sms.h" - -/** MODEM OBJECT - **/ -typedef struct AModemRec_* AModem; - -/* a function used by the modem to send unsolicited messages to the channel controller */ -typedef void (*AModemUnsolFunc)( void* opaque, const char* message ); - -extern AModem amodem_create( int base_port, AModemUnsolFunc unsol_func, void* unsol_opaque ); -extern void amodem_destroy( AModem modem ); - -/* send a command to the modem */ -extern const char* amodem_send( AModem modem, const char* cmd ); - -/* simulate the receipt on an incoming SMS message */ -extern void amodem_receive_sms( AModem modem, SmsPDU pdu ); - -/** RADIO STATE - **/ -typedef enum { - A_RADIO_STATE_OFF = 0, /* Radio explictly powered off (eg CFUN=0) */ - A_RADIO_STATE_ON, /* Radio on */ -} ARadioState; - -extern ARadioState amodem_get_radio_state( AModem modem ); -extern void amodem_set_radio_state( AModem modem, ARadioState state ); - -/** SIM CARD STATUS - **/ -extern ASimCard amodem_get_sim( AModem modem ); - -/** VOICE AND DATA NETWORK REGISTRATION - **/ - -/* 'stat' for +CREG/+CGREG commands */ -typedef enum { - A_REGISTRATION_UNREGISTERED = 0, - A_REGISTRATION_HOME = 1, - A_REGISTRATION_SEARCHING, - A_REGISTRATION_DENIED, - A_REGISTRATION_UNKNOWN, - A_REGISTRATION_ROAMING -} ARegistrationState; - -typedef enum { - A_GPRS_NETWORK_UNKNOWN = 0, - A_GPRS_NETWORK_GPRS, - A_GPRS_NETWORK_EDGE, - A_GPRS_NETWORK_UMTS -} AGprsNetworkType; - -extern ARegistrationState amodem_get_voice_registration( AModem modem ); -extern void amodem_set_voice_registration( AModem modem, ARegistrationState state ); - -extern ARegistrationState amodem_get_data_registration( AModem modem ); -extern void amodem_set_data_registration( AModem modem, ARegistrationState state ); -extern void amodem_set_data_network_type( AModem modem, AGprsNetworkType type ); - -extern AGprsNetworkType android_parse_network_type( const char* speed ); - - -/** OPERATOR NAMES - **/ -typedef enum { - A_NAME_LONG = 0, - A_NAME_SHORT, - A_NAME_NUMERIC, - A_NAME_MAX /* don't remove */ -} ANameIndex; - -/* retrieve operator name into user-provided buffer. returns number of writes written, including terminating zero */ -extern int amodem_get_operator_name ( AModem modem, ANameIndex index, char* buffer, int buffer_size ); - -/* reset one operator name from a user-provided buffer, set buffer_size to -1 for zero-terminated strings */ -extern void amodem_set_operator_name( AModem modem, ANameIndex index, const char* buffer, int buffer_size ); - -/** CALL STATES - **/ - -typedef enum { - A_CALL_OUTBOUND = 0, - A_CALL_INBOUND = 1, -} ACallDir; - -typedef enum { - A_CALL_ACTIVE = 0, - A_CALL_HELD, - A_CALL_DIALING, - A_CALL_ALERTING, - A_CALL_INCOMING, - A_CALL_WAITING -} ACallState; - -typedef enum { - A_CALL_VOICE = 0, - A_CALL_DATA, - A_CALL_FAX, - A_CALL_UNKNOWN = 9 -} ACallMode; - -#define A_CALL_NUMBER_MAX_SIZE 16 - -typedef struct { - int id; - ACallDir dir; - ACallState state; - ACallMode mode; - int multi; - char number[ A_CALL_NUMBER_MAX_SIZE+1 ]; -} ACallRec, *ACall; - -extern int amodem_get_call_count( AModem modem ); -extern ACall amodem_get_call( AModem modem, int index ); -extern ACall amodem_find_call_by_number( AModem modem, const char* number ); -extern int amodem_add_inbound_call( AModem modem, const char* number ); -extern int amodem_update_call( AModem modem, const char* number, ACallState state ); -extern int amodem_disconnect_call( AModem modem, const char* number ); - -/**/ - -#endif /* _android_modem_h_ */ diff --git a/telephony/gsm.c b/telephony/gsm.c deleted file mode 100644 index b55578d..0000000 --- a/telephony/gsm.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "gsm.h" -#include <stdlib.h> -#include <string.h> - -/** UTILITIES - **/ -byte_t -gsm_int_to_bcdi( int value ) -{ - return (byte_t)((value / 10) | ((value % 10) << 4)); -} - -int -gsm_int_from_bcdi( byte_t val ) -{ - int ret = 0; - - if ((val & 0xf0) <= 0x90) - ret = (val >> 4); - - if ((val & 0x0f) <= 0x90) - ret |= (val % 0xf)*10; - - return ret; -} - -#if 0 -static int -gsm_bcdi_to_ascii( cbytes_t bcd, int bcdlen, bytes_t dst ) -{ - static byte_t bcdichars[14] = "0123456789*#,N"; - - int result = 0; - int shift = 0; - - while (bcdlen > 0) { - int c = (bcd[0] >> shift) & 0xf; - - if (c == 0xf && bcdlen == 1) - break; - - if (c < 14) { - if (dst) dst[result] = bcdichars[c]; - result += 1; - } - bcdlen --; - shift += 4; - if (shift == 8) { - bcd++; - shift = 0; - } - } - return result; -} -#endif - -#if 0 -static int -gsm_bcdi_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst ) -{ - cbytes_t end = ascii + asciilen; - int result = 0; - int phase = 0x01; - - while (ascii < end) { - int c = *ascii++; - - if (c == '*') - c = 11; - else if (c == '#') - c = 12; - else if (c == ',') - c = 13; - else if (c == 'N') - c = 14; - else { - c -= '0'; - if ((unsigned)c >= 10) - break; - } - phase = (phase << 4) | c; - if (phase & 0x100) { - if (dst) dst[result] = (byte_t) phase; - result += 1; - phase = 0x01; - } - } - if (phase != 0x01) { - if (dst) dst[result] = (byte_t)( phase | 0xf0 ); - result += 1; - } - return result; -} -#endif - -int -gsm_hexchar_to_int( char c ) -{ - if ((unsigned)(c - '0') < 10) - return c - '0'; - if ((unsigned)(c - 'a') < 6) - return 10 + (c - 'a'); - if ((unsigned)(c - 'A') < 6) - return 10 + (c - 'A'); - return -1; -} - -int -gsm_hexchar_to_int0( char c ) -{ - int ret = gsm_hexchar_to_int(c); - - return (ret < 0) ? 0 : ret; -} - -int -gsm_hex2_to_byte( const char* hex ) -{ - int hi = gsm_hexchar_to_int(hex[0]); - int lo = gsm_hexchar_to_int(hex[1]); - - if (hi < 0 || lo < 0) - return -1; - - return ( (hi << 4) | lo ); -} - -int -gsm_hex4_to_short( const char* hex ) -{ - int hi = gsm_hex2_to_byte(hex); - int lo = gsm_hex2_to_byte(hex+2); - - if (hi < 0 || lo < 0) - return -1; - - return ((hi << 8) | lo); -} - -int -gsm_hex2_to_byte0( const char* hex ) -{ - int hi = gsm_hexchar_to_int0(hex[0]); - int lo = gsm_hexchar_to_int0(hex[1]); - - return (byte_t)( (hi << 4) | lo ); -} - -void -gsm_hex_from_byte( char* hex, int val ) -{ - static const char hexdigits[] = "0123456789abcdef"; - - hex[0] = hexdigits[(val >> 4) & 15]; - hex[1] = hexdigits[val & 15]; -} - -void -gsm_hex_from_short( char* hex, int val ) -{ - gsm_hex_from_byte( hex, (val >> 8) ); - gsm_hex_from_byte( hex+2, val ); -} - - - -/** HEX - **/ -void -gsm_hex_to_bytes0( cbytes_t hex, int hexlen, bytes_t dst ) -{ - int nn; - - for (nn = 0; nn < hexlen/2; nn++ ) { - dst[nn] = (byte_t) gsm_hex2_to_byte0( (const char*)hex+2*nn ); - } - if (hexlen & 1) { - dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4; - } -} - -int -gsm_hex_to_bytes( cbytes_t hex, int hexlen, bytes_t dst ) -{ - int nn; - - if (hexlen & 1) /* must be even */ - return -1; - - for (nn = 0; nn < hexlen/2; nn++ ) { - int c = gsm_hex2_to_byte( (const char*)hex+2*nn ); - if (c < 0) return -1; - dst[nn] = (byte_t) c; - } - return hexlen/2; -} - -void -gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen ) -{ - int nn; - - for (nn = 0; nn < srclen; nn++) { - gsm_hex_from_byte( hex + 2*nn, src[nn] ); - } -} - -/** ROPES - **/ - -void -gsm_rope_init( GsmRope rope ) -{ - rope->data = NULL; - rope->pos = 0; - rope->max = 0; - rope->error = 0; -} - -void -gsm_rope_init_alloc( GsmRope rope, int count ) -{ - rope->data = rope->data0; - rope->pos = 0; - rope->max = sizeof(rope->data0); - rope->error = 0; - - if (count > 0) { - rope->data = calloc( count, 1 ); - rope->max = count; - - if (rope->data == NULL) { - rope->error = 1; - rope->max = 0; - } - } -} - -int -gsm_rope_done( GsmRope rope ) -{ - int result = rope->error; - - if (rope->data && rope->data != rope->data0) - free(rope->data); - - rope->data = NULL; - rope->pos = 0; - rope->max = 0; - rope->error = 0; - - return result; -} - - -bytes_t -gsm_rope_done_acquire( GsmRope rope, int *psize ) -{ - bytes_t result = rope->data; - - *psize = rope->pos; - if (result == rope->data0) { - result = malloc( rope->pos ); - if (result != NULL) - memcpy( result, rope->data, rope->pos ); - } - return result; -} - - -int -gsm_rope_ensure( GsmRope rope, int new_count ) -{ - if (rope->data != NULL) { - int old_max = rope->max; - bytes_t old_data = rope->data == rope->data0 ? NULL : rope->data; - int new_max = old_max; - bytes_t new_data; - - while (new_max < new_count) { - new_max += (new_max >> 1) + 4; - } - new_data = realloc( old_data, new_max ); - if (new_data == NULL) { - rope->error = 1; - return -1; - } - rope->data = new_data; - rope->max = new_max; - } else { - rope->max = new_count; - } - return 0; -} - -static int -gsm_rope_can_grow( GsmRope rope, int count ) -{ - if (!rope->data || rope->error) - return 0; - - if (rope->pos + count > rope->max) - { - if (rope->data == NULL) - rope->max = rope->pos + count; - - else if (rope->error || - gsm_rope_ensure( rope, rope->pos + count ) < 0) - return 0; - } - return 1; -} - -void -gsm_rope_add_c( GsmRope rope, char c ) -{ - if (gsm_rope_can_grow(rope, 1)) { - rope->data[ rope->pos ] = (byte_t) c; - } - rope->pos += 1; -} - -void -gsm_rope_add( GsmRope rope, const void* buf, int buflen ) -{ - if (gsm_rope_can_grow(rope, buflen)) { - memcpy( rope->data + rope->pos, (const char*)buf, buflen ); - } - rope->pos += buflen; -} - -void* -gsm_rope_reserve( GsmRope rope, int count ) -{ - void* result = NULL; - - if (gsm_rope_can_grow(rope, count)) - { - if (rope->data != NULL) - result = rope->data + rope->pos; - } - rope->pos += count; - - return result; -} - -/* skip a given number of Unicode characters in a utf-8 byte string */ -cbytes_t -utf8_skip( cbytes_t utf8, - cbytes_t utf8end, - int count) -{ - cbytes_t p = utf8; - cbytes_t end = utf8end; - - for ( ; count > 0; count-- ) { - int c; - - if (p >= end) - break; - - c = *p++; - if (c > 128) { - while (p < end && (p[0] & 0xc0) == 0x80) - p++; - } - } - return p; -} - - -static __inline__ int -utf8_next( cbytes_t *pp, cbytes_t end ) -{ - cbytes_t p = *pp; - int result = -1; - - if (p < end) { - int c= *p++; - if (c >= 128) { - if ((c & 0xe0) == 0xc0) - c &= 0x1f; - else if ((c & 0xf0) == 0xe0) - c &= 0x0f; - else - c &= 0x07; - - while (p < end && (p[0] & 0xc0) == 0x80) { - c = (c << 6) | (p[0] & 0x3f); - p ++; - } - } - result = c; - *pp = p; - } - return result; -} - - -__inline__ int -utf8_write( bytes_t utf8, int offset, int v ) -{ - int result; - - if (v < 128) { - result = 1; - if (utf8) - utf8[offset] = (byte_t) v; - } else if (v < 0x800) { - result = 2; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xc0 | (v >> 6) ); - utf8[offset+1] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } else if (v < 0x10000) { - result = 3; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xe0 | (v >> 12) ); - utf8[offset+1] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) ); - utf8[offset+2] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } else { - result = 4; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xf0 | ((v >> 18) & 0x7) ); - utf8[offset+1] = (byte_t)( 0x80 | ((v >> 12) & 0x3f) ); - utf8[offset+2] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) ); - utf8[offset+3] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } - return result; -} - -static __inline__ int -ucs2_write( bytes_t ucs2, int offset, int v ) -{ - if (ucs2) { - ucs2[offset+0] = (byte_t) (v >> 8); - ucs2[offset+1] = (byte_t) (v); - } - return 2; -} - -int -utf8_check( cbytes_t p, int utf8len ) -{ - cbytes_t end = p + utf8len; - int result = 0; - - if (p) { - while (p < end) { - int c = *p++; - if (c >= 128) { - int len; - if ((c & 0xe0) == 0xc0) { - len = 1; - } - else if ((c & 0xf0) == 0xe0) { - len = 2; - } - else if ((c & 0xf8) == 0xf0) { - len = 3; - } - else - goto Exit; /* malformed utf-8 */ - - if (p+len > end) /* string too short */ - goto Exit; - - for ( ; len > 0; len--, p++ ) { - if ((p[0] & 0xc0) != 0x80) - goto Exit; - } - } - } - result = 1; - } -Exit: - return result; -} - -/** UCS2 to UTF8 - **/ - -/* convert a UCS2 string into a UTF8 byte string, assumes 'buf' is correctly sized */ -int -ucs2_to_utf8( cbytes_t ucs2, - int ucs2len, - bytes_t buf ) -{ - int nn; - int result = 0; - - for (nn = 0; nn < ucs2len; ucs2 += 2, nn++) { - int c= (ucs2[0] << 8) | ucs2[1]; - result += utf8_write(buf, result, c); - } - return result; -} - -/* count the number of UCS2 chars contained in a utf8 byte string */ -int -utf8_to_ucs2( cbytes_t utf8, - int utf8len, - bytes_t ucs2 ) -{ - cbytes_t p = utf8; - cbytes_t end = p + utf8len; - int result = 0; - - while (p < end) { - int c = utf8_next(&p, end); - - if (c < 0) - break; - - result += ucs2_write(ucs2, result, c); - } - return result/2; -} - - - -/** GSM ALPHABET - **/ - -#define GSM_7BITS_ESCAPE 0x1b -#define GSM_7BITS_UNKNOWN 0 - -static const unsigned short gsm7bits_to_unicode[128] = { - '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5, -0x394, '_',0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,0x3a3,0x398,0x39e, 0, 0xc6, 0xe6, 0xdf, 0xc9, - ' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', - 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6,0x147, 0xdc, 0xa7, - 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0, -}; - -static const unsigned short gsm7bits_extend_to_unicode[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0, - 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\', - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0, - '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,0x20ac, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - - -static int -unichar_to_gsm7( int unicode ) -{ - int nn; - for (nn = 0; nn < 128; nn++) { - if (gsm7bits_to_unicode[nn] == unicode) { - return nn; - } - } - return -1; -} - -static int -unichar_to_gsm7_extend( int unichar ) -{ - int nn; - for (nn = 0; nn < 128; nn++) { - if (gsm7bits_extend_to_unicode[nn] == unichar) { - return nn; - } - } - return -1; -} - - -/* return the number of septets needed to encode a unicode charcode */ -static int -unichar_to_gsm7_count( int unicode ) -{ - int nn; - - nn = unichar_to_gsm7(unicode); - if (nn >= 0) - return 1; - - nn = unichar_to_gsm7_extend(unicode); - if (nn >= 0) - return 2; - - return 0; -} - - -cbytes_t -utf8_skip_gsm7( cbytes_t utf8, cbytes_t utf8end, int gsm7len ) -{ - cbytes_t p = utf8; - cbytes_t end = utf8end; - - while (gsm7len >0) { - cbytes_t q = p; - int c = utf8_next( &q, end ); - int len; - - if (c < 0) - break; - - len = unichar_to_gsm7_count( c ); - if (len == 0) /* unknown chars are replaced by spaces */ - len = 1; - - if (len > gsm7len) - break; - - gsm7len -= len; - p = q; - } - return p; -} - - -int -utf8_check_gsm7( cbytes_t utf8, - int utf8len ) -{ - cbytes_t utf8end = utf8 + utf8len; - - while (utf8 < utf8end) { - int c = utf8_next( &utf8, utf8end ); - if (unichar_to_gsm7_count(c) == 0) - return 0; - } - return 1; -} - - -int -utf8_from_gsm7( cbytes_t src, - int septet_offset, - int septet_count, - bytes_t utf8 ) -{ - int shift = (septet_offset & 7); - int escaped = 0; - int result = 0; - - src += (septet_offset >> 3); - for ( ; septet_count > 0; septet_count-- ) - { - int c = (src[0] >> shift) & 0x7f; - int v; - - if (shift > 1) { - c = ((src[1] << (8-shift)) | c) & 0x7f; - } - - if (escaped) { - v = gsm7bits_extend_to_unicode[c]; - } else if (c == GSM_7BITS_ESCAPE) { - escaped = 1; - goto NextSeptet; - } else { - v = gsm7bits_to_unicode[c]; - } - - result += utf8_write( utf8, result, v ); - - NextSeptet: - shift += 7; - if (shift >= 8) { - shift -= 8; - src += 1; - } - } - return result; -} - - -int -utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 ) -{ - int result = 0; - int escaped = 0; - - - for ( ; count > 0; count-- ) - { - int c = *src++; - - if (c == 0xff) - break; - - if (c == GSM_7BITS_ESCAPE) { - if (escaped) { /* two escape characters => one space */ - c = 0x20; - escaped = 0; - } else { - escaped = 1; - continue; - } - } - else - { - if (c >= 0x80) { - c = 0x20; - escaped = 0; - } else if (escaped) { - c = gsm7bits_extend_to_unicode[c]; - } else - c = gsm7bits_to_unicode[c]; - } - - result += utf8_write( utf8, result, c ); - } - return result; -} - -/* convert a GSM 7-bit message into a unicode character array - * the 'dst' array must contain at least 160 chars. the function - * returns the number of characters decoded - * - * assumes the 'dst' array has at least septet_count items, returns the - * number of unichars really written - */ -int -ucs2_from_gsm7( bytes_t ucs2, - cbytes_t src, - int septet_offset, - int septet_count ) -{ - const unsigned char* p = src + (septet_offset >> 3); - int shift = (septet_offset & 7); - int escaped = 0; - int result = 0; - - for ( ; septet_count > 0; septet_count-- ) - { - unsigned val = (p[0] >> shift) & 0x7f; - - if (shift > 1) - val = (val | (p[1] << (8-shift))) & 0x7f; - - if (escaped) { - int c = gsm7bits_to_unicode[val]; - - result += ucs2_write(ucs2, result, c); - escaped = 0; - } - else if (val == GSM_7BITS_ESCAPE) { - escaped = 1; - } - else { - val = gsm7bits_extend_to_unicode[val]; - if (val == 0) - val = 0x20; - - result += ucs2_write( ucs2, result, val ); - } - } - return result/2; -} - - -/* count the number of septets required to write a utf8 string */ -static int -utf8_to_gsm7_count( cbytes_t utf8, int utf8len ) -{ - cbytes_t utf8end = utf8 + utf8len; - int result = 0; - - while ( utf8 < utf8end ) { - int len; - int c = utf8_next( &utf8, utf8end ); - - if (c < 0) - break; - - len = unichar_to_gsm7_count(c); - if (len == 0) /* replace non-representables with space */ - len = 1; - - result += len; - } - return result; -} - -typedef struct { - bytes_t dst; - unsigned pad; - int bits; - int offset; -} BWriterRec, *BWriter; - -static void -bwriter_init( BWriter writer, bytes_t dst, int start ) -{ - int shift = start & 7; - - writer->dst = dst + (start >> 3); - writer->pad = 0; - writer->bits = shift; - writer->offset = start; - - if (shift > 0) { - writer->pad = writer->dst[0] & ~(0xFF << shift); - } -} - -static void -bwriter_add7( BWriter writer, unsigned value ) -{ - writer->pad |= (unsigned)(value << writer->bits); - writer->bits += 7; - if (writer->bits >= 8) { - writer->dst[0] = (byte_t)writer->pad; - writer->bits -= 8; - writer->pad >>= 8; - writer->dst += 1; - } - writer->offset += 7; -} - -static int -bwriter_done( BWriter writer ) -{ - if (writer->bits > 0) { - writer->dst[0] = (byte_t)writer->pad; - writer->pad = 0; - writer->bits = 0; - writer->dst += 1; - } - return writer->offset; -} - -/* convert a utf8 string to a gsm7 byte string - return the number of septets written */ -int -utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset ) -{ - const unsigned char* utf8end = utf8 + utf8len; - BWriterRec writer[1]; - - if (dst == NULL) - return utf8_to_gsm7_count(utf8, utf8len); - - bwriter_init( writer, dst, offset ); - while ( utf8 < utf8end ) { - int c = utf8_next( &utf8, utf8end ); - int nn; - - if (c < 0) - break; - - nn = unichar_to_gsm7(c); - if (nn >= 0) { - bwriter_add7( writer, nn ); - continue; - } - - nn = unichar_to_gsm7_extend(c); - if (nn >= 0) { - bwriter_add7( writer, GSM_7BITS_ESCAPE ); - bwriter_add7( writer, nn ); - continue; - } - - /* unknown => replaced by space */ - bwriter_add7( writer, 0x20 ); - } - return bwriter_done( writer ); -} - - -int -utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst ) -{ - const unsigned char* utf8end = utf8 + utf8len; - int result = 0; - - while ( utf8 < utf8end ) { - int c = utf8_next( &utf8, utf8end ); - int nn; - - if (c < 0) - break; - - nn = unichar_to_gsm7(c); - if (nn >= 0) { - if (dst) - dst[result] = (byte_t)nn; - result += 1; - continue; - } - - nn = unichar_to_gsm7_extend(c); - if (nn >= 0) { - if (dst) { - dst[result+0] = (byte_t) GSM_7BITS_ESCAPE; - dst[result+1] = (byte_t) nn; - } - result += 2; - continue; - } - - /* unknown => space */ - if (dst) - dst[result] = 0x20; - result += 1; - } - return result; -} - - -int -ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset ) -{ - const unsigned char* ucs2end = ucs2 + ucs2len*2; - BWriterRec writer[1]; - - bwriter_init( writer, dst, offset ); - while ( ucs2 < ucs2end ) { - int c = *ucs2++; - int nn; - - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_to_unicode[nn] == c ) { - bwriter_add7( writer, nn ); - goto NextUnicode; - } - } - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_extend_to_unicode[nn] == c ) { - bwriter_add7( writer, GSM_7BITS_ESCAPE ); - bwriter_add7( writer, nn ); - goto NextUnicode; - } - } - - /* unknown */ - bwriter_add7( writer, 0x20 ); - - NextUnicode: - ; - } - return bwriter_done( writer ); -} - - -int -ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst ) -{ - const unsigned char* ucs2end = ucs2 + ucs2len*2; - bytes_t dst0 = dst; - - while ( ucs2 < ucs2end ) { - int c = *ucs2++; - int nn; - - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_to_unicode[nn] == c ) { - *dst++ = (byte_t)nn; - goto NextUnicode; - } - } - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_extend_to_unicode[nn] == c ) { - dst[0] = (byte_t) GSM_7BITS_ESCAPE; - dst[1] = (byte_t) nn; - dst += 2; - goto NextUnicode; - } - } - - /* unknown */ - *dst++ = 0x20; - - NextUnicode: - ; - } - return (dst - dst0); -} - -int -gsm_bcdnum_to_ascii( cbytes_t bcd, int count, bytes_t dst ) -{ - int result = 0; - int shift = 0; - - while (count > 0) { - int c = (bcd[0] >> shift) & 0xf; - - if (c == 15 && count == 1) /* ignore trailing 0xf */ - break; - - if (c >= 14) - c = 0; - - if (dst) dst[result] = "0123456789*#,N"[c]; - result += 1; - - shift += 4; - if (shift == 8) { - shift = 0; - bcd += 1; - } - } - return result; -} - - -int -gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst ) -{ - cbytes_t end = ascii + asciilen; - int result = 0; - int phase = 0x01; - - while (ascii < end) { - int c = *ascii++; - - if (c == '*') - c = 10; - else if (c == '#') - c = 11; - else if (c == ',') - c = 12; - else if (c == 'N') - c = 13; - else { - c -= '0'; - if ((unsigned)c >= 10U) - return -1; - } - phase = (phase << 4) | c; - result += 1; - if (phase & 0x100) { - if (dst) dst[result/2] = (byte_t) phase; - phase = 0x01; - } - } - - if (result & 1) { - if (dst) dst[result/2] = (byte_t)(phase | 0xf0); - } - return result; -} - -/** ADN: Abbreviated Dialing Number - **/ - -#define ADN_FOOTER_SIZE 14 -#define ADN_OFFSET_NUMBER_LENGTH 0 -#define ADN_OFFSET_TON_NPI 1 -#define ADN_OFFSET_NUMBER_START 2 -#define ADN_OFFSET_NUMBER_END 11 -#define ADN_OFFSET_CAPABILITY_ID 12 -#define ADN_OFFSET_EXTENSION_ID 13 - -/* see 10.5.1 of 3GPP 51.011 */ -static int -sim_adn_alpha_to_utf8( cbytes_t alpha, cbytes_t end, bytes_t dst ) -{ - int result = 0; - - /* ignore trailing 0xff */ - while (alpha < end && end[-1] == 0xff) - end--; - - if (alpha >= end) - return 0; - - if (alpha[0] == 0x80) { /* UCS/2 source encoding */ - alpha += 1; - result = ucs2_to_utf8( alpha, (end-alpha)/2, dst ); - } - else - { - int is_ucs2 = 0; - int len = 0, base = 0; - - if (alpha+3 <= end && alpha[0] == 0x81) { - is_ucs2 = 1; - len = alpha[1]; - base = alpha[2] << 7; - alpha += 3; - if (len > end-alpha) - len = end-alpha; - } else if (alpha+4 <= end && alpha[0] == 0x82) { - is_ucs2 = 1; - len = alpha[1]; - base = (alpha[2] << 8) | alpha[3]; - alpha += 4; - if (len > end-alpha) - len = end-alpha; - } - - if (is_ucs2) { - end = alpha + len; - while (alpha < end) { - int c = alpha[0]; - if (c >= 0x80) { - result += utf8_write(dst, result, base + (c & 0x7f)); - alpha += 1; - } else { - /* GSM character set */ - int count; - for (count = 0; alpha+count < end && alpha[count] < 128; count++) - ; - result += utf8_from_gsm8(alpha, count, (dst ? dst+result : NULL)); - alpha += count; - } - } - } - else { - result = utf8_from_gsm8(alpha, end-alpha, dst); - } - } - return result; -} - -#if 0 -static int -sim_adn_alpha_from_utf8( cbytes_t utf8, int utf8len, bytes_t dst ) -{ - int result = 0; - - if (utf8_check_gsm7(utf8, utf8len)) { - /* GSM 7-bit compatible, encode directly as 8-bit string */ - result = utf8_to_gsm8(utf8, utf8len, dst); - } else { - /* otherwise, simply try UCS-2 encoding, nothing more serious at the moment */ - if (dst) { - dst[0] = 0x80; - } - result = 1 + utf8_to_ucs2(utf8, utf8len, dst ? (dst+1) : NULL)*2; - } - return result; -} -#endif - -int -sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int len ) -{ - cbytes_t end = data + len; - cbytes_t footer = end - ADN_FOOTER_SIZE; - int num_len; - - rec->adn.alpha[0] = 0; - rec->adn.number[0] = 0; - rec->ext_record = 0xff; - - if (len < ADN_FOOTER_SIZE) - return -1; - - /* alpha is optional */ - if (len > ADN_FOOTER_SIZE) { - cbytes_t dataend = data + len - ADN_FOOTER_SIZE; - int count = sim_adn_alpha_to_utf8(data, dataend, NULL); - - if (count > sizeof(rec->adn.alpha)-1) /* too long */ - return -1; - - sim_adn_alpha_to_utf8(data, dataend, rec->adn.alpha); - rec->adn.alpha[count] = 0; - } - - num_len = footer[ADN_OFFSET_NUMBER_LENGTH]; - if (num_len > 11) - return -1; - - /* decode TON and number to ASCII, NOTE: this is lossy !! */ - { - int ton = footer[ADN_OFFSET_TON_NPI]; - bytes_t number = (bytes_t) rec->adn.number; - int len = sizeof(rec->adn.number)-1; - int count; - - if (ton != 0x81 && ton != 0x91) - return -1; - - if (ton == 0x91) { - *number++ = '+'; - len -= 1; - } - - count = gsm_bcdnum_to_ascii( footer + ADN_OFFSET_NUMBER_START, - num_len*2, number ); - number[count] = 0; - } - return 0; -} - -int -sim_adn_record_to_bytes( SimAdnRecord rec, bytes_t data, int datalen ) -{ - bytes_t end = data + datalen; - bytes_t footer = end - ADN_FOOTER_SIZE; - int ton = 0x81; - cbytes_t number = (cbytes_t) rec->adn.number; - - if (number[0] == '+') { - ton = 0x91; - number += 1; - } - footer[0] = (strlen((const char*)number)+1)/2 + 1; - /* XXXX: TODO */ - return 0; -} diff --git a/telephony/gsm.h b/telephony/gsm.h deleted file mode 100644 index f799dea..0000000 --- a/telephony/gsm.h +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _android_gsm_h -#define _android_gsm_h - -/** USEFUL TYPES - **/ - -typedef unsigned char byte_t; -typedef byte_t* bytes_t; -typedef const byte_t* cbytes_t; - -/** BCD - **/ - -/* convert a 8-bit value into the corresponding nibble-bcd byte */ -extern byte_t gsm_int_to_bcdi( int value ); - -/* convert a nibble-bcd byte into an int, invalid nibbles are silently converted to 0 */ -extern int gsm_int_from_bcdi( byte_t value ); - -/** HEX - **/ - -/* try to convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even. - * returns the number of bytes on exit, or -1 in case of badly formatted data */ -extern int gsm_hex_to_bytes ( cbytes_t hex, int hexlen, bytes_t dst ); - -/* convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even. - * no checks are performed */ -extern void gsm_hex_to_bytes0 ( cbytes_t hex, int hexlen, bytes_t dst ); - -/* convert a byte string into a hex string, assumes 'hex' is properly sized */ -extern void gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen ); - -/* convert a hexchar to an int, returns -1 on error */ -extern int gsm_hexchar_to_int( char c ); - -/* convert a hexchar to an int, returns 0 on error */ -extern int gsm_hexchar_to_int0( char c ); - -/* convert a 2-char hex value into an int, returns -1 on error */ -extern int gsm_hex2_to_byte( const char* hex ); - -/* convert a 2-char hex value into an int, returns 0 on error */ -extern int gsm_hex2_to_byte0( const char* hex ); - -/* convert a 4-char hex value into an int, returns -1 on error */ -extern int gsm_hex4_to_short( const char* hex ); - -/* convert a 4-char hex value into an int, returns 0 on error */ -extern int gsm_hex4_to_short0( const char* hex ); - -/* write a byte to a 2-byte hex string */ -extern void gsm_hex_from_byte( char* hex, int val ); - -extern void gsm_hex_from_short( char* hex, int val ); - -/** UTF-8 and GSM Alphabet - **/ - -/* check that a given utf8 string is well-formed, returns 1 on success, 0 otherwise */ -extern int utf8_check( cbytes_t utf8, int utf8len ); - -/* check that all characters in a given utf8 string can be encoded into the GSM alphabet. - returns 1 if TRUE, 0 otherwise */ -extern int utf8_check_gsm7( cbytes_t utf8, int utf8len ); - -/* try to skip enough utf8 characters to generate gsm7len GSM septets */ -extern cbytes_t utf8_skip_gsm7( cbytes_t utf8, cbytes_t utf8end, int gsm7len ); - -/* convert a utf-8 string into a GSM septet string, assumes 'dst' is NULL or is properly sized, - and that all characters are representable. 'offset' is the starting bit offset in 'dst'. - non-representable characters are replaced by spaces. - returns the number of septets, */ -extern int utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset ); - -/* convert a utf8 string into an array of 8-bit unpacked GSM septets, - * assumes 'dst' is NULL or is properly sized, returns the number of GSM bytes */ -extern int utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst ); - -/* convert a GSM septets string into a utf-8 byte string. assumes that 'utf8' is NULL or properly - sized. 'offset' is the starting bit offset in 'src', 'count' is the number of input septets. - return the number of utf8 bytes. */ -extern int utf8_from_gsm7( cbytes_t src, int offset, int count, bytes_t utf8 ); - -/* convert an unpacked 8-bit GSM septets string into a utf-8 byte string. assumes that 'utf8' - is NULL or properly sized. 'count' is the number of input bytes. - returns the number of utf8 bytes */ -extern int utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 ); - - -/** UCS-2 and GSM Alphabet - ** - ** Note that here, 'ucs2' really refers to non-aligned UCS2-BE, as used by the GSM standard - **/ - -/* check that all characters in a given ucs2 string can be encoded into the GSM alphabet. - returns 1 if TRUE, 0 otherwise */ -extern int ucs2_check_gsm7( cbytes_t ucs2, int ucs2len ); - -/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized, - 'offset' is the starting bit offset in 'dst'. non-representable characters are replaced - by spaces. returns the number of septets */ -extern int ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset ); - -/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized, - non-representable characters are replaced by spaces. returns the number of bytes */ -extern int ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst ); - -/* convert a GSM septets string into a ucs2 string. assumes that 'ucs2' is NULL or - properly sized. 'offset' is the starting bit offset in 'src', 'count' is the number - of input septets. return the number of ucs2 characters (not bytes) */ -extern int ucs2_from_gsm7( bytes_t ucs2, cbytes_t src, int offset, int count ); - -/* convert an 8-bit unpacked GSM septets string into a ucs2 string. assumes that 'ucs2' - is NULL or properly sized. 'count' is the number of input septets. return the number - of ucs2 characters (not bytes) */ -extern int ucs2_from_gsm8( bytes_t ucs2, cbytes_t src, int count ); - - -/** UCS2 to/from UTF8 - **/ - -/* convert a ucs2 string into a utf8 byte string, assumes 'utf8' NULL or properly sized. - returns the number of utf8 bytes*/ -extern int ucs2_to_utf8( cbytes_t ucs2, int ucs2len, bytes_t utf8 ); - -/* convert a utf8 byte string into a ucs2 string, assumes 'ucs2' NULL or properly sized. - returns the number of ucs2 chars */ -extern int utf8_to_ucs2( cbytes_t utf8, int utf8len, bytes_t ucs2 ); - -/* try to skip a given number of characters in a utf-8 byte string, return new position */ -extern cbytes_t utf8_skip( cbytes_t utf8, cbytes_t utf8end, int count); - -/** Dial Numbers: TON byte + 'count' bcd numbers - **/ - -/* convert a bcd-coded GSM dial number into an ASCII string (not zero-terminated) - assumes 'dst' is NULL or properly sized, returns 0 in case of success, -1 in case of error. - 'num_digits' is the number of digits, not input bytes. a trailing 0xf0 is ignored automatically - return the number of ASCII chars */ -extern int gsm_bcdnum_to_ascii ( cbytes_t bcd, int num_digits, bytes_t dst ); - -/* convert an ASCII dial-number into a bcd-coded string, returns the number of 4-bit nibbles written, */ -extern int gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst ); - -/** ADN: Abbreviated Dialing Numbers - **/ -#define SIM_ADN_MAX_ALPHA 20 /* maximum number of characters in ADN alpha tag */ -#define SIM_ADN_MAX_NUMBER 20 /* maximum digits in ADN number */ - -typedef struct { - byte_t alpha [ SIM_ADN_MAX_ALPHA*3+1 ]; /* alpha tag in zero-terminated utf-8 */ - char number[ SIM_ADN_MAX_NUMBER+1 ]; /* dialing number in zero-terminated ASCII */ -} -SimAdnRec, *SimAdn; - -typedef struct { - SimAdnRec adn; - byte_t ext_record; /* 0 or 0xFF means no extension */ -} -SimAdnRecordRec, *SimAdnRecord; - -extern int sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int datalen ); -extern int sim_adn_record_to_bytes ( SimAdnRecord rec, bytes_t data, int datalen ); - -/** ROPES - **/ - -typedef struct { - bytes_t data; - int max; - int pos; - int error; - unsigned char data0[16]; -} GsmRopeRec, *GsmRope; - -extern void gsm_rope_init( GsmRope rope ); -extern void gsm_rope_init_alloc( GsmRope rope, int alloc ); -extern int gsm_rope_done( GsmRope rope ); -extern bytes_t gsm_rope_done_acquire( GsmRope rope, int *psize ); -extern void gsm_rope_add_c( GsmRope rope, char c ); -extern void gsm_rope_add( GsmRope rope, const void* str, int len ); -extern void* gsm_rope_reserve( GsmRope rope, int len ); - -#endif /* _android_gsm_h */ diff --git a/telephony/modem_driver.c b/telephony/modem_driver.c deleted file mode 100644 index 99bbe6c..0000000 --- a/telephony/modem_driver.c +++ /dev/null @@ -1,148 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -/* implement the modem character device for Android within the QEMU event loop. - * it communicates through a serial port with "rild" (Radio Interface Layer Daemon) - * on the emulated device. - */ -#include "modem_driver.h" -#include "qemu-char.h" - -#define xxDEBUG - -#ifdef DEBUG -# include <stdio.h> -# define D(...) ( fprintf( stderr, __VA_ARGS__ ) ) -#else -# define D(...) ((void)0) -#endif - -AModem android_modem; -CharDriverState* android_modem_cs; - -typedef struct { - CharDriverState* cs; - AModem modem; - char in_buff[ 1024 ]; - int in_pos; - int in_sms; -} ModemDriver; - -/* send unsollicited messages to the device */ -static void -modem_driver_unsol( void* _md, const char* message) -{ - ModemDriver* md = _md; - int len = strlen(message); - - qemu_chr_write(md->cs, (const uint8_t*)message, len); -} - -static int -modem_driver_can_read( void* _md ) -{ - ModemDriver* md = _md; - int ret = sizeof(md->in_buff) - md->in_pos; - - return ret; -} - -/* despite its name, this function is called when the device writes to the modem */ -static void -modem_driver_read( void* _md, const uint8_t* src, int len ) -{ - ModemDriver* md = _md; - const uint8_t* end = src + len; - int nn; - - D( "%s: reading %d from %p bytes:", __FUNCTION__, len, src ); - for (nn = 0; nn < len; nn++) { - int c = src[nn]; - if (c >= 32 && c < 127) - D( "%c", c ); - else if (c == '\n') - D( "<LF>" ); - else if (c == '\r') - D( "<CR>" ); - else - D( "\\x%02x", c ); - } - D( "\n" ); - - for ( ; src < end; src++ ) { - char c = src[0]; - - if (md->in_sms) { - if (c != 26) - goto AppendChar; - - md->in_buff[ md->in_pos ] = c; - md->in_pos++; - md->in_sms = 0; - c = '\n'; - } - - if (c == '\n' || c == '\r') { - const char* answer; - - if (md->in_pos == 0) /* skip empty lines */ - continue; - - md->in_buff[ md->in_pos ] = 0; - md->in_pos = 0; - - D( "%s: << %s\n", __FUNCTION__, md->in_buff ); - answer = amodem_send(android_modem, md->in_buff); - if (answer != NULL) { - D( "%s: >> %s\n", __FUNCTION__, answer ); - len = strlen(answer); - if (len == 2 && answer[0] == '>' && answer[1] == ' ') - md->in_sms = 1; - - qemu_chr_write(md->cs, (const uint8_t*)answer, len); - qemu_chr_write(md->cs, (const uint8_t*)"\r", 1); - } else - D( "%s: -- NO ANSWER\n", __FUNCTION__ ); - - continue; - } - AppendChar: - md->in_buff[ md->in_pos++ ] = c; - if (md->in_pos == sizeof(md->in_buff)) { - /* input is too long !! */ - md->in_pos = 0; - } - } - D( "%s: done\n", __FUNCTION__ ); -} - - -static void -modem_driver_init( int base_port, ModemDriver* dm, CharDriverState* cs ) -{ - dm->cs = cs; - dm->in_pos = 0; - dm->in_sms = 0; - dm->modem = amodem_create( base_port, modem_driver_unsol, dm ); - - qemu_chr_add_handlers( cs, modem_driver_can_read, modem_driver_read, NULL, dm ); -} - - -void android_modem_init( int base_port ) -{ - static ModemDriver modem_driver[1]; - - if (android_modem_cs != NULL) { - modem_driver_init( base_port, modem_driver, android_modem_cs ); - android_modem = modem_driver->modem; - } -} diff --git a/telephony/modem_driver.h b/telephony/modem_driver.h deleted file mode 100644 index d03010f..0000000 --- a/telephony/modem_driver.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _modem_driver_h -#define _modem_driver_h - -#include "android_modem.h" -#include "qemu-common.h" - -/** in telephony/modem_driver.c */ -/* this is the internal character driver used to communicate with the - * emulated GSM modem. see qemu_chr_open() in vl.c */ -extern CharDriverState* android_modem_cs; - -/* the emulated GSM modem itself */ -extern AModem android_modem; - -/* must be called before the VM runs if there is a modem to emulate */ -extern void android_modem_init( int base_port ); - -#endif /* _modem_driver_h */ diff --git a/telephony/remote_call.c b/telephony/remote_call.c deleted file mode 100644 index 927e11d..0000000 --- a/telephony/remote_call.c +++ /dev/null @@ -1,430 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "remote_call.h" -#include "android/utils/bufprint.h" -#include "android/utils/debug.h" -#include "sysdeps.h" -#include "gsm.h" -#include "android/android.h" -#include "sockets.h" -#include <stdlib.h> - -#define DEBUG 1 - -#if 1 -# define D_ACTIVE VERBOSE_CHECK(modem) -#else -# define D_ACTIVE DEBUG -#endif - -#if 1 -# define S_ACTIVE VERBOSE_CHECK(socket) -#else -# define S_ACTIVE DEBUG -#endif - -#if DEBUG -# include <stdio.h> -# define D(...) do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0) -# define S(...) do { if (S_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0) -#else -# define D(...) ((void)0) -# define S(...) ((void)0) -#endif - -/** By convention, remote numbers are the console ports, i.e. 5554, 5556, etc... - **/ -#define REMOTE_NUMBER_BASE 5554 -#define REMOTE_NUMBER_MAX 16 -#define REMOTE_NUMBER_MAX_CHARS 4 -#define REMOTE_CONSOLE_PORT 5554 - -int -remote_number_from_port( int port ) -{ - if (port & 1) /* must be even */ - return -1; - - port = (port - REMOTE_CONSOLE_PORT) >> 1; - if ((unsigned)port >= REMOTE_NUMBER_MAX) - return -1; - - return REMOTE_NUMBER_BASE + port*2; -} - -int -remote_number_to_port( int number ) -{ - if (number & 1) /* must be even */ - return -1; - - number = (number - REMOTE_NUMBER_BASE) >> 1; - if ((unsigned)number >= REMOTE_NUMBER_MAX) - return -1; - - return REMOTE_CONSOLE_PORT + number*2; -} - -int -remote_number_string_to_port( const char* number ) -{ - char* end; - long num = strtol( number, &end, 10 ); - - if (end == NULL || *end || (int)num != num ) - return -1; - - return remote_number_to_port( (int)num ); -} - -/** REMOTE CALL OBJECTS - **/ - -typedef struct RemoteCallRec { - struct RemoteCallRec* next; - struct RemoteCallRec** pref; - RemoteCallType type; - int to_port; - int from_port; - SysChannel channel; - RemoteResultFunc result_func; - void* result_opaque; - - char quitting; - - /* the output buffer */ - char* buff; - int buff_pos; - int buff_len; - int buff_size; - char buff0[32]; - -} RemoteCallRec, *RemoteCall; - -static void -remote_call_done( RemoteCall call ) -{ - call->pref[0] = call->next; - call->next = NULL; - call->pref = &call->next; - - if (call->buff && call->buff != call->buff0) { - free(call->buff); - call->buff = call->buff0; - call->buff_size = (int) sizeof(call->buff0); - } - - if ( call->channel ) { - sys_channel_close( call->channel ); - call->channel = NULL; - } - - call->buff_pos = 0; - call->buff_len = 0; -} - - -static void -remote_call_free( RemoteCall call ) -{ - if (call) { - remote_call_done( call ); - free(call); - } -} - - -static void remote_call_event( void* opaque, int events ); /* forward */ - -static RemoteCall -remote_call_alloc( RemoteCallType type, int to_port, int from_port ) -{ - RemoteCall rcall = calloc( sizeof(*rcall), 1 ); - int from_num = remote_number_from_port(from_port); - - if (rcall != NULL) { - char *p, *end; - - rcall->pref = &rcall->next; - rcall->type = type; - rcall->to_port = to_port; - rcall->from_port = from_port; - rcall->buff = rcall->buff0; - rcall->buff_size = sizeof(rcall->buff0); - rcall->buff_pos = 0; - - p = rcall->buff; - end = p + rcall->buff_size; - - switch (type) { - case REMOTE_CALL_DIAL: - p = bufprint(p, end, "gsm call %d\n", from_num ); - break; - - case REMOTE_CALL_BUSY: - p = bufprint(p, end, "gsm busy %d\n", from_num); - break; - - case REMOTE_CALL_HOLD: - p = bufprint(p, end, "gsm hold %d\n", from_num); - break; - - case REMOTE_CALL_ACCEPT: - p = bufprint(p, end, "gsm accept %d\n", from_num); - break; - - case REMOTE_CALL_HANGUP: - p = bufprint(p, end, "gsm cancel %d\n", from_num ); - break; - - default: - ; - } - if (p >= end) { - D("%s: buffer too short\n", __FUNCTION__ ); - remote_call_free(rcall); - return NULL; - } - - rcall->buff_len = p - rcall->buff; - - rcall->channel = sys_channel_create_tcp_client( "localhost", to_port ); - if (rcall->channel == NULL) { - D("%s: could not create channel to port %d\n", __FUNCTION__, to_port); - remote_call_free(rcall); - return NULL; - } - - sys_channel_on( rcall->channel, SYS_EVENT_WRITE, remote_call_event, rcall ); - } - return rcall; -} - - -static int -remote_call_set_sms_pdu( RemoteCall call, - SmsPDU pdu ) -{ - char *p, *end; - int msg2len; - - msg2len = 32 + smspdu_to_hex( pdu, NULL, 0 ); - if (msg2len > call->buff_size) { - char* old_buff = call->buff == call->buff0 ? NULL : call->buff; - char* new_buff = realloc( old_buff, msg2len ); - if (new_buff == NULL) { - D("%s: not enough memory to alloc %d bytes", __FUNCTION__, msg2len); - return -1; - } - call->buff = new_buff; - call->buff_size = msg2len; - } - - p = call->buff; - end = p + call->buff_size; - - p = bufprint(p, end, "sms pdu "); - p += smspdu_to_hex( pdu, p, end-p ); - *p++ = '\n'; - *p = 0; - - call->buff_len = p - call->buff; - call->buff_pos = 0; - return 0; -} - - -static void -remote_call_add( RemoteCall call, - RemoteCall *plist ) -{ - RemoteCall first = *plist; - - call->next = first; - call->pref = plist; - - if (first) - first->pref = &call->next; -} - -static void -remote_call_event( void* opaque, int events ) -{ - RemoteCall call = opaque; - - S("%s: called for call (%d,%d), events=%02x\n", __FUNCTION__, - call->from_port, call->to_port, events); - - if (events & SYS_EVENT_READ) { - /* simply drain the channel */ - char temp[32]; - int n = sys_channel_read( call->channel, temp, sizeof(temp) ); - if (n <= 0) { - /* remote emulator probably quitted */ - //S("%s: emulator %d quitted with %d: %s\n", __FUNCTION__, call->to_port, errno, errno_str); - remote_call_free( call ); - return; - } - } - - if (events & SYS_EVENT_WRITE) { - int n; - - if (S_ACTIVE) { - int nn; - S("%s: call (%d,%d) sending %d bytes '", __FUNCTION__, - call->from_port, call->to_port, call->buff_len - call->buff_pos ); - for (nn = call->buff_pos; nn < call->buff_len; nn++) { - int c = call->buff[nn]; - if (c < 32) { - if (c == '\n') - S("\\n"); - else if (c == '\t') - S("\\t"); - else if (c == '\r') - S("\\r"); - else - S("\\x%02x", c); - } else - S("%c", c); - } - S("'\n"); - } - - n = sys_channel_write( call->channel, - call->buff + call->buff_pos, - call->buff_len - call->buff_pos ); - if (n <= 0) { - /* remote emulator probably quitted */ - S("%s: emulator %d quitted unexpectedly with error %d: %s\n", - __FUNCTION__, call->to_port, errno, errno_str); - if (call->result_func) - call->result_func( call->result_opaque, 0 ); - remote_call_free( call ); - return; - } - call->buff_pos += n; - - if (call->buff_pos >= call->buff_len) { - /* cool, we sent everything */ - S("%s: finished sending data to %d\n", __FUNCTION__, call->to_port); - if (!call->quitting) { - call->quitting = 1; - sprintf( call->buff, "quit\n" ); - call->buff_len = strlen(call->buff); - call->buff_pos = 0; - } else { - call->quitting = 0; - if (call->result_func) - call->result_func( call->result_opaque, 1 ); - - sys_channel_on( call->channel, SYS_EVENT_READ, remote_call_event, call ); - } - } - } -} - -static RemoteCall _the_remote_calls; - -#if 0 -static int -remote_from_number( const char* from ) -{ - char* end; - long num = strtol( from, &end, 10 ); - - if (end == NULL || *end) - return -1; - - if ((unsigned)(num - REMOTE_NUMBER_BASE) >= REMOTE_NUMBER_MAX) - return -1; - - return (int) num; -} -#endif - -static RemoteCall -remote_call_generic( RemoteCallType type, const char* to_number, int from_port ) -{ - int to_port = remote_number_string_to_port(to_number); - RemoteCall call; - - if ( remote_number_from_port(from_port) < 0 ) { - D("%s: from_port value %d is not valid", __FUNCTION__, from_port); - return NULL; - } - if ( to_port < 0 ) { - D("%s: phone number '%s' is not decimal or remote", __FUNCTION__, to_number); - return NULL; - } - if (to_port == from_port) { - D("%s: trying to call self\n", __FUNCTION__); - return NULL; - } - call = remote_call_alloc( type, to_port, from_port ); - if (call == NULL) { - return NULL; - } - remote_call_add( call, &_the_remote_calls ); - D("%s: adding new call from port %d to port %d\n", __FUNCTION__, from_port, to_port); - return call; -} - - -int -remote_call_dial( const char* number, - int from, - RemoteResultFunc result_func, - void* result_opaque ) -{ - RemoteCall call = remote_call_generic( REMOTE_CALL_DIAL, number, from ); - - if (call != NULL) { - call->result_func = result_func; - call->result_opaque = result_opaque; - } - return call ? 0 : -1; -} - - -void -remote_call_other( const char* to_number, int from_port, RemoteCallType type ) -{ - remote_call_generic( type, to_number, from_port ); -} - -/* call this function to send a SMS to a remote emulator */ -int -remote_call_sms( const char* number, - int from, - SmsPDU pdu ) -{ - RemoteCall call = remote_call_generic( REMOTE_CALL_SMS, number, from ); - - if (call == NULL) - return -1; - - if (call != NULL) { - if ( remote_call_set_sms_pdu( call, pdu ) < 0 ) { - remote_call_free(call); - return -1; - } - } - return call ? 0 : -1; -} - - -void -remote_call_cancel( const char* to_number, int from_port ) -{ - remote_call_generic( REMOTE_CALL_HANGUP, to_number, from_port ); -} diff --git a/telephony/remote_call.h b/telephony/remote_call.h deleted file mode 100644 index c6891b8..0000000 --- a/telephony/remote_call.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _REMOTE_CALL_H -#define _REMOTE_CALL_H - -#include "sms.h" - -/* convert a base console port into a remote phone number, -1 on error */ -extern int remote_number_from_port( int port ); - -/* convert a remote phone number into a remote console port, -1 on error */ -extern int remote_number_to_port( int number ); - -extern int remote_number_string_to_port( const char* number ); - -typedef void (*RemoteResultFunc)( void* opaque, int success ); - -typedef enum { - REMOTE_CALL_DIAL = 0, - REMOTE_CALL_BUSY, - REMOTE_CALL_HANGUP, - REMOTE_CALL_HOLD, - REMOTE_CALL_ACCEPT, - REMOTE_CALL_SMS -} RemoteCallType; - -/* call this function when you need to dial a remote voice call. - * this will try to connect to a remote emulator. the result function - * is called to indicate success or failure after some time. - * - * returns 0 if the number is to a remote phone, or -1 otherwise - */ -extern int remote_call_dial( const char* to_number, - int from_port, - RemoteResultFunc result_func, - void* result_opaque ); - -/* call this function to send a SMS to a remote emulator */ -extern int remote_call_sms( const char* number, int from_port, SmsPDU pdu ); - -/* call this function to indicate that you're busy to a remote caller */ -extern void remote_call_other( const char* to_number, int from_port, RemoteCallType type ); - -extern void remote_call_cancel( const char* to_number, int from_port ); - -#endif /* _REMOTE_CALL_H */ diff --git a/telephony/sim_card.c b/telephony/sim_card.c deleted file mode 100644 index a5a3249..0000000 --- a/telephony/sim_card.c +++ /dev/null @@ -1,439 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sim_card.h" -#include <string.h> -#include <assert.h> - -/* set ENABLE_DYNAMIC_RECORDS to 1 to enable dynamic records - * for now, this is an experimental feature that needs more testing - */ -#define ENABLE_DYNAMIC_RECORDS 0 - -#define A_SIM_PIN_SIZE 4 -#define A_SIM_PUK_SIZE 8 - -typedef struct ASimCardRec_ { - ASimStatus status; - char pin[ A_SIM_PIN_SIZE+1 ]; - char puk[ A_SIM_PUK_SIZE+1 ]; - int pin_retries; - - char out_buff[ 256 ]; - int out_size; - -} ASimCardRec; - -static ASimCardRec _s_card[1]; - -ASimCard -asimcard_create( void ) -{ - ASimCard card = _s_card; - card->status = A_SIM_STATUS_READY; - card->pin_retries = 0; - strncpy( card->pin, "0000", sizeof(card->pin) ); - strncpy( card->puk, "12345678", sizeof(card->puk) ); - return card; -} - -void -asimcard_destroy( ASimCard card ) -{ - /* nothing really */ - card=card; -} - -static __inline__ int -asimcard_ready( ASimCard card ) -{ - return card->status == A_SIM_STATUS_READY; -} - -ASimStatus -asimcard_get_status( ASimCard sim ) -{ - return sim->status; -} - -void -asimcard_set_status( ASimCard sim, ASimStatus status ) -{ - sim->status = status; -} - -const char* -asimcard_get_pin( ASimCard sim ) -{ - return sim->pin; -} - -const char* -asimcard_get_puk( ASimCard sim ) -{ - return sim->puk; -} - -void -asimcard_set_pin( ASimCard sim, const char* pin ) -{ - strncpy( sim->pin, pin, A_SIM_PIN_SIZE ); - sim->pin_retries = 0; -} - -void -asimcard_set_puk( ASimCard sim, const char* puk ) -{ - strncpy( sim->puk, puk, A_SIM_PUK_SIZE ); - sim->pin_retries = 0; -} - - -int -asimcard_check_pin( ASimCard sim, const char* pin ) -{ - if (sim->status != A_SIM_STATUS_PIN && - sim->status != A_SIM_STATUS_READY ) - return 0; - - if ( !strcmp( sim->pin, pin ) ) { - sim->status = A_SIM_STATUS_READY; - sim->pin_retries = 0; - return 1; - } - - if (sim->status != A_SIM_STATUS_READY) { - if (++sim->pin_retries == 3) - sim->status = A_SIM_STATUS_PUK; - } - return 0; -} - - -int -asimcard_check_puk( ASimCard sim, const char* puk, const char* pin ) -{ - if (sim->status != A_SIM_STATUS_PUK) - return 0; - - if ( !strcmp( sim->puk, puk ) ) { - strncpy( sim->puk, puk, A_SIM_PUK_SIZE ); - strncpy( sim->pin, pin, A_SIM_PIN_SIZE ); - sim->status = A_SIM_STATUS_READY; - sim->pin_retries = 0; - return 1; - } - - if ( ++sim->pin_retries == 6 ) { - sim->status = A_SIM_STATUS_ABSENT; - } - return 0; -} - -typedef enum { - SIM_FILE_DM = 0, - SIM_FILE_DF, - SIM_FILE_EF_DEDICATED, - SIM_FILE_EF_LINEAR, - SIM_FILE_EF_CYCLIC -} SimFileType; - -typedef enum { - SIM_FILE_READ_ONLY = (1 << 0), - SIM_FILE_NEED_PIN = (1 << 1), -} SimFileFlags; - -/* descriptor for a known SIM File */ -#define SIM_FILE_HEAD \ - SimFileType type; \ - unsigned short id; \ - unsigned short flags; - -typedef struct { - SIM_FILE_HEAD -} SimFileAnyRec, *SimFileAny; - -typedef struct { - SIM_FILE_HEAD - cbytes_t data; - int length; -} SimFileEFDedicatedRec, *SimFileEFDedicated; - -typedef struct { - SIM_FILE_HEAD - byte_t rec_count; - byte_t rec_len; - cbytes_t records; -} SimFileEFLinearRec, *SimFileEFLinear; - -typedef SimFileEFLinearRec SimFileEFCyclicRec; -typedef SimFileEFCyclicRec* SimFileEFCyclic; - -typedef union { - SimFileAnyRec any; - SimFileEFDedicatedRec dedicated; - SimFileEFLinearRec linear; - SimFileEFCyclicRec cyclic; -} SimFileRec, *SimFile; - - -#if ENABLE_DYNAMIC_RECORDS -/* convert a SIM File descriptor into an ASCII string, - assumes 'dst' is NULL or properly sized. - return the number of chars, or -1 on error */ -static int -sim_file_to_hex( SimFile file, bytes_t dst ) -{ - SimFileType type = file->any.type; - int result = 0; - - /* see 9.2.1 in TS 51.011 */ - switch (type) { - case SIM_FILE_EF_DEDICATED: - case SIM_FILE_EF_LINEAR: - case SIM_FILE_EF_CYCLIC: - { - if (dst) { - int file_size, perm; - - memcpy(dst, "0000", 4); /* bytes 1-2 are RFU */ - dst += 4; - - /* bytes 3-4 are the file size */ - if (type == SIM_FILE_EF_DEDICATED) - file_size = file->dedicated.length; - else - file_size = file->linear.rec_count * file->linear.rec_len; - - gsm_hex_from_short( dst, file_size ); - dst += 4; - - /* bytes 5-6 are the file id */ - gsm_hex_from_short( dst, file->any.id ); - dst += 4; - - /* byte 7 is the file type - always EF, i.e. 0x04 */ - dst[0] = '0'; - dst[1] = '4'; - dst += 2; - - /* byte 8 is RFU, except bit 7 for cyclic files, which indicates - that INCREASE is allowed. Since we don't support this yet... */ - dst[0] = '0'; - dst[1] = '0'; - dst += 2; - - /* byte 9-11 are access conditions */ - if (file->any.flags & SIM_FILE_READ_ONLY) { - if (file->any.flags & SIM_FILE_NEED_PIN) - perm = 0x1a; - else - perm = 0x0a; - } else { - if (file->any.flags & SIM_FILE_NEED_PIN) - perm = 0x11; - else - perm = 0x00; - } - gsm_hex_from_byte(dst, perm); - memcpy( dst+2, "a0aa", 4 ); - dst += 6; - - /* byte 12 is file status, we don't support invalidation */ - dst[0] = '0'; - dst[1] = '0'; - dst += 2; - - /* byte 13 is length of the following data, always 2 */ - dst[0] = '0'; - dst[1] = '2'; - dst += 2; - - /* byte 14 is struct of EF */ - dst[0] = '0'; - if (type == SIM_FILE_EF_DEDICATED) - dst[1] = '0'; - else if (type == SIM_FILE_EF_LINEAR) - dst[1] = '1'; - else - dst[1] = '3'; - - /* byte 15 is lenght of record, or 0 */ - if (type == SIM_FILE_EF_DEDICATED) { - dst[0] = '0'; - dst[1] = '0'; - } else - gsm_hex_from_byte( dst, file->linear.rec_len ); - } - result = 30; - } - break; - - default: - result = -1; - } - return result; -} - - -static const byte_t _const_spn_cphs[20] = { - 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -static const byte_t _const_voicemail_cphs[1] = { - 0x55 -}; - -static const byte_t _const_iccid[10] = { - 0x98, 0x10, 0x14, 0x30, 0x12, 0x11, 0x81, 0x15, 0x70, 0x02 -}; - -static const byte_t _const_cff_cphs[1] = { - 0x55 -}; - -static SimFileEFDedicatedRec _const_files_dedicated[] = -{ - { SIM_FILE_EF_DEDICATED, 0x6f14, SIM_FILE_READ_ONLY | SIM_FILE_NEED_PIN, - _const_spn_cphs, sizeof(_const_spn_cphs) }, - - { SIM_FILE_EF_DEDICATED, 0x6f11, SIM_FILE_NEED_PIN, - _const_voicemail_cphs, sizeof(_const_voicemail_cphs) }, - - { SIM_FILE_EF_DEDICATED, 0x2fe2, SIM_FILE_READ_ONLY, - _const_iccid, sizeof(_const_iccid) }, - - { SIM_FILE_EF_DEDICATED, 0x6f13, SIM_FILE_NEED_PIN, - _const_cff_cphs, sizeof(_const_cff_cphs) }, - - { 0, 0, 0, NULL, 0 } /* end of list */ -}; -#endif /* ENABLE_DYNAMIC_RECORDS */ - -const char* -asimcard_io( ASimCard sim, const char* cmd ) -{ - int nn; -#if ENABLE_DYNAMIC_RECORDS - int command, id, p1, p2, p3; -#endif - static const struct { const char* cmd; const char* answer; } answers[] = - { - { "+CRSM=192,28436,0,0,15", "+CRSM: 144,0,000000146f1404001aa0aa01020000" }, - { "+CRSM=176,28436,0,0,20", "+CRSM: 144,0,416e64726f6964ffffffffffffffffffffffffff" }, - - { "+CRSM=192,28433,0,0,15", "+CRSM: 144,0,000000016f11040011a0aa01020000" }, - { "+CRSM=176,28433,0,0,1", "+CRSM: 144,0,55" }, - - { "+CRSM=192,12258,0,0,15", "+CRSM: 144,0,0000000a2fe204000fa0aa01020000" }, - { "+CRSM=176,12258,0,0,10", "+CRSM: 144,0,98101430121181157002" }, - - { "+CRSM=192,28435,0,0,15", "+CRSM: 144,0,000000016f13040011a0aa01020000" }, - { "+CRSM=176,28435,0,0,1", "+CRSM: 144,0,55" }, - - { "+CRSM=192,28472,0,0,15", "+CRSM: 144,0,0000000f6f3804001aa0aa01020000" }, - { "+CRSM=176,28472,0,0,15", "+CRSM: 144,0,ff30ffff3c003c03000c0000f03f00" }, - - { "+CRSM=192,28617,0,0,15", "+CRSM: 144,0,000000086fc9040011a0aa01020104" }, - { "+CRSM=178,28617,1,4,4", "+CRSM: 144,0,01000000" }, - - { "+CRSM=192,28618,0,0,15", "+CRSM: 144,0,0000000a6fca040011a0aa01020105" }, - { "+CRSM=178,28618,1,4,5", "+CRSM: 144,0,0000000000" }, - - { "+CRSM=192,28589,0,0,15", "+CRSM: 144,0,000000046fad04000aa0aa01020000" }, - { "+CRSM=176,28589,0,0,4", "+CRSM: 144,0,00000003" }, - - { "+CRSM=192,28438,0,0,15", "+CRSM: 144,0,000000026f1604001aa0aa01020000" }, - { "+CRSM=176,28438,0,0,2", "+CRSM: 144,0,0233" }, - - { "+CRSM=192,28486,0,0,15", "+CRSM: 148,4" }, - { "+CRSM=192,28621,0,0,15", "+CRSM: 148,4" }, - - { "+CRSM=192,28613,0,0,15", "+CRSM: 144,0,000000f06fc504000aa0aa01020118" }, - { "+CRSM=178,28613,1,4,24", "+CRSM: 144,0,43058441aa890affffffffffffffffffffffffffffffffff" }, - - { "+CRSM=192,28480,0,0,15", "+CRSM: 144,0,000000806f40040011a0aa01020120" }, - { "+CRSM=178,28480,1,4,32", "+CRSM: 144,0,ffffffffffffffffffffffffffffffffffff07815155258131f5ffffffffffff" }, - - { "+CRSM=192,28615,0,0,15", "+CRSM: 144,0,000000406fc7040011a0aa01020120" }, - { "+CRSM=178,28615,1,4,32", "+CRSM: 144,0,566f6963656d61696cffffffffffffffffff07915155125740f9ffffffffffff" }, - - { NULL, NULL } - }; - - assert( memcmp( cmd, "+CRSM=", 6 ) == 0 ); - -#if ENABLE_DYNAMIC_RECORDS - if ( sscanf(cmd, "+CRSM=%d,%d,%d,%d,%d", &command, &id, &p1, &p2, &p3) == 5 ) { - switch (command) { - case A_SIM_CMD_GET_RESPONSE: - { - const SimFileEFDedicatedRec* file = _const_files_dedicated; - - assert(p1 == 0 && p2 == 0 && p3 == 15); - - for ( ; file->id != 0; file++ ) { - if (file->id == id) { - int count; - char* out = sim->out_buff; - strcpy( out, "+CRSM: 144,0," ); - out += strlen(out); - count = sim_file_to_hex( (SimFile) file, out ); - if (count < 0) - return "ERROR: INTERNAL SIM ERROR"; - out[count] = 0; - return sim->out_buff; - } - } - break; - } - - case A_SIM_CMD_READ_BINARY: - { - const SimFileEFDedicatedRec* file = _const_files_dedicated; - - assert(p1 == 0 && p2 == 0); - - for ( ; file->id != 0; file++ ) { - if (file->id == id) { - char* out = sim->out_buff; - - if (p3 > file->length) - return "ERROR: BINARY LENGTH IS TOO LONG"; - - strcpy( out, "+CRSM: 144,0," ); - out += strlen(out); - gsm_hex_from_bytes( out, file->data, p3 ); - out[p3*2] = 0; - return sim->out_buff; - } - } - break; - } - - case A_SIM_CMD_READ_RECORD: - break; - - default: - return "ERROR: UNSUPPORTED SIM COMMAND"; - } - } -#endif - - for (nn = 0; answers[nn].cmd != NULL; nn++) { - if ( !strcmp( answers[nn].cmd, cmd ) ) { - return answers[nn].answer; - } - } - return "ERROR: BAD COMMAND"; -} - diff --git a/telephony/sim_card.h b/telephony/sim_card.h deleted file mode 100644 index af78237..0000000 --- a/telephony/sim_card.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _android_sim_card_h -#define _android_sim_card_h - -#include "gsm.h" - -typedef struct ASimCardRec_* ASimCard; - -extern ASimCard asimcard_create( void ); -extern void asimcard_destroy( ASimCard sim ); - -typedef enum { - A_SIM_STATUS_ABSENT = 0, - A_SIM_STATUS_NOT_READY, - A_SIM_STATUS_READY, - A_SIM_STATUS_PIN, - A_SIM_STATUS_PUK, - A_SIM_STATUS_NETWORK_PERSONALIZATION -} ASimStatus; - -extern ASimStatus asimcard_get_status( ASimCard sim ); -extern void asimcard_set_status( ASimCard sim, ASimStatus status ); - -extern const char* asimcard_get_pin( ASimCard sim ); -extern const char* asimcard_get_puk( ASimCard sim ); -extern void asimcard_set_pin( ASimCard sim, const char* pin ); -extern void asimcard_set_puk( ASimCard sim, const char* puk ); - -extern int asimcard_check_pin( ASimCard sim, const char* pin ); -extern int asimcard_check_puk( ASimCard sim, const char* puk, const char* pin ); - -/* Restricted SIM Access command, as defined by 8.18 of 3GPP 27.007 */ -typedef enum { - A_SIM_CMD_READ_BINARY = 176, - A_SIM_CMD_READ_RECORD = 178, - A_SIM_CMD_GET_RESPONSE = 192, - A_SIM_CMD_UPDATE_BINARY = 214, - A_SIM_CMD_UPDATE_RECORD = 220, - A_SIM_CMD_STATUS = 242 -} ASimCommand; - -extern const char* asimcard_io( ASimCard sim, const char* cmd ); - -#endif /* _android_sim_card_h */ diff --git a/telephony/simulator.c b/telephony/simulator.c deleted file mode 100644 index 43f267a..0000000 --- a/telephony/simulator.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "android_modem.h" -#include "sysdeps.h" -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> - -#define DEFAULT_PORT 6703 - -static AModem modem; - -typedef struct { - SysChannel channel; - char in_buff[ 128 ]; - int in_pos; - - char out_buff[ 128 ]; - int out_pos; - int out_size; -} ClientRec, *Client; - -static Client -client_alloc( SysChannel channel ) -{ - Client client = calloc( sizeof(*client), 1 ); - - client->channel = channel; - return client; -} - -static void -client_free( Client client ) -{ - sys_channel_close( client->channel ); - client->channel = NULL; - free( client ); -} - -static void -client_append( Client client, const char* str, int len ); - -static void -dump_line( const char* line, const char* prefix ) -{ - if (prefix) - printf( "%s", prefix ); - - for ( ; *line; line++ ) { - int c = line[0]; - - if (c >= 32 && c < 127) - printf( "%c", c ); - else if (c == '\r') - printf( "<CR>" ); - else if (c == '\n') - printf( "<LF>" ); - else - printf( "\\x%02x", c ); - } - printf( "\n" ); -} - -static void -client_handle_line( Client client, const char* cmd ) -{ - const char* answer; - - dump_line( cmd, "<< " ); - answer = amodem_send( modem, cmd ); - if (answer == NULL) /* not an AT command, ignored */ { - printf( "-- NO ANSWER\n" ); - return; - } - - dump_line( answer, ">> " ); - client_append( client, answer, -1 ); - client_append( client, "\r", 1 ); -} - -static void -client_handler( void* _client, int events ) -{ - Client client = _client; - - if (events & SYS_EVENT_READ) { - int ret; - /* read into buffer, one character at a time */ - ret = sys_channel_read( client->channel, client->in_buff + client->in_pos, 1 ); - if (ret != 1) { - fprintf(stderr, "client %p could not read byte, result = %d, error: %s\n", - client, ret, strerror(errno) ); - goto ExitClient; - } - if (client->in_buff[client->in_pos] == '\r' || - client->in_buff[client->in_pos] == '\n' ) { - const char* cmd = client->in_buff; - client->in_buff[client->in_pos] = 0; - - if (client->in_pos > 0) { - client_handle_line( client, cmd ); - client->in_pos = 0; - } - } else - client->in_pos += 1; - } - - if (events & SYS_EVENT_WRITE) { - int ret; - /* write from output buffer, one char at a time */ - ret = sys_channel_write( client->channel, client->out_buff + client->out_pos, 1 ); - if (ret != 1) { - fprintf(stderr, "client %p could not write byte, result = %d, error: %s\n", - client, ret, strerror(errno) ); - goto ExitClient; - } - client->out_pos += 1; - if (client->out_pos == client->out_size) { - client->out_size = 0; - client->out_pos = 0; - /* we don't need to write */ - sys_channel_on( client->channel, SYS_EVENT_READ, client_handler, client ); - } - } - return; - -ExitClient: - printf( "client %p exiting\n", client ); - client_free( client ); -} - - -static void -client_append( Client client, const char* str, int len ) -{ - int avail; - - if (len < 0) - len = strlen(str); - - avail = sizeof(client->out_buff) - client->out_size; - if (len > avail) - len = avail; - - memcpy( client->out_buff + client->out_size, str, len ); - if (client->out_size == 0) { - sys_channel_on( client->channel, SYS_EVENT_READ | SYS_EVENT_WRITE, client_handler, client ); - } - client->out_size += len; -} - - -static void -accept_func( void* _server, int events ) -{ - SysChannel server = _server; - SysChannel handler; - Client client; - - printf( "connection accepted for server channel, getting handler socket\n" ); - handler = sys_channel_create_tcp_handler( server ); - client = client_alloc( handler ); - printf( "got one. created client %p\n", client ); - - events=events; - sys_channel_on( handler, SYS_EVENT_READ, client_handler, client ); -} - - -int main( void ) -{ - int port = DEFAULT_PORT; - SysChannel server; - - sys_main_init(); - modem = amodem_create( NULL, NULL ); - - server = sys_channel_create_tcp_server( port ); - printf( "GSM simulator listening on local port %d\n", port ); - - sys_channel_on( server, SYS_EVENT_READ, accept_func, server ); - sys_main_loop(); - printf( "GSM simulator exiting\n" ); - return 0; -} diff --git a/telephony/sms.c b/telephony/sms.c deleted file mode 100644 index 448eab4..0000000 --- a/telephony/sms.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sms.h" -#include "gsm.h" -#include <memory.h> -#include <stdlib.h> -#include <assert.h> - -#define DEBUG 1 - -#if 1 -# include "android/utils/debug.h" -# define D_ACTIVE VERBOSE_CHECK(modem) -#else -# define D_ACTIVE DEBUG -#endif - -#if DEBUG -# define D(...) VERBOSE_PRINT(modem,__VA_ARGS__) -#else -# define D(...) ((void)0) -#endif - -/* maximum number of data bytes in a SMS data message */ -#define MAX_USER_DATA_BYTES 140 - -/* maximum number of 7-bit septets in a SMS text message */ -#define MAX_USER_DATA_SEPTETS 160 - -/* size of the user data header in bytes */ -#define USER_DATA_HEADER_SIZE 6 - -/** MESSAGE TEXT - **/ -int -sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len ) -{ - cbytes_t p = (cbytes_t)str; - cbytes_t end = p + strlen; - int count = 0; - int escaped = 0; - - while (p < end) - { - int c = p[0]; - - /* read the value from the string */ - p += 1; - if (c >= 128) { - if ((c & 0xe0) == 0xc0) - c &= 0x1f; - else if ((c & 0xf0) == 0xe0) - c &= 0x0f; - else - c &= 0x07; - p++; - while (p < end && (p[0] & 0xc0) == 0x80) { - c = (c << 6) | (p[0] & 0x3f); - p++; - } - } - if (escaped) { - switch (c) { - case '\\': - break; - case 'n': /* \n is line feed */ - c = 10; - break; - - case 'x': /* \xNN, where NN is a 2-digit hexadecimal value */ - if (p+2 > end) - return -1; - c = gsm_hex2_to_byte( (const char*)p ); - if (c < 0) - return -1; - p += 2; - break; - - case 'u': /* \uNNNN where NNNN is a 4-digiti hexadecimal value */ - if (p + 4 > end) - return -1; - c = gsm_hex4_to_short( (const char*)p ); - if (c < 0) - return -1; - p += 4; - break; - - default: /* invalid escape, return -1 */ - return -1; - } - escaped = 0; - } - else if (c == '\\') - { - escaped = 1; - continue; - } - - /* now, try to write it to the destination */ - if (c < 128) { - if (count < utf8len) - utf8[count] = (byte_t) c; - count += 1; - } - else if (c < 0x800) { - if (count < utf8len) - utf8[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f)); - if (count+1 < utf8len) - utf8[count+1] = (byte_t)(0x80 | (c & 0x3f)); - count += 2; - } - else { - if (count < utf8len) - utf8[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf)); - if (count+1 < utf8len) - utf8[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f)); - if (count+2 < utf8len) - utf8[count+2] = (byte_t)(0x80 | (c & 0x3f)); - count += 3; - } - } - - if (escaped) /* bad final escape */ - return -1; - - return count; -} - -/* to convert utf-8 to a message string, we only need to deal with control characters - * and that's it */ -int sms_utf8_to_message_str( const unsigned char* utf8, int utf8len, char* str, int strlen ) -{ - cbytes_t p = utf8; - cbytes_t end = p + utf8len; - int count = 0; - - while (p < end) - { - int c = p[0]; - int escape = 0; - - /* read the value from the string */ - p += 1; - if (c >= 128) { - if ((c & 0xe0) == 0xc0) - c &= 0x1f; - else if ((c & 0xf0) == 0xe0) - c &= 0x0f; - else - c &= 0x07; - p++; - while (p < end && (p[0] & 0xc0) == 0x80) { - c = (c << 6) | (p[0] & 0x3f); - p++; - } - } - - if (c < ' ') { - escape = 1; - if (c == '\n') { - c = 'n'; - escape = 2; - } - } - else if (c == '\\') - escape = 2; - - switch (escape) { - case 0: - if (c < 128) { - if (count < strlen) - str[count] = (char) c; - count += 1; - } - else if (c < 0x800) { - if (count < strlen) - str[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f)); - if (count+1 < strlen) - str[count+1] = (byte_t)(0x80 | (c & 0x3f)); - count += 2; - } - else { - if (count < strlen) - str[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf)); - if (count+1 < strlen) - str[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f)); - if (count+2 < strlen) - str[count+2] = (byte_t)(0x80 | (c & 0x3f)); - count += 3; - } - break; - - case 1: - if (count+3 < strlen) { - str[count+0] = '\\'; - str[count+1] = 'x'; - gsm_hex_from_byte(str + count + 2, c); - } - count += 4; - break; - - default: - if (count+2 < strlen) { - str[count+0] = '\\'; - str[count+1] = (char) c; - } - count += 2; - } - } - return count; -} - - -/** TIMESTAMPS - **/ -void -sms_timestamp_now( SmsTimeStamp stamp ) -{ - time_t now_time = time(NULL); - struct tm gm = *(gmtime(&now_time)); - struct tm local = *(localtime(&now_time)); - int tzdiff = 0; - - stamp->data[0] = gsm_int_to_bcdi( local.tm_year % 100 ); - stamp->data[1] = gsm_int_to_bcdi( local.tm_mon+1 ); - stamp->data[2] = gsm_int_to_bcdi( local.tm_mday ); - stamp->data[3] = gsm_int_to_bcdi( local.tm_hour ); - stamp->data[4] = gsm_int_to_bcdi( local.tm_min ); - stamp->data[5] = gsm_int_to_bcdi( local.tm_sec ); - - tzdiff = (local.tm_hour*4 + local.tm_min/15) - (gm.tm_hour*4 + gm.tm_min/15); - if (local.tm_yday > gm.tm_yday) - tzdiff += 24*4; - else if (local.tm_yday < gm.tm_yday) - tzdiff -= 24*4; - - stamp->data[6] = gsm_int_to_bcdi( tzdiff >= 0 ? tzdiff : -tzdiff ); - if (tzdiff < 0) - stamp->data[6] |= 0x08; -} - -int -sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm ) -{ - int tzdiff; - - tm->tm_year = gsm_int_from_bcdi( stamp->data[0] ); - if (tm->tm_year < 50) - tm->tm_year += 100; - tm->tm_mon = gsm_int_from_bcdi( stamp->data[1] ) -1; - tm->tm_mday = gsm_int_from_bcdi( stamp->data[2] ); - tm->tm_hour = gsm_int_from_bcdi( stamp->data[3] ); - tm->tm_min = gsm_int_from_bcdi( stamp->data[4] ); - tm->tm_sec = gsm_int_from_bcdi( stamp->data[5] ); - - tm->tm_isdst = -1; - - tzdiff = gsm_int_from_bcdi( stamp->data[6] & 0xf7 ); - if (stamp->data[6] & 0x8) - tzdiff = -tzdiff; - - return tzdiff; -} - -static void -gsm_rope_add_timestamp( GsmRope rope, const SmsTimeStampRec* ts ) -{ - gsm_rope_add( rope, ts->data, 7 ); -} - - -/** SMS ADDRESSES - **/ - -int -sms_address_from_str( SmsAddress address, const char* src, int srclen ) -{ - const char* end = src + srclen; - int shift = 0, len = 0; - bytes_t data = address->data; - - address->len = 0; - address->toa = 0x81; - - if (src >= end) - return -1; - - if ( src[0] == '+' ) { - address->toa = 0x91; - if (++src == end) - goto Fail; - } - - memset( address->data, 0, sizeof(address->data) ); - - shift = 0; - - while (src < end) { - int c = *src++ - '0'; - - if ( (unsigned)c >= 10 || - data >= address->data + sizeof(address->data) ) - goto Fail; - - data[0] |= c << shift; - len += 1; - shift += 4; - if (shift == 8) { - shift = 0; - data += 1; - } - } - if (shift != 0) - data[0] |= 0xf0; - - address->len = len; - return 0; - -Fail: - return -1; -} - -int -sms_address_to_str( SmsAddress address, char* str, int strlen ) -{ - static const char dialdigits[16] = "0123456789*#,N%"; - int n, count = 0; - - if (address->toa == 0x91) { - if (count < strlen) - str[count] = '+'; - count++; - } - for (n = 0; n < address->len; n += 2) - { - int c = address->data[n/2]; - - if (count < strlen) - str[count] = dialdigits[c & 0xf]; - count += 1; - - if (n+1 > address->len) - break; - - if (count < strlen) - str[count] = dialdigits[(c >> 4) & 0xf]; - count += 1; - } - return count; -} - -int -sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen ) -{ - int len = sizeof(address->data), num_digits; - - if (buflen < 2) - return -1; - - address->len = num_digits = buf[0]; - address->toa = buf[1]; - - len = (num_digits+1)/2; - if ( len > sizeof(address->data) ) - return -1; - - memcpy( address->data, buf+2, len ); - return 0; -} - -int -sms_address_to_bytes( SmsAddress address, unsigned char* buf, int bufsize ) -{ - int len = (address->len + 1)/2 + 2; - - if (buf == NULL) - bufsize = 0; - - if (bufsize < 1) goto Exit; - buf[0] = address->len; - - if (bufsize < 2) goto Exit; - buf[1] = address->toa; - - buf += 2; - bufsize -= 2; - if (bufsize > len-2) - bufsize = len - 2; - - memcpy( buf, address->data, bufsize ); -Exit: - return len; -} - -int -sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen ) -{ - const char* hexend = hex + hexlen; - int nn, len, num_digits; - - if (hexlen < 4) - return -1; - - address->len = num_digits = gsm_hex2_to_byte( hex ); - address->toa = gsm_hex2_to_byte( hex+2 ); - hex += 4; - - len = (num_digits + 1)/2; - if (hex + len*2 > hexend) - return -1; - - for ( nn = 0; nn < len; nn++ ) - address->data[nn] = gsm_hex2_to_byte( hex + nn*2 ); - - return 0; -} - -int -sms_address_to_hex ( SmsAddress address, char* hex, int hexlen ) -{ - int len = (address->len + 1)/2 + 2; - int nn; - - if (hex == NULL) - hexlen = 0; - - if (hexlen < 2) goto Exit; - gsm_hex_from_byte( hex, address->len ); - if (hexlen < 4) goto Exit; - gsm_hex_from_byte( hex+2, address->toa ); - hex += 4; - hexlen -= 4; - if ( hexlen > 2*(len - 2) ) - hexlen = (len - 2)/2; - - for ( nn = 0; nn < hexlen; nn += 2 ) - gsm_hex_from_byte( hex+nn, address->data[nn/2] ); - -Exit: - return len*2; -} - -static void -gsm_rope_add_address( GsmRope rope, const SmsAddressRec* addr ) -{ - gsm_rope_add_c( rope, addr->len ); - gsm_rope_add_c( rope, addr->toa ); - gsm_rope_add( rope, addr->data, (addr->len+1)/2 ); - if (addr->len & 1) { - if (!rope->error && rope->data != NULL) - rope->data[ rope->pos-1 ] |= 0xf0; - } -} - -static int -sms_address_eq( const SmsAddressRec* addr1, const SmsAddressRec* addr2 ) -{ - if ( addr1->toa != addr2->toa || - addr1->len != addr2->len ) - return 0; - - return ( !memcmp( addr1->data, addr2->data, addr1->len ) ); -} - -/** SMS PARSER - **/ -static int -sms_get_byte( cbytes_t *pcur, cbytes_t end ) -{ - cbytes_t cur = *pcur; - int result = -1; - - if (cur < end) { - result = cur[0]; - *pcur = cur + 1; - } - return result; -} - -/* parse a service center address, returns -1 in case of error */ -static int -sms_get_sc_address( cbytes_t *pcur, - cbytes_t end, - SmsAddress address ) -{ - cbytes_t cur = *pcur; - int result = -1; - - if (cur < end) { - int len = cur[0]; - int dlen, adjust = 0; - - cur += 1; - - if (len == 0) { /* empty address */ - address->len = 0; - address->toa = 0x00; - result = 0; - goto Exit; - } - - if (cur + len > end) { - goto Exit; - } - - address->toa = *cur++; - len -= 1; - result = 0; - - for (dlen = 0; dlen < len; dlen+=1) - { - int c = cur[dlen]; - int v; - - adjust = 0; - if (dlen >= sizeof(address->data)) { - result = -1; - break; - } - - v = (c & 0xf); - if (v >= 0xe) - break; - - adjust = 1; - address->data[dlen] = (byte_t) c; - - v = (c >> 4) & 0xf; - if (v >= 0xe) { - break; - } - } - address->len = 2*dlen + adjust; - } -Exit: - if (!result) - *pcur = cur; - - return result; -} - -static int -sms_skip_sc_address( cbytes_t *pcur, - cbytes_t end ) -{ - cbytes_t cur = *pcur; - int result = -1; - int len; - - if (cur >= end) - goto Exit; - - len = cur[0]; - cur += 1 + len; - if (cur > end) - goto Exit; - - *pcur = cur; - result = 0; -Exit: - return result; -} - -/* parse a sender/receiver address, returns -1 in case of error */ -static int -sms_get_address( cbytes_t *pcur, - cbytes_t end, - SmsAddress address ) -{ - cbytes_t cur = *pcur; - int result = -1; - int len, dlen; - - if (cur >= end) - goto Exit; - - dlen = *cur++; - - if (dlen == 0) { - address->len = 0; - address->toa = 0; - result = 0; - goto Exit; - } - - if (cur + 1 + (dlen+1)/2 > end) - goto Exit; - - address->len = dlen; - address->toa = *cur++; - - len = (dlen + 1)/2; - if (len > sizeof(address->data)) - goto Exit; - - memcpy( address->data, cur, len ); - cur += len; - result = 0; - -Exit: - if (!result) - *pcur = cur; - - return result; -} - -static int -sms_skip_address( cbytes_t *pcur, - cbytes_t end ) -{ - cbytes_t cur = *pcur; - int result = -1; - int dlen; - - if (cur + 2 > end) - goto Exit; - - dlen = cur[0]; - cur += 2 + (dlen + 1)/2; - if (cur > end) - goto Exit; - - result = 0; -Exit: - return result; -} - -/* parse a service center timestamp */ -static int -sms_get_timestamp( cbytes_t *pcur, - cbytes_t end, - SmsTimeStamp ts ) -{ - cbytes_t cur = *pcur; - - if (cur + 7 > end) - return -1; - - memcpy( ts->data, cur, 7 ); - *pcur = cur + 7; - return 0; -} - -static int -sms_skip_timestamp( cbytes_t *pcur, - cbytes_t end ) -{ - cbytes_t cur = *pcur; - - if (cur + 7 > end) - return -1; - - *pcur = cur + 7; - return 0; -} - - -static int -sms_skip_validity_period( cbytes_t *pcur, - cbytes_t end, - int mtiByte ) -{ - cbytes_t cur = *pcur; - - switch ((mtiByte >> 3) & 3) { - case 1: /* relative format */ - cur += 1; - break; - - case 2: /* enhanced format */ - case 3: /* absolute format */ - cur += 7; - } - if (cur > end) - return -1; - - *pcur = cur; - return 0; -} - -/** SMS PDU - **/ - -typedef struct SmsPDURec { - bytes_t base; - bytes_t end; - bytes_t tpdu; -} SmsPDURec; - -void -smspdu_free( SmsPDU pdu ) -{ - if (pdu) { - free( pdu->base ); - pdu->base = NULL; - pdu->end = NULL; - pdu->tpdu = NULL; - } -} - -SmsPduType -smspdu_get_type( SmsPDU pdu ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte(&data, end); - - switch (mtiByte & 3) { - case 0: return SMS_PDU_DELIVER; - case 1: return SMS_PDU_SUBMIT; - case 2: return SMS_PDU_STATUS_REPORT; - default: return SMS_PDU_INVALID; - } -} - -int -smspdu_get_sender_address( SmsPDU pdu, SmsAddress address ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte(&data, end); - - switch (mtiByte & 3) { - case 0: /* SMS_PDU_DELIVER; */ - return sms_get_sc_address( &data, end, address ); - - default: return -1; - } -} - -int -smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp ts ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte( &data, end ); - - switch (mtiByte & 3) { - case 0: /* SMS_PDU_DELIVER */ - { - SmsAddressRec address; - - if ( sms_get_sc_address( &data, end, &address ) < 0 ) - return -1; - - data += 2; /* skip protocol identifer + coding scheme */ - - return sms_get_timestamp( &data, end, ts ); - } - - default: return -1; - } -} - -int -smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte( &data, end ); - - switch (mtiByte & 3) { - case 1: /* SMS_PDU_SUBMIT */ - { - data += 1; /* skip message reference */ - return sms_get_address( &data, end, address ); - } - - default: return -1; - } -} - -typedef enum { - SMS_CODING_SCHEME_UNKNOWN = 0, - SMS_CODING_SCHEME_GSM7, - SMS_CODING_SCHEME_UCS2 - -} SmsCodingScheme; - -/* see TS 23.038 Section 5 for details */ -static SmsCodingScheme -sms_get_coding_scheme( cbytes_t *pcur, - cbytes_t end ) -{ - cbytes_t cur = *pcur; - int dataCoding; - - if (cur >= end) - return SMS_CODING_SCHEME_UNKNOWN; - - dataCoding = *cur++; - *pcur = cur; - - switch (dataCoding >> 4) { - case 0x00: - case 0x02: - case 0x03: - return SMS_CODING_SCHEME_GSM7; - - case 0x01: - if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7; - if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2; - break; - - case 0x04: case 0x05: case 0x06: case 0x07: - if (dataCoding & 0x20) return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */ - if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7; - if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2; - break; - - case 0xF: - if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7; - break; - } - return SMS_CODING_SCHEME_UNKNOWN; -} - - -/* see TS 23.040 section 9.2.3.24 for details */ -static int -sms_get_text_utf8( cbytes_t *pcur, - cbytes_t end, - int hasUDH, - SmsCodingScheme coding, - GsmRope rope ) -{ - cbytes_t cur = *pcur; - int result = -1; - int len; - - if (cur >= end) - goto Exit; - - len = *cur++; - - /* skip user data header if any */ - if ( hasUDH ) - { - int hlen; - - if (cur >= end) - goto Exit; - - hlen = *cur++; - if (cur + hlen > end) - goto Exit; - - cur += hlen; - - if (coding == SMS_CODING_SCHEME_GSM7) - len -= 2*(hlen+1); - else - len -= hlen+1; - - if (len < 0) - goto Exit; - } - - /* switch the user data header if any */ - if (coding == SMS_CODING_SCHEME_GSM7) - { - int count = utf8_from_gsm7( cur, 0, len, NULL ); - - if (rope != NULL) - { - bytes_t dst = gsm_rope_reserve( rope, count ); - if (dst != NULL) - utf8_from_gsm7( cur, 0, len, dst ); - } - cur += (len+1)/2; - } - else if (coding == SMS_CODING_SCHEME_UCS2) - { - int count = ucs2_to_utf8( cur, len/2, NULL ); - - if (rope != NULL) - { - bytes_t dst = gsm_rope_reserve( rope, count ); - if (dst != NULL) - ucs2_to_utf8( cur, len/2, dst ); - } - cur += len; - } - result = 0; - -Exit: - if (!result) - *pcur = cur; - - return result; -} - -/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */ -/* or -1 in case of error */ -int -smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte( &data, end ); - - switch (mtiByte & 3) { - case 0: /* SMS_PDU_DELIVER */ - { - SmsAddressRec address; - SmsTimeStampRec timestamp; - SmsCodingScheme coding; - GsmRopeRec rope[1]; - int result; - - if ( sms_get_sc_address( &data, end, &address ) < 0 ) - goto Fail; - - data += 1; /* skip protocol identifier */ - coding = sms_get_coding_scheme( &data, end ); - if (coding == SMS_CODING_SCHEME_UNKNOWN) - goto Fail; - - if ( sms_get_timestamp( &data, end, ×tamp ) < 0 ) - goto Fail; - - if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) - goto Fail; - - result = rope->pos; - if (utf8len > result) - utf8len = result; - - if (utf8len > 0) - memcpy( utf8, rope->data, utf8len ); - - gsm_rope_done( rope ); - return result; - } - - case 1: /* SMS_PDU_SUBMIT */ - { - SmsAddressRec address; - SmsCodingScheme coding; - GsmRopeRec rope[1]; - int result; - - data += 1; /* message reference */ - - if ( sms_get_address( &data, end, &address ) < 0 ) - goto Fail; - - data += 1; /* skip protocol identifier */ - coding = sms_get_coding_scheme( &data, end ); - if (coding == SMS_CODING_SCHEME_UNKNOWN) - goto Fail; - - gsm_rope_init_alloc( rope, 0 ); - if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) { - gsm_rope_done( rope ); - goto Fail; - } - - result = rope->pos; - if (utf8len > result) - utf8len = result; - - if (utf8len > 0) - memcpy( utf8, rope->data, utf8len ); - - gsm_rope_done( rope ); - return result; - } - } -Fail: - return -1; -} - -static cbytes_t -smspdu_get_user_data_ref( SmsPDU pdu ) -{ - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte( &data, end ); - int len; - - /* if there is no user-data-header, there is no message reference here */ - if ((mtiByte & 0x40) == 0) - goto Fail; - - switch (mtiByte & 3) { - case 0: /* SMS_PDU_DELIVER */ - if ( sms_skip_address( &data, end ) < 0 ) - goto Fail; - - data += 2; /* skip protocol identifier + coding scheme */ - - if ( sms_skip_timestamp( &data, end ) < 0 ) - goto Fail; - - break; - - case 1: /* SMS_PDU_SUBMIT */ - data += 1; /* skip message reference */ - - if ( sms_skip_address( &data, end ) < 0 ) - goto Fail; - - data += 2; /* protocol identifier + oding schene */ - if ( sms_skip_validity_period( &data, end, mtiByte ) < 0 ) - goto Fail; - - break; - - default: - goto Fail; - } - - /* skip user-data length */ - if (data+1 >= end) - goto Fail; - - len = data[1]; - data += 2; - - while (len >= 2 && data + 2 <= end) { - int htype = data[0]; - int hlen = data[1]; - - if (htype == 00 && hlen == 3 && data + 5 <= end) { - return data + 2; - } - - data += hlen; - len -= hlen - 2; - } -Fail: - return NULL; -} - -int -smspdu_get_ref( SmsPDU pdu ) -{ - cbytes_t user_ref = smspdu_get_user_data_ref( pdu ); - - if (user_ref != NULL) - { - return user_ref[0]; - } - else - { - cbytes_t data = pdu->tpdu; - cbytes_t end = pdu->end; - int mtiByte = sms_get_byte( &data, end ); - - if ((mtiByte & 3) == 1) { - /* try to extract directly the reference for a SMS-SUBMIT */ - if (data < end) - return data[0]; - } - } - return -1; -} - -int -smspdu_get_max_index( SmsPDU pdu ) -{ - cbytes_t user_ref = smspdu_get_user_data_ref( pdu ); - - if (user_ref != NULL) { - return user_ref[1]; - } else { - return 1; - } -} - -int -smspdu_get_cur_index( SmsPDU pdu ) -{ - cbytes_t user_ref = smspdu_get_user_data_ref( pdu ); - - if (user_ref != NULL) { - return user_ref[2] - 1; - } else { - return 0; - } -} - - -static void -gsm_rope_add_sms_user_header( GsmRope rope, - int ref_number, - int pdu_count, - int pdu_index ) -{ - gsm_rope_add_c( rope, 0x05 ); /* total header length == 5 bytes */ - gsm_rope_add_c( rope, 0x00 ); /* element id: concatenated message reference number */ - gsm_rope_add_c( rope, 0x03 ); /* element len: 3 bytes */ - gsm_rope_add_c( rope, (byte_t)ref_number ); /* reference number */ - gsm_rope_add_c( rope, (byte_t)pdu_count ); /* max pdu index */ - gsm_rope_add_c( rope, (byte_t)pdu_index+1 ); /* current pdu index */ -} - -/* write a SMS-DELIVER PDU into a rope */ -static void -gsm_rope_add_sms_deliver_pdu( GsmRope rope, - cbytes_t utf8, - int utf8len, - int use_gsm7, - const SmsAddressRec* sender_address, - const SmsTimeStampRec* timestamp, - int ref_num, - int pdu_count, - int pdu_index) -{ - int coding; - int mtiByte = 0x20; /* message type - SMS DELIVER */ - - if (pdu_count > 1) - mtiByte |= 0x40; /* user data header indicator */ - - gsm_rope_add_c( rope, 0 ); /* no SC Address */ - gsm_rope_add_c( rope, mtiByte ); /* message type - SMS-DELIVER */ - gsm_rope_add_address( rope, sender_address ); - gsm_rope_add_c( rope, 0 ); /* protocol identifier */ - - /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */ - coding = (use_gsm7 ? 0x00 : 0x09); - - gsm_rope_add_c( rope, coding ); /* data coding scheme */ - gsm_rope_add_timestamp( rope, timestamp ); /* service center timestamp */ - - if (use_gsm7) { - bytes_t dst; - int count = utf8_to_gsm7( utf8, utf8len, NULL, 0 ); - int pad = 0; - - assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE ); - - if (pdu_count > 1) - { - int headerBits = 6*8; /* 6 is size of header in bytes */ - int headerSeptets = headerBits / 7; - if (headerBits % 7 > 0) - headerSeptets += 1; - - pad = headerSeptets*7 - headerBits; - - gsm_rope_add_c( rope, count + headerSeptets ); - gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index); - } - else - gsm_rope_add_c( rope, count ); - - count = (count*7+pad+7)/8; /* convert to byte count */ - - dst = gsm_rope_reserve( rope, count ); - if (dst != NULL) { - utf8_to_gsm7( utf8, utf8len, dst, pad ); - } - } else { - bytes_t dst; - int count = utf8_to_ucs2( utf8, utf8len, NULL ); - - assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE ); - - if (pdu_count > 1) - { - gsm_rope_add_c( rope, count*2 + 6 ); - gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index ); - } - else - gsm_rope_add_c( rope, count*2 ); - - gsm_rope_add_c( rope, count*2 ); - dst = gsm_rope_reserve( rope, count*2 ); - if (dst != NULL) { - utf8_to_ucs2( utf8, utf8len, dst ); - } - } -} - - -static SmsPDU -smspdu_create_deliver( cbytes_t utf8, - int utf8len, - int use_gsm7, - const SmsAddressRec* sender_address, - const SmsTimeStampRec* timestamp, - int ref_num, - int pdu_count, - int pdu_index ) -{ - SmsPDU p; - GsmRopeRec rope[1]; - int size; - - p = calloc( sizeof(*p), 1 ); - if (!p) goto Exit; - - gsm_rope_init( rope ); - gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7, - sender_address, timestamp, - ref_num, pdu_count, pdu_index); - if (rope->error) - goto Fail; - - gsm_rope_init_alloc( rope, rope->pos ); - - gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7, - sender_address, timestamp, - ref_num, pdu_count, pdu_index ); - - p->base = gsm_rope_done_acquire( rope, &size ); - if (p->base == NULL) - goto Fail; - - p->end = p->base + size; - p->tpdu = p->base + 1; -Exit: - return p; - -Fail: - free(p); - return NULL; -} - - -void -smspdu_free_list( SmsPDU* pdus ) -{ - if (pdus) { - int nn; - for (nn = 0; pdus[nn] != NULL; nn++) - smspdu_free( pdus[nn] ); - - free( pdus ); - } -} - - - -SmsPDU* -smspdu_create_deliver_utf8( const unsigned char* utf8, - int utf8len, - const SmsAddressRec* sender_address, - const SmsTimeStampRec* timestamp ) -{ - SmsTimeStampRec ts0; - int use_gsm7; - int count, block; - int num_pdus = 0; - int leftover = 0; - SmsPDU* list = NULL; - - static unsigned char ref_num = 0; - - if (timestamp == NULL) { - sms_timestamp_now( &ts0 ); - timestamp = &ts0; - } - - /* can we encode the message with the GSM 7-bit alphabet ? */ - use_gsm7 = utf8_check_gsm7( utf8, utf8len ); - - /* count the number of SMS PDUs we'll need */ - block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE; - - if (use_gsm7) { - count = utf8_to_gsm7( utf8, utf8len, NULL, 0 ); - } else { - count = utf8_to_ucs2( utf8, utf8len, NULL ); - block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE; - } - - num_pdus = count / block; - leftover = count - num_pdus*block; - if (leftover > 0) - num_pdus += 1; - - list = calloc( sizeof(SmsPDU*), num_pdus + 1 ); - if (list == NULL) - return NULL; - - /* now create each SMS PDU */ - { - cbytes_t src = utf8; - cbytes_t src_end = utf8 + utf8len; - int nn; - - for (nn = 0; nn < num_pdus; nn++) - { - int skip = block; - cbytes_t src_next; - - if (leftover > 0 && nn == num_pdus-1) - skip = leftover; - - src_next = utf8_skip_gsm7( src, src_end, skip ); - - list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp, - ref_num, num_pdus, nn ); - if (list[nn] == NULL) - goto Fail; - - src = src_next; - } - } - - ref_num++; - return list; - -Fail: - smspdu_free_list(list); - return NULL; -} - - -SmsPDU -smspdu_create_from_hex( const char* hex, int hexlen ) -{ - SmsPDU p; - cbytes_t data; - - p = calloc( sizeof(*p), 1 ); - if (!p) goto Exit; - - p->base = malloc( (hexlen+1)/2 ); - if (p->base == NULL) { - free(p); - p = NULL; - goto Exit; - } - - if ( gsm_hex_to_bytes( (cbytes_t)hex, hexlen, p->base ) < 0 ) - goto Fail; - - p->end = p->base + (hexlen+1)/2; - - data = p->base; - if ( sms_skip_sc_address( &data, p->end ) < 0 ) - goto Fail; - - p->tpdu = (bytes_t) data; - -Exit: - return p; - -Fail: - free(p->base); - free(p); - return NULL; -} - -int -smspdu_to_hex( SmsPDU pdu, char* hex, int hexlen ) -{ - int result = (pdu->end - pdu->base)*2; - int nn; - - if (hexlen > result) - hexlen = result; - - for (nn = 0; nn*2 < hexlen; nn++) { - gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] ); - } - return result; -} - - -/** SMS SUBMIT RECEIVER - ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver - **/ - -typedef struct SmsFragmentRec { - struct SmsFragmentRec* next; - SmsAddressRec from[1]; - byte_t ref; - byte_t max; - byte_t count; - int index; - SmsPDU* pdus; - -} SmsFragmentRec, *SmsFragment; - - -typedef struct SmsReceiverRec { - int last; - SmsFragment fragments; - -} SmsReceiverRec; - - -static void -sms_fragment_free( SmsFragment frag ) -{ - int nn; - - for (nn = 0; nn < frag->max; nn++) { - if (frag->pdus[nn] != NULL) { - smspdu_free( frag->pdus[nn] ); - frag->pdus[nn] = NULL; - } - } - frag->pdus = NULL; - frag->count = 0; - frag->max = 0; - frag->index = 0; - free( frag ); -} - -static SmsFragment -sms_fragment_alloc( SmsReceiver rec, const SmsAddressRec* from, int ref, int max ) -{ - SmsFragment frag = calloc(sizeof(*frag) + max*sizeof(SmsPDU), 1 ); - - if (frag != NULL) { - frag->from[0] = from[0]; - frag->ref = ref; - frag->max = max; - frag->pdus = (SmsPDU*)(frag + 1); - frag->index = ++rec->last; - } - return frag; -} - - - -SmsReceiver sms_receiver_create( void ) -{ - SmsReceiver rec = calloc(sizeof(*rec),1); - return rec; -} - -void -sms_receiver_destroy( SmsReceiver rec ) -{ - while (rec->fragments) { - SmsFragment frag = rec->fragments; - rec->fragments = frag->next; - sms_fragment_free(frag); - } -} - -static SmsFragment* -sms_receiver_find_p( SmsReceiver rec, const SmsAddressRec* from, int ref ) -{ - SmsFragment* pnode = &rec->fragments; - SmsFragment node; - - for (;;) { - node = *pnode; - if (node == NULL) - break; - if (node->ref == ref && sms_address_eq( node->from, from )) - break; - pnode = &node->next; - } - return pnode; -} - -static SmsFragment* -sms_receiver_find_index_p( SmsReceiver rec, int index ) -{ - SmsFragment* pnode = &rec->fragments; - SmsFragment node; - - for (;;) { - node = *pnode; - if (node == NULL) - break; - if (node->index == index) - break; - pnode = &node->next; - } - return pnode; -} - -int -sms_receiver_add_submit_pdu( SmsReceiver rec, SmsPDU submit_pdu ) -{ - SmsAddressRec from[1]; - int ref, max, cur; - SmsFragment* pnode; - SmsFragment frag; - - if ( smspdu_get_receiver_address( submit_pdu, from ) < 0 ) { - D( "%s: could not extract receiver address\n", __FUNCTION__ ); - return -1; - } - - ref = smspdu_get_ref( submit_pdu ); - if (ref < 0) { - D( "%s: could not extract message reference from pdu\n", __FUNCTION__ ); - return -1; - } - max = smspdu_get_max_index( submit_pdu ); - if (max < 0) { - D( "%s: invalid max fragment value: %d should be >= 1\n", - __FUNCTION__, max ); - return -1; - } - pnode = sms_receiver_find_p( rec, from, ref ); - frag = *pnode; - if (frag == NULL) { - frag = sms_fragment_alloc( rec, from, ref, max ); - if (frag == NULL) { - D("%s: not enough memory to allocate new fragment\n", __FUNCTION__ ); - return -1; - } - if (D_ACTIVE) { - char tmp[32]; - int len; - - len = sms_address_to_str( from, tmp, sizeof(tmp) ); - if (len < 0) { - strcpy( tmp, "<unknown>" ); - len = strlen(tmp); - } - D("%s: created SMS index %d, from %.*s, ref %d, max %d\n", __FUNCTION__, - frag->index, len, tmp, frag->ref, frag->max); - } - *pnode = frag; - } - - cur = smspdu_get_cur_index( submit_pdu ); - if (cur < 0) { - D("%s: SMS fragment index is too small: %d should be >= 1\n", __FUNCTION__, cur+1 ); - return -1; - } - if (cur >= max) { - D("%s: SMS fragment index is too large (%d >= %d)\n", __FUNCTION__, cur, max); - return -1; - } - if ( frag->pdus[cur] != NULL ) { - D("%s: receiving duplicate SMS fragment for %d/%d, ref=%d, discarding old one\n", - __FUNCTION__, cur+1, max, ref); - smspdu_free( frag->pdus[cur] ); - frag->count -= 1; - } - frag->pdus[cur] = submit_pdu; - frag->count += 1; - - if (frag->count >= frag->max) { - /* yes, we received all fragments for this SMS */ - D( "%s: SMS index %d, received all %d fragments\n", __FUNCTION__, frag->index, frag->count ); - return frag->index; - } - else { - /* still waiting for more */ - D( "%s: SMS index %d, received %d/%d, waiting for %d more\n", __FUNCTION__, - frag->index, cur+1, max, frag->max - frag->count ); - return 0; - } -} - - -int -sms_receiver_get_text_message( SmsReceiver rec, int index, bytes_t utf8, int utf8len ) -{ - SmsFragment* pnode = sms_receiver_find_index_p( rec, index ); - SmsFragment frag = *pnode; - int nn, total; - - if (frag == NULL) { - D( "%s: invalid SMS index %d\n", __FUNCTION__, index ); - return -1; - } - if (frag->count != frag->max) { - D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__, - frag->index, frag->max - frag->count ); - return -1; - } - /* get the size of all combined text */ - total = 0; - for ( nn = 0; nn < frag->count; nn++ ) { - int partial; - if (utf8 && utf8len > 0) { - partial = smspdu_get_text_message( frag->pdus[nn], utf8, utf8len ); - utf8 += partial; - utf8len -= partial; - } else { - partial = smspdu_get_text_message( frag->pdus[nn], NULL, 0 ); - } - total += partial; - } - return total; -} - - -static void -sms_receiver_remove( SmsReceiver rec, int index ) -{ - SmsFragment* pnode = sms_receiver_find_index_p( rec, index ); - SmsFragment frag = *pnode; - if (frag != NULL) { - *pnode = frag->next; - sms_fragment_free(frag); - } -} - - -SmsPDU* -sms_receiver_create_deliver( SmsReceiver rec, int index, const SmsAddressRec* from ) -{ - SmsPDU* result = NULL; - SmsFragment* pnode = sms_receiver_find_index_p( rec, index ); - SmsFragment frag = *pnode; - SmsTimeStampRec now[1]; - int nn, total; - bytes_t utf8; - int utf8len; - - if (frag == NULL) { - D( "%s: invalid SMS index %d\n", __FUNCTION__, index ); - return NULL; - } - if (frag->count != frag->max) { - D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__, - frag->index, frag->max - frag->count ); - return NULL; - } - - /* get the combined text message */ - utf8len = sms_receiver_get_text_message( rec, index, NULL, 0 ); - if (utf8len < 0) - goto Exit; - - utf8 = malloc( utf8len + 1 ); - if (utf8 == NULL) { - D( "%s: not enough memory to allocate %d bytes\n", - __FUNCTION__, utf8len+1 ); - goto Exit; - } - - total = 0; - for ( nn = 0; nn < frag->count; nn++ ) { - total += smspdu_get_text_message( frag->pdus[nn], utf8 + total, utf8len - total ); - } - - sms_timestamp_now( now ); - - result = smspdu_create_deliver_utf8( utf8, utf8len, from, now ); - - free(utf8); - -Exit: - sms_receiver_remove( rec, index ); - return result; -} - diff --git a/telephony/sms.h b/telephony/sms.h deleted file mode 100644 index 7059ee3..0000000 --- a/telephony/sms.h +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _android_sms_h -#define _android_sms_h - -#include <time.h> - -/** MESSAGE TEXT - **/ -/* convert a quoted message text into a utf8 string. Note: you can use 'str' as the destination buffer - * with the current implementation. always return the number of utf8 bytes corresponding to the original - * message string, even if utf8 is NULL and utf8len is 0 - */ -extern int sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len ); - -/* the equivalent in the opposite direction - */ -extern int sms_utf8_to_message_str( const unsigned char* utf8, int utf8len, char* str, int strlen ); - -/** TIMESTAMPS - **/ - -/* An SMS timestamp structure */ -typedef struct { - unsigned char data[7]; -} SmsTimeStampRec, *SmsTimeStamp; - -extern void sms_timestamp_now( SmsTimeStamp stamp ); -extern int sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm ); - -/** SMS ADDRESSES - **/ - -#define SMS_ADDRESS_MAX_SIZE 16 - -typedef struct { - unsigned char len; - unsigned char toa; - unsigned char data[ SMS_ADDRESS_MAX_SIZE ]; -} SmsAddressRec, *SmsAddress; - -extern int sms_address_from_str( SmsAddress address, const char* src, int srclen ); -extern int sms_address_to_str( SmsAddress address, char* src, int srclen ); - -extern int sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen ); -extern int sms_address_to_bytes ( SmsAddress address, unsigned char* buf, int bufsize ); -extern int sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen ); -extern int sms_address_to_hex ( SmsAddress address, char* hex, int hexsize ); - -/** SMS PROTOCOL DATA UNITS - **/ - -typedef struct SmsPDURec* SmsPDU; - -extern SmsPDU* smspdu_create_deliver_utf8( const unsigned char* utf8, - int utf8len, - const SmsAddressRec* sender_address, - const SmsTimeStampRec* timestamp ); - -extern void smspdu_free_list( SmsPDU* pdus ); - -extern SmsPDU smspdu_create_from_hex( const char* hex, int hexlen ); - -extern int smspdu_to_hex( SmsPDU pdu, char* hex, int hexsize ); - -/* free a given SMS PDU */ -extern void smspdu_free( SmsPDU pdu ); - -typedef enum { - SMS_PDU_INVALID = 0, - SMS_PDU_DELIVER, - SMS_PDU_SUBMIT, - SMS_PDU_STATUS_REPORT -} SmsPduType; - -extern SmsPduType smspdu_get_type( SmsPDU pdu ); - -/* retrieve the sender address of a SMS-DELIVER pdu, returns -1 otherwise */ -extern int smspdu_get_sender_address( SmsPDU pdu, SmsAddress address ); - -/* retrieve the service center timestamp of a SMS-DELIVER pdu, return -1 otherwise */ -extern int smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp timestamp ); - -/* retrieve the receiver address of a SMS-SUBMIT pdu, return -1 otherwise */ -extern int smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address ); - -extern int smspdu_get_ref ( SmsPDU pdu ); -extern int smspdu_get_max_index( SmsPDU pdu ); -extern int smspdu_get_cur_index( SmsPDU pdu ); - -/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */ -/* or -1 in case of error */ -extern int smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len ); - -/** SMS SUBMIT RECEIVER - ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver - **/ - -typedef struct SmsReceiverRec *SmsReceiver; - -extern SmsReceiver sms_receiver_create( void ); -extern void sms_receiver_destroy( SmsReceiver rec ); - -extern int sms_receiver_add_submit_pdu( SmsReceiver rec, SmsPDU submit_pdu ); -extern int sms_receiver_get_text_message( SmsReceiver rec, int index, unsigned char* utf8, int utf8len ); -extern SmsPDU* sms_receiver_create_deliver( SmsReceiver rec, int index, const SmsAddressRec* from ); - -#endif /* _android_sms_h */ diff --git a/telephony/sysdeps.h b/telephony/sysdeps.h deleted file mode 100644 index 19ca8d3..0000000 --- a/telephony/sysdeps.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef __sysdeps_h__ -#define __sysdeps_h__ - -/* system-dependent platform abstraction used by the emulated GSM modem - */ - -/* to be called before anything else */ - -extern void sys_main_init( void ); - -/** callbacks - **/ -typedef void (*SysCallback)( void* opaque ); - -/** events - **/ -enum { - SYS_EVENT_READ = 0x01, - SYS_EVENT_WRITE = 0x02, - SYS_EVENT_ERROR = 0x04, - SYS_EVENT_ALL = 0x07 -}; - -/** channels - **/ -typedef struct SysChannelRec_* SysChannel; - -typedef void (*SysChannelCallback)( void* opaque, int event_flags ); - -/* XXX: TODO: channel creation functions */ -extern SysChannel sys_channel_create_tcp_server( int port ); -extern SysChannel sys_channel_create_tcp_handler( SysChannel server_channel ); -extern SysChannel sys_channel_create_tcp_client( const char* hostname, int port ); -extern int sys_channel_set_non_block( SysChannel channel ); - -extern void sys_channel_on( SysChannel channel, - int event_flags, - SysChannelCallback event_callback, - void* event_opaqe ); - -extern int sys_channel_read( SysChannel channel, void* buffer, int size ); - -extern int sys_channel_write( SysChannel channel, const void* buffer, int size ); - -extern void sys_channel_close( SysChannel channel ); - - -/** time measurement - **/ -typedef long long SysTime; - -extern SysTime sys_time_now( void ); - -/** timers - **/ -typedef struct SysTimerRec_* SysTimer; - -extern SysTimer sys_timer_create( void ); -extern void sys_timer_set( SysTimer timer, SysTime when, SysCallback callback, void* opaque ); -extern void sys_timer_unset( SysTimer timer ); -extern void sys_timer_destroy( SysTimer timer ); - -extern long long sys_time_ms( void ); - -/** main loop (may return immediately on some platform) - **/ -extern int sys_main_loop( void ); - -#endif /* __sysdeps_h__ */ diff --git a/telephony/sysdeps_posix.c b/telephony/sysdeps_posix.c deleted file mode 100644 index 8c5eb12..0000000 --- a/telephony/sysdeps_posix.c +++ /dev/null @@ -1,645 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sysdeps.h" -#include <assert.h> -#include <unistd.h> -#include <sys/select.h> -#include <errno.h> -#include <memory.h> -#include <stdio.h> -#ifndef HAVE_WINSOCK -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <netdb.h> -#endif - -/** QUEUE - **/ -#define SYS_MAX_QUEUE 16 - -typedef struct { - int start; - int end; - void* pending[ SYS_MAX_QUEUE ]; -} -SysQueueRec, *SysQueue; - -static void -sys_queue_reset( SysQueue queue ) -{ - queue->start = queue->end = 0; -} - -static void -sys_queue_add( SysQueue queue, void* item ) -{ - assert( queue->end - queue->start < SYS_MAX_QUEUE ); - assert( queue->start == 0 ); - assert( item != NULL ); - queue->pending[ queue->end++ ] = item; -} - -#if 0 -static void -sys_queue_remove( SysQueue queue, void* item ) -{ - int nn, count; - assert( queue->end > queue->start ); - assert( item != NULL ); - count = queue->end - queue->start; - for ( nn = queue->start; count > 0; ++nn, --count ) { - if ( queue->pending[nn] == item ) { - queue->pending[nn] = queue->pending[nn+count-1]; - queue->end -= 1; - break; - } - } - assert( 0 && "sys_queue_remove: item not found" ); -} -#endif - -static void* -sys_queue_get( SysQueue queue ) -{ - if (queue->end > queue->start) { - return queue->pending[ queue->start++ ]; - } - return NULL; -} - -/** CHANNELS - **/ -typedef struct SysChannelRec_ { - SysChannel next; - int fd; - char active; - char pending; - char closed; - int wanted; - int ready; - SysChannelCallback callback; - void* opaque; -} SysChannelRec; - - -/*** channel allocation ***/ -#define SYS_EVENT_MAX 3 -#define SYS_MAX_CHANNELS 16 - -static SysChannelRec _s_channels0[ SYS_MAX_CHANNELS ]; -static SysChannel _s_free_channels; - -static SysChannel -sys_channel_alloc( void ) -{ - SysChannel channel = _s_free_channels; - assert( channel != NULL && "out of free channels" ); - _s_free_channels = channel->next; - channel->next = NULL; - channel->active = 0; - channel->closed = 0; - channel->pending = 0; - channel->wanted = 0; - return channel; -} - -static void -sys_channel_free( SysChannel channel ) -{ - if (channel->fd >= 0) { -#ifdef _WIN32 - shutdown( channel->fd, SD_BOTH ); -#else - shutdown( channel->fd, SHUT_RDWR ); -#endif - close(channel->fd); - channel->fd = -1; - } - channel->wanted = 0; - channel->ready = 0; - channel->callback = NULL; - - channel->next = _s_free_channels; - _s_free_channels = channel; -} - - -/* list of active channels */ -static SysChannel _s_channels; - -/* used by select to wait on channel events */ -static fd_set _s_fdsets[SYS_EVENT_MAX]; -static int _s_maxfd; - -static void -sys_channel_deactivate( SysChannel channel ) -{ - assert( channel->active != 0 ); - SysChannel *pnode = &_s_channels; - for (;;) { - SysChannel node = *pnode; - assert( node != NULL ); - if (node == channel) - break; - pnode = &node->next; - } - *pnode = channel->next; - channel->next = NULL; - channel->active = 0; -} - -static void -sys_channel_activate( SysChannel channel ) -{ - assert( channel->active == 0 ); - channel->next = _s_channels; - _s_channels = channel; - channel->active = 1; - if (channel->fd > _s_maxfd) - _s_maxfd = channel->fd; -} - - -/* queue of pending channels */ -static SysQueueRec _s_pending_channels[1]; - - -static void -sys_init_channels( void ) -{ - int nn; - - for (nn = 0; nn < SYS_MAX_CHANNELS-1; nn++) - _s_channels0[nn].next = &_s_channels0[nn+1]; - _s_free_channels = &_s_channels0[0]; - - for (nn = 0; nn < SYS_EVENT_MAX; nn++) - FD_ZERO( &_s_fdsets[nn] ); - - _s_maxfd = -1; - - sys_queue_reset( _s_pending_channels ); -} - - -void -sys_channel_on( SysChannel channel, - int events, - SysChannelCallback callback, - void* opaque ) -{ - int adds = events & ~channel->wanted; - int removes = channel->wanted & ~events; - - channel->wanted = events; - channel->callback = callback; - channel->opaque = opaque; - - /* update global fdsets */ - if (adds) { - int ee; - for (ee = 0; ee < SYS_EVENT_MAX; ee++) - if (adds & (1 << ee)) - FD_SET( channel->fd, &_s_fdsets[ee] ); - } - if (removes) { - int ee; - for (ee = 0; ee < SYS_EVENT_MAX; ee++) - if (removes & (1 << ee)) - FD_CLR( channel->fd, &_s_fdsets[ee] ); - } - if (events && !channel->active) { - sys_channel_activate( channel ); - } - else if (!events && channel->active) { - sys_channel_deactivate( channel ); - } -} - -int -sys_channel_read( SysChannel channel, void* buffer, int size ) -{ - char* buff = buffer; - int count = 0; - - assert( !channel->closed ); - - while (size > 0) { - int len = read(channel->fd, buff, size); - if (len < 0) { - if (errno == EINTR) - continue; - if (count == 0) - count = -1; - break; - } - buff += len; - size -= len; - count += len; - } - return count; -} - - -int -sys_channel_write( SysChannel channel, const void* buffer, int size ) -{ - const char* buff = buffer; - int count = 0; - - assert( !channel->closed ); - - while (size > 0) { - int len = write(channel->fd, buff, size); - if (len < 0) { - if (errno == EINTR) - continue; - if (count == 0) - count = -1; - break; - } - buff += len; - size -= len; - count += len; - } - return count; -} - - -void -sys_channel_close( SysChannel channel ) -{ - if (channel->active) { - sys_channel_on( channel, 0, NULL, NULL ); - } - - if (channel->pending) { - /* we can't free the channel right now because it */ - /* is in the pending list, set a flag */ - channel->closed = 1; - return; - } - - if (!channel->closed) { - channel->closed = 1; - } - - sys_channel_free( channel ); -} - -/** time measurement - **/ -SysTime sys_time_ms( void ) -{ - struct timeval tv; - gettimeofday( &tv, NULL ); - return (SysTime)(tv.tv_usec / 1000) + (SysTime)tv.tv_sec * 1000; -} - -/** timers - **/ -typedef struct SysTimerRec_ -{ - SysTimer next; - SysTime when; - SysCallback callback; - void* opaque; -} SysTimerRec; - -#define SYS_MAX_TIMERS 16 - -static SysTimerRec _s_timers0[ SYS_MAX_TIMERS ]; -static SysTimer _s_free_timers; -static SysTimer _s_timers; - -static SysQueueRec _s_pending_timers[1]; - - -static void -sys_init_timers( void ) -{ - int nn; - for (nn = 0; nn < SYS_MAX_TIMERS-1; nn++) { - _s_timers0[nn].next = & _s_timers0[nn+1]; - } - _s_free_timers = &_s_timers0[0]; - - sys_queue_reset( _s_pending_timers ); -} - - -SysTimer sys_timer_create( void ) -{ - SysTimer timer = _s_free_timers; - assert( timer != NULL && "too many timers allocated" ); - _s_free_timers = timer->next; - timer->next = NULL; - return timer; -} - - -void sys_timer_unset( SysTimer timer ) -{ - if (timer->callback != NULL) { - SysTimer *pnode, node; - pnode = &_s_timers; - for (;;) { - node = *pnode; - if (node == NULL) - break; - if (node == timer) { - *pnode = node->next; - break; - } - pnode = &node->next; - } - timer->next = NULL; - timer->callback = NULL; - timer->opaque = NULL; - } -} - - -void sys_timer_set( SysTimer timer, - SysTime when, - SysCallback callback, - void* opaque ) -{ - if (timer->callback != NULL) - sys_timer_unset(timer); - - if (callback != NULL) { - SysTime now = sys_time_ms(); - - if (now >= when) { - callback( opaque ); - } else { - SysTimer *pnode, node; - pnode = &_s_timers; - for (;;) { - node = *pnode; - if (node == NULL || node->when >= when) { - break; - } - pnode = &node->next; - } - timer->next = *pnode; - *pnode = timer; - timer->when = when; - timer->callback = callback; - timer->opaque = opaque; - } - } -} - - -void sys_timer_destroy( SysTimer timer ) -{ - assert( timer != NULL && "sys_timer_destroy: bad argument" ); - if (timer->callback != NULL) - sys_timer_unset(timer); - - timer->next = _s_free_timers; - _s_free_timers = timer; -} - - -static void -sys_single_loop( void ) -{ - fd_set rfd, wfd, efd; - struct timeval timeout_tv, *timeout = NULL; - int n; - - memcpy(&rfd, &_s_fdsets[0], sizeof(fd_set)); - memcpy(&wfd, &_s_fdsets[1], sizeof(fd_set)); - memcpy(&efd, &_s_fdsets[2], sizeof(fd_set)); - - if ( _s_timers != NULL ) { - SysTime now = sys_time_ms(); - SysTimer first = _s_timers; - - timeout = &timeout_tv; - if (first->when <= now) { - timeout->tv_sec = 0; - timeout->tv_usec = 0; - } else { - SysTime diff = first->when - now; - timeout->tv_sec = diff / 1000; - timeout->tv_usec = (diff - timeout->tv_sec*1000) * 1000; - } - } - - n = select( _s_maxfd+1, &rfd, &wfd, &efd, timeout); - if(n < 0) { - if(errno == EINTR) return; - perror("select"); - return; - } - - /* enqueue pending channels */ - { - int i; - - sys_queue_reset( _s_pending_channels ); - for(i = 0; (i <= _s_maxfd) && (n > 0); i++) - { - int events = 0; - - if(FD_ISSET(i, &rfd)) events |= SYS_EVENT_READ; - if(FD_ISSET(i, &wfd)) events |= SYS_EVENT_WRITE; - if(FD_ISSET(i, &efd)) events |= SYS_EVENT_ERROR; - - if (events) { - SysChannel channel; - - n--; - for (channel = _s_channels; channel; channel = channel->next) - { - if (channel->fd != i) - continue; - - channel->ready = events; - channel->pending = 1; - sys_queue_add( _s_pending_channels, channel ); - break; - } - } - } - } - - /* enqueue pending timers */ - { - SysTimer timer = _s_timers; - SysTime now = sys_time_ms(); - - sys_queue_reset( _s_pending_timers ); - while (timer != NULL) - { - if (timer->when > now) - break; - - sys_queue_add( _s_pending_timers, timer ); - _s_timers = timer = timer->next; - } - } -} - -void sys_main_init( void ) -{ - sys_init_channels(); - sys_init_timers(); -} - - -int sys_main_loop( void ) -{ - for (;;) { - SysTimer timer; - SysChannel channel; - - /* exit if we have nothing to do */ - if (_s_channels == NULL && _s_timers == NULL) - break; - - sys_single_loop(); - - while ((timer = sys_queue_get( _s_pending_timers )) != NULL) { - timer->callback( timer->opaque ); - } - - while ((channel = sys_queue_get( _s_pending_channels )) != NULL) { - int events; - - channel->pending = 0; - if (channel->closed) { - /* the channel was closed by a previous callback */ - sys_channel_close(channel); - } - events = channel->ready; - channel->ready = 0; - channel->callback( channel->opaque, events ); - } - } - return 0; -} - - - - -SysChannel -sys_channel_create_tcp_server( int port ) -{ - SysChannel channel; - int on = 1; - const int BACKLOG = 4; - - channel = sys_channel_alloc(); - if (-1==(channel->fd=socket(AF_INET, SOCK_STREAM, 0))) { - perror("socket"); - sys_channel_free( channel ); - return NULL; - } - - /* Enable address re-use for server mode */ - if ( -1==setsockopt( channel->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) )) { - perror("setsockopt(SO_REUSEADDR)"); - } - - { - struct sockaddr_in servname; - long in_addr = INADDR_ANY; - - servname.sin_family = AF_INET; - servname.sin_port = htons(port); - - servname.sin_addr.s_addr=in_addr; - - if (-1==bind(channel->fd, (struct sockaddr*)&servname, sizeof(servname))) { - perror("bind"); - sys_channel_close(channel); - return NULL; - } - - /* Listen but don't accept */ - if ( listen(channel->fd, BACKLOG) < 0 ) { - perror("listen"); - sys_channel_close(channel); - return NULL; - } - } - return channel; -} - - -SysChannel -sys_channel_create_tcp_handler( SysChannel server_channel ) -{ - int on = 1; - SysChannel channel = sys_channel_alloc(); - - channel->fd = accept( server_channel->fd, NULL, 0 ); - if (channel->fd < 0) { - perror( "accept" ); - sys_channel_free( channel ); - return NULL; - } - - /* set to non-blocking and disable TCP Nagle algorithm */ - fcntl(channel->fd, F_SETFL, O_NONBLOCK); - setsockopt(channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - return channel; -} - - -SysChannel -sys_channel_create_tcp_client( const char* hostname, int port ) -{ - struct hostent* hp; - struct sockaddr_in addr; - SysChannel channel = sys_channel_alloc(); - int on = 1; - - hp = gethostbyname(hostname); - if(hp == 0) { - fprintf(stderr, "unknown host: %s\n", hostname); - sys_channel_free(channel); - return NULL; - }; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = hp->h_addrtype; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - - channel->fd = socket(hp->h_addrtype, SOCK_STREAM, 0); - if(channel->fd < 0) { - sys_channel_free(channel); - return NULL; - } - - if(connect( channel->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror( "connect" ); - sys_channel_free(channel); - return NULL; - } - - /* set to non-blocking and disable Nagle algorithm */ - fcntl(channel->fd, F_SETFL, O_NONBLOCK); - setsockopt( channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) ); - return channel; -} - diff --git a/telephony/sysdeps_qemu.c b/telephony/sysdeps_qemu.c deleted file mode 100644 index ec0b3f5..0000000 --- a/telephony/sysdeps_qemu.c +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sockets.h" -#include "sysdeps.h" -#include "qemu-timer.h" -#ifdef _WIN32 -#include <winsock2.h> -#else -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <netdb.h> -#endif - -#define DEBUG 1 - -#define D_ACTIVE DEBUG - -#if DEBUG -#define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0) -#else -#define D(...) ((void)0) -#endif - -/** TIME - **/ - -SysTime -sys_time_ms( void ) -{ - return qemu_get_clock( rt_clock ); -} - -/** TIMERS - **/ - -typedef struct SysTimerRec_ { - QEMUTimer* timer; - QEMUTimerCB* callback; - void* opaque; - SysTimer next; -} SysTimerRec; - -#define MAX_TIMERS 32 - -static SysTimerRec _s_timers0[ MAX_TIMERS ]; -static SysTimer _s_free_timers; - -static void -sys_init_timers( void ) -{ - int nn; - for (nn = 0; nn < MAX_TIMERS-1; nn++) - _s_timers0[nn].next = _s_timers0 + (nn+1); - - _s_free_timers = _s_timers0; -} - -static SysTimer -sys_timer_alloc( void ) -{ - SysTimer timer = _s_free_timers; - - if (timer != NULL) { - _s_free_timers = timer->next; - timer->next = NULL; - timer->timer = NULL; - } - return timer; -} - - -static void -sys_timer_free( SysTimer timer ) -{ - if (timer->timer) { - qemu_del_timer( timer->timer ); - qemu_free_timer( timer->timer ); - timer->timer = NULL; - } - timer->next = _s_free_timers; - _s_free_timers = timer; -} - - -SysTimer sys_timer_create( void ) -{ - SysTimer timer = sys_timer_alloc(); - return timer; -} - -void -sys_timer_set( SysTimer timer, SysTime when, SysCallback _callback, void* opaque ) -{ - QEMUTimerCB* callback = (QEMUTimerCB*)_callback; - - if (callback == NULL) { /* unsetting the timer */ - if (timer->timer) { - qemu_del_timer( timer->timer ); - qemu_free_timer( timer->timer ); - timer->timer = NULL; - } - timer->callback = callback; - timer->opaque = NULL; - return; - } - - if ( timer->timer ) { - if ( timer->callback == callback && timer->opaque == opaque ) - goto ReuseTimer; - - /* need to replace the timer */ - qemu_free_timer( timer->timer ); - } - - timer->timer = qemu_new_timer( rt_clock, callback, opaque ); - timer->callback = callback; - timer->opaque = opaque; - -ReuseTimer: - qemu_mod_timer( timer->timer, when ); -} - -void -sys_timer_unset( SysTimer timer ) -{ - if (timer->timer) { - qemu_del_timer( timer->timer ); - } -} - -void -sys_timer_destroy( SysTimer timer ) -{ - sys_timer_free( timer ); -} - - -/** CHANNELS - **/ - -typedef struct SysChannelRec_ { - int fd; - SysChannelCallback callback; - void* opaque; - SysChannel next; -} SysChannelRec; - -#define MAX_CHANNELS 16 - -static SysChannelRec _s_channels0[ MAX_CHANNELS ]; -static SysChannel _s_free_channels; - -static void -sys_init_channels( void ) -{ - int nn; - - for ( nn = 0; nn < MAX_CHANNELS-1; nn++ ) { - _s_channels0[nn].next = _s_channels0 + (nn+1); - } - _s_free_channels = _s_channels0; -} - -static SysChannel -sys_channel_alloc( ) -{ - SysChannel channel = _s_free_channels; - if (channel != NULL) { - _s_free_channels = channel->next; - channel->next = NULL; - channel->fd = -1; - channel->callback = NULL; - channel->opaque = NULL; - } - return channel; -} - -static void -sys_channel_free( SysChannel channel ) -{ - if (channel->fd >= 0) { - socket_close( channel->fd ); - channel->fd = -1; - } - channel->next = _s_free_channels; - _s_free_channels = channel; -} - - -static void -sys_channel_read_handler( void* _channel ) -{ - SysChannel channel = _channel; - D( "%s: read event for channel %p:%d\n", __FUNCTION__, - channel, channel->fd ); - channel->callback( channel->opaque, SYS_EVENT_READ ); -} - -static void -sys_channel_write_handler( void* _channel ) -{ - SysChannel channel = _channel; - D( "%s: write event for channel %p:%d\n", __FUNCTION__, channel, channel->fd ); - channel->callback( channel->opaque, SYS_EVENT_WRITE ); -} - -void -sys_channel_on( SysChannel channel, - int events, - SysChannelCallback event_callback, - void* event_opaque ) -{ - IOHandler* read_handler = NULL; - IOHandler* write_handler = NULL; - - if (events & SYS_EVENT_READ) { - read_handler = sys_channel_read_handler; - } - if (events & SYS_EVENT_WRITE) { - write_handler = sys_channel_write_handler; - } - channel->callback = event_callback; - channel->opaque = event_opaque; - qemu_set_fd_handler( channel->fd, read_handler, write_handler, channel ); -} - -int -sys_channel_read( SysChannel channel, void* buffer, int size ) -{ - int len = size; - char* buf = (char*) buffer; - - while (len > 0) { - int ret = socket_recv(channel->fd, buf, len); - if (ret < 0) { - if (errno == EINTR) - continue; - if (errno == EWOULDBLOCK) - break; - D( "%s: after reading %d bytes, recv() returned error %d: %s\n", - __FUNCTION__, size - len, errno, errno_str); - return -1; - } else if (ret == 0) { - break; - } else { - buf += ret; - len -= ret; - } - } - return size - len; -} - - -int -sys_channel_write( SysChannel channel, const void* buffer, int size ) -{ - int len = size; - const char* buf = (const char*) buffer; - - while (len > 0) { - int ret = socket_send(channel->fd, buf, len); - if (ret < 0) { - if (errno == EINTR) - continue; - if (errno == EWOULDBLOCK) - break; - D( "%s: send() returned error %d: %s\n", - __FUNCTION__, errno, errno_str); - return -1; - } else if (ret == 0) { - break; - } else { - buf += ret; - len -= ret; - } - } - return size - len; -} - -void sys_channel_close( SysChannel channel ) -{ - qemu_set_fd_handler( channel->fd, NULL, NULL, NULL ); - sys_channel_free( channel ); -} - -void sys_main_init( void ) -{ - sys_init_channels(); - sys_init_timers(); -} - - -int sys_main_loop( void ) -{ - /* no looping, qemu has its own event loop */ - return 0; -} - - - - -SysChannel -sys_channel_create_tcp_server( int port ) -{ - SysChannel channel = sys_channel_alloc(); - - channel->fd = socket_anyaddr_server( port, SOCKET_STREAM ); - if (channel->fd < 0) { - D( "%s: failed to created network socket on TCP:%d\n", - __FUNCTION__, port ); - sys_channel_free( channel ); - return NULL; - } - - D( "%s: server channel %p:%d now listening on port %d\n", - __FUNCTION__, channel, channel->fd, port ); - - return channel; -} - - -SysChannel -sys_channel_create_tcp_handler( SysChannel server_channel ) -{ - SysChannel channel = sys_channel_alloc(); - - D( "%s: creating handler from server channel %p:%d\n", __FUNCTION__, - server_channel, server_channel->fd ); - - channel->fd = socket_accept_any( server_channel->fd ); - if (channel->fd < 0) { - perror( "accept" ); - sys_channel_free( channel ); - return NULL; - } - - /* disable Nagle algorithm */ - socket_set_nodelay( channel->fd ); - - D( "%s: handler %p:%d created from server %p:%d\n", __FUNCTION__, - server_channel, server_channel->fd, channel, channel->fd ); - - return channel; -} - - -SysChannel -sys_channel_create_tcp_client( const char* hostname, int port ) -{ - SysChannel channel = sys_channel_alloc(); - - channel->fd = socket_network_client( hostname, port, SOCKET_STREAM ); - if (channel->fd < 0) { - sys_channel_free(channel); - return NULL; - }; - - /* set to non-blocking and disable Nagle algorithm */ - socket_set_nonblock( channel->fd ); - socket_set_nodelay( channel->fd ); - - return channel; -} - diff --git a/telephony/test1.c b/telephony/test1.c deleted file mode 100644 index 52701b9..0000000 --- a/telephony/test1.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sysdeps.h" -#include <stdio.h> - -#define MAX_COUNTER 10 - -static int counter = 0; - -static void -timer_func( void* _timer ) -{ - SysTimer timer = _timer; - SysTime now = sys_time_ms(); - - ++counter; - printf( "tick %d/%d a %.2fs\n", counter, MAX_COUNTER, now/1000. ); - if (counter < MAX_COUNTER) - sys_timer_set( timer, now + 2000, timer_func, timer ); - else - sys_timer_destroy( timer ); -} - - -int main( void ) -{ - SysTimer timer; - - /* initialize event subsystem */ - sys_main_init(); - - /* create timer and register it */ - timer = sys_timer_create(); - sys_timer_set( timer, sys_time_ms() + 1000, timer_func, timer ); - - printf("entering event loop\n"); - sys_main_loop(); - printf("exiting event loop\n" ); - return 0; -} diff --git a/telephony/test2.c b/telephony/test2.c deleted file mode 100644 index a0cd66f..0000000 --- a/telephony/test2.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "sysdeps.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#define PORT 8000 -#define MAX_COUNTER 30 -#define INITIAL_DELAY 1000 -#define DELAY 5000 - -static int counter = 0; - -static void -timer_func( void* _timer ) -{ - SysTimer timer = _timer; - SysTime now = sys_time_ms(); - - ++counter; - printf( "tick %d/%d a %.2fs\n", counter, MAX_COUNTER, now/1000. ); - if (counter < MAX_COUNTER) - sys_timer_set( timer, now + DELAY, timer_func, timer ); - else - sys_timer_destroy( timer ); -} - -typedef struct { - SysChannel channel; - char in_buff[ 128 ]; - int in_pos; - - char out_buff[ 128 ]; - int out_pos; - int out_size; -} ClientRec, *Client; - -static Client -client_alloc( SysChannel channel ) -{ - Client client = calloc( sizeof(*client), 1 ); - - client->channel = channel; - return client; -} - -static void -client_free( Client client ) -{ - sys_channel_close( client->channel ); - client->channel = NULL; - free( client ); -} - -static void -client_append( Client client, const char* str, int len ); - -static void -client_handle_line( Client client, const char* cmd ) -{ - char temp[256]; - int nn, mm = 0; - - for (nn = 0; cmd[nn] != 0; nn++) { - int c = cmd[nn]; - if (c >= 32 && c <= 127) - temp[mm++] = c; - else if (c == '\n') { - strcat( temp+mm, "<LF>" ); - mm += 4; - } - else if (c == '\r') { - strcat( temp+mm, "<CR>" ); - mm += 4; - } - else { - sprintf( temp+mm, "\\x%02x", c ); - mm += strlen( temp+mm ); - } - } - temp[mm] = 0; - printf( "%p: << %s\n", client, temp ); - - if ( !strcmp( cmd, "quit" ) ) { - printf( "client %p quitting\n", client ); - client_free( client ); - return; - } - client_append( client, "type 'quit' to quit\n", -1 ); -} - -static void -client_handler( void* _client, int events ) -{ - Client client = _client; - - if (events & SYS_EVENT_READ) { - int ret; - /* read into buffer, one character at a time */ - ret = sys_channel_read( client->channel, client->in_buff + client->in_pos, 1 ); - if (ret != 1) { - fprintf(stderr, "client %p could not read byte, result = %d, error: %s\n", - client, ret, strerror(errno) ); - goto ExitClient; - } - if (client->in_buff[client->in_pos] == '\r' || - client->in_buff[client->in_pos] == '\n' ) { - const char* cmd = client->in_buff; - client->in_buff[client->in_pos] = 0; - - /* eat leading cr and lf, maybe left-overs from previous line */ - while (*cmd == '\r' || *cmd =='\n') - cmd++; - - client_handle_line( client, cmd ); - client->in_pos = 0; - } else - client->in_pos += 1; - } - - if (events & SYS_EVENT_WRITE) { - int ret; - /* write from output buffer, one char at a time */ - ret = sys_channel_write( client->channel, client->out_buff + client->out_pos, 1 ); - if (ret != 1) { - fprintf(stderr, "client %p could not write byte, result = %d, error: %s\n", - client, ret, strerror(errno) ); - goto ExitClient; - } - client->out_pos += 1; - if (client->out_pos == client->out_size) { - client->out_size = 0; - client->out_pos = 0; - /* we don't need to write */ - sys_channel_on( client->channel, SYS_EVENT_READ, client_handler, client ); - } - } - return; - -ExitClient: - printf( "client %p exiting\n", client ); - client_free( client ); -} - -static void -client_append( Client client, const char* str, int len ) -{ - int avail; - - if (len < 0) - len = strlen(str); - - avail = sizeof(client->out_buff) - client->out_size; - if (len > avail) - len = avail; - - memcpy( client->out_buff + client->out_size, str, len ); - if (client->out_size == 0) { - sys_channel_on( client->channel, SYS_EVENT_READ | SYS_EVENT_WRITE, client_handler, client ); - } - client->out_size += len; -} - - -static void -accept_func( void* _server, int events ) -{ - SysChannel server = _server; - SysChannel handler; - Client client; - - printf( "connection accepted for server channel, getting handler socket\n" ); - handler = sys_channel_create_tcp_handler( server ); - printf( "got one. creating client\n" ); - client = client_alloc( handler ); - - events=events; - sys_channel_on( handler, SYS_EVENT_READ, client_handler, client ); - client_append( client, "Welcome !\n", -1 ); -} - - -int main( void ) -{ - SysTimer timer; - SysChannel server_channel; - - /* initialize event subsystem */ - sys_main_init(); - - /* create timer and register it */ - timer = sys_timer_create(); - sys_timer_set( timer, sys_time_ms() + INITIAL_DELAY, timer_func, timer ); - - server_channel = sys_channel_create_tcp_server( PORT ); - printf( "listening on port %d with %p\n", PORT, server_channel ); - - sys_channel_on( server_channel, SYS_EVENT_READ, accept_func, server_channel ); - - printf("entering event loop\n"); - sys_main_loop(); - printf("exiting event loop\n" ); - return 0; -} |