mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-31 19:57:06 +01:00
Merge branch 'android_branch' into android_translate
This commit is contained in:
commit
9fb8671ef0
31 changed files with 813 additions and 570 deletions
|
@ -10,7 +10,7 @@ android:
|
||||||
- tools
|
- tools
|
||||||
- platform-tools
|
- platform-tools
|
||||||
- build-tools-27.0.3
|
- build-tools-27.0.3
|
||||||
- android-26
|
- android-23
|
||||||
licenses:
|
licenses:
|
||||||
- android-sdk-preview-license-.+
|
- android-sdk-preview-license-.+
|
||||||
- android-sdk-license-.+
|
- android-sdk-license-.+
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
def INITIAL_CLIENT_VERS = 8
|
def INITIAL_CLIENT_VERS = 8
|
||||||
def VERSION_CODE_BASE = 133
|
def VERSION_CODE_BASE = 135
|
||||||
def VERSION_NAME = '4.4.137'
|
def VERSION_NAME = '4.4.139'
|
||||||
def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY")
|
def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY")
|
||||||
def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID")
|
def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID")
|
||||||
def BUILD_INFO_NAME = "build-info.txt"
|
def BUILD_INFO_NAME = "build-info.txt"
|
||||||
|
@ -33,7 +33,7 @@ android {
|
||||||
buildToolsVersion '27.0.3'
|
buildToolsVersion '27.0.3'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 8
|
minSdkVersion 8
|
||||||
targetSdkVersion 26
|
targetSdkVersion 23
|
||||||
versionCode VERSION_CODE_BASE
|
versionCode VERSION_CODE_BASE
|
||||||
versionName VERSION_NAME
|
versionName VERSION_NAME
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,6 @@ android {
|
||||||
}
|
}
|
||||||
xw4d {
|
xw4d {
|
||||||
dimension "variant"
|
dimension "variant"
|
||||||
minSdkVersion 8
|
|
||||||
applicationId "org.eehouse.android.xw4dbg"
|
applicationId "org.eehouse.android.xw4dbg"
|
||||||
manifestPlaceholders = [ FABRIC_API_KEY: "$FABRIC_API_KEY", APP_ID: applicationId, ]
|
manifestPlaceholders = [ FABRIC_API_KEY: "$FABRIC_API_KEY", APP_ID: applicationId, ]
|
||||||
resValue "string", "app_name", "CrossDbg"
|
resValue "string", "app_name", "CrossDbg"
|
||||||
|
@ -223,7 +222,7 @@ task copyStrings(type: Exec) {
|
||||||
|
|
||||||
task ndkSetup(type: Exec) {
|
task ndkSetup(type: Exec) {
|
||||||
workingDir '../'
|
workingDir '../'
|
||||||
commandLine "./scripts/ndksetup.sh", "--with-clang"
|
commandLine "./scripts/ndksetup.sh", "--with-clang", "--arm-only"
|
||||||
}
|
}
|
||||||
|
|
||||||
task myPreBuild(dependsOn: ['ndkSetup', 'mkImages', 'copyStrings', 'mkXml']) {
|
task myPreBuild(dependsOn: ['ndkSetup', 'mkImages', 'copyStrings', 'mkXml']) {
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>CrossWords 4.4.137 release</h2>
|
<h2>CrossWords 4.4.139 release</h2>
|
||||||
|
|
||||||
<p>This release paves the way for play-via-SMS improvements.</p>
|
<p>This release fixes a bug with picking tiles face-up</p>
|
||||||
|
|
||||||
<div id="survey">
|
<div id="survey">
|
||||||
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
||||||
|
@ -25,12 +25,10 @@
|
||||||
|
|
||||||
<h3>New with this release</h3>
|
<h3>New with this release</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Add new SMS-handling code. One feature isn't compatible with
|
<li>Don't put up multiple tile pickers. (This feature is rarely
|
||||||
the previous release so it won't be activated until there's been
|
used, but had apparently been broken for a while.)</li>
|
||||||
time for everybody to upgrade.</li>
|
<li>Fix two more bugs reported by users (Thanks!)</li>
|
||||||
<li>Include new Catalan translations</li>
|
<li>Include new translations for Catalan and Norwegian</li>
|
||||||
<li>Fix bug causing (rarely) unending notifications of wordlist
|
|
||||||
upgrade</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>(The full changelog
|
<p>(The full changelog
|
||||||
|
|
|
@ -365,7 +365,7 @@ public class BTService extends XWService {
|
||||||
break;
|
break;
|
||||||
case INVITE:
|
case INVITE:
|
||||||
String jsonData = intent.getStringExtra( GAMEDATA_KEY );
|
String jsonData = intent.getStringExtra( GAMEDATA_KEY );
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( this, jsonData );
|
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, jsonData );
|
||||||
Log.i( TAG, "onStartCommand: nli: %s", nli.toString() );
|
Log.i( TAG, "onStartCommand: nli: %s", nli.toString() );
|
||||||
String btAddr = intent.getStringExtra( ADDR_KEY );
|
String btAddr = intent.getStringExtra( ADDR_KEY );
|
||||||
m_sender.add( new BTQueueElem( BTCmd.INVITE, nli, btAddr ) );
|
m_sender.add( new BTQueueElem( BTCmd.INVITE, nli, btAddr ) );
|
||||||
|
@ -545,7 +545,7 @@ public class BTService extends XWService {
|
||||||
NetLaunchInfo nli;
|
NetLaunchInfo nli;
|
||||||
if ( BT_PROTO_JSONS == proto ) {
|
if ( BT_PROTO_JSONS == proto ) {
|
||||||
String asJson = is.readUTF();
|
String asJson = is.readUTF();
|
||||||
nli = new NetLaunchInfo( BTService.this, asJson );
|
nli = NetLaunchInfo.makeFrom( BTService.this, asJson );
|
||||||
} else {
|
} else {
|
||||||
short len = is.readShort();
|
short len = is.readShort();
|
||||||
byte[] nliData = new byte[len];
|
byte[] nliData = new byte[len];
|
||||||
|
@ -1106,11 +1106,17 @@ public class BTService extends XWService {
|
||||||
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
|
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MultiMsgSink getSink( long rowid )
|
||||||
|
{
|
||||||
|
return m_btMsgSink;
|
||||||
|
}
|
||||||
|
|
||||||
private BTCmd makeOrNotify( NetLaunchInfo nli, String btName,
|
private BTCmd makeOrNotify( NetLaunchInfo nli, String btName,
|
||||||
String btAddr )
|
String btAddr )
|
||||||
{
|
{
|
||||||
BTCmd result;
|
BTCmd result;
|
||||||
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) {
|
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) { // here
|
||||||
result = BTCmd.INVITE_ACCPT;
|
result = BTCmd.INVITE_ACCPT;
|
||||||
} else {
|
} else {
|
||||||
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
|
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
|
||||||
|
|
|
@ -115,7 +115,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
private BoardUtilCtxt m_utils;
|
private BoardUtilCtxt m_utils;
|
||||||
private boolean m_gameOver = false;
|
private boolean m_gameOver = false;
|
||||||
|
|
||||||
private JNIThread m_jniThread;
|
private volatile JNIThread m_jniThread;
|
||||||
private JNIThread m_jniThreadRef;
|
private JNIThread m_jniThreadRef;
|
||||||
private JNIThread.GameStateInfo m_gsi;
|
private JNIThread.GameStateInfo m_gsi;
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
m_when = when;
|
m_when = when;
|
||||||
m_handle = handle;
|
m_handle = handle;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
m_timers[m_why] = null;
|
m_timers[m_why] = null;
|
||||||
if ( null != m_jniThread ) {
|
if ( null != m_jniThread ) {
|
||||||
|
@ -1117,6 +1118,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
|
|
||||||
case ENABLE_SMS_DO:
|
case ENABLE_SMS_DO:
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
retrySMSInvites( params );
|
retrySMSInvites( params );
|
||||||
}
|
}
|
||||||
|
@ -1164,6 +1166,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
case ENABLE_RELAY_DO_OR:
|
case ENABLE_RELAY_DO_OR:
|
||||||
if ( m_dropOnDismiss ) {
|
if ( m_dropOnDismiss ) {
|
||||||
postDelayed( new Runnable() {
|
postDelayed( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
askDropRelay();
|
askDropRelay();
|
||||||
}
|
}
|
||||||
|
@ -1174,6 +1177,16 @@ public class BoardDelegate extends DelegateBase
|
||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BLANK_PICKED:
|
||||||
|
case TRAY_PICKED:
|
||||||
|
// If the user cancels the tile picker the common code doesn't
|
||||||
|
// know, and won't put it up again as long as this game remains
|
||||||
|
// loaded. There might be a way to fix that, but the safest thing
|
||||||
|
// to do for now is to close. User will have to begin the process
|
||||||
|
// of committing turn again on re-launching the game.
|
||||||
|
finish();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
handled = false;
|
handled = false;
|
||||||
}
|
}
|
||||||
|
@ -1257,17 +1270,20 @@ public class BoardDelegate extends DelegateBase
|
||||||
@SuppressWarnings("fallthrough")
|
@SuppressWarnings("fallthrough")
|
||||||
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
|
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
|
||||||
{
|
{
|
||||||
|
boolean doStopProgress = false;
|
||||||
switch( event ) {
|
switch( event ) {
|
||||||
case MESSAGE_ACCEPTED:
|
case MESSAGE_ACCEPTED:
|
||||||
case MESSAGE_REFUSED:
|
case MESSAGE_REFUSED:
|
||||||
ConnStatusHandler.
|
ConnStatusHandler.
|
||||||
updateStatusIn( m_activity, this, CommsConnType.COMMS_CONN_BT,
|
updateStatusIn( m_activity, this, CommsConnType.COMMS_CONN_BT,
|
||||||
MultiService.MultiEvent.MESSAGE_ACCEPTED == event);
|
MultiService.MultiEvent.MESSAGE_ACCEPTED == event);
|
||||||
|
doStopProgress = true;
|
||||||
break;
|
break;
|
||||||
case MESSAGE_NOGAME:
|
case MESSAGE_NOGAME:
|
||||||
int gameID = (Integer)args[0];
|
int gameID = (Integer)args[0];
|
||||||
if ( gameID == m_gi.gameID ) {
|
if ( gameID == m_gi.gameID ) {
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showDialogFragment( DlgID.DLG_DELETED );
|
showDialogFragment( DlgID.DLG_DELETED );
|
||||||
}
|
}
|
||||||
|
@ -1285,13 +1301,11 @@ public class BoardDelegate extends DelegateBase
|
||||||
Log.w( TAG, "failed to create game" );
|
Log.w( TAG, "failed to create game" );
|
||||||
break;
|
break;
|
||||||
case NEWGAME_DUP_REJECTED:
|
case NEWGAME_DUP_REJECTED:
|
||||||
if ( m_progressShown ) {
|
doStopProgress = true;
|
||||||
m_progressShown = false;
|
|
||||||
stopProgress(); // in case it's a BT invite
|
|
||||||
}
|
|
||||||
final String msg =
|
final String msg =
|
||||||
getString( R.string.err_dup_invite_fmt, (String)args[0] );
|
getString( R.string.err_dup_invite_fmt, (String)args[0] );
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
makeOkOnlyBuilder( msg ).show();
|
makeOkOnlyBuilder( msg ).show();
|
||||||
}
|
}
|
||||||
|
@ -1311,13 +1325,15 @@ public class BoardDelegate extends DelegateBase
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ( m_progressShown ) {
|
doStopProgress = true; // in case it's a BT invite
|
||||||
m_progressShown = false;
|
|
||||||
stopProgress(); // in case it's a BT invite
|
|
||||||
}
|
|
||||||
super.eventOccurred( event, args );
|
super.eventOccurred( event, args );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( doStopProgress && m_progressShown ) {
|
||||||
|
m_progressShown = false;
|
||||||
|
stopProgress();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
@ -1328,6 +1344,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
final boolean allHere, final int nMissing )
|
final boolean allHere, final int nMissing )
|
||||||
{
|
{
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
handleConndMessage( room, devOrder, allHere, nMissing ); // from here too
|
handleConndMessage( room, devOrder, allHere, nMissing ); // from here too
|
||||||
}
|
}
|
||||||
|
@ -1381,6 +1398,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
final int strIDf = strID;
|
final int strIDf = strID;
|
||||||
final DlgID dlgIDf = dlgID;
|
final DlgID dlgIDf = dlgID;
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showDialogFragment( dlgIDf, R.string.relay_alert,
|
showDialogFragment( dlgIDf, R.string.relay_alert,
|
||||||
getString( strIDf ) );
|
getString( strIDf ) );
|
||||||
|
@ -1397,6 +1415,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
{
|
{
|
||||||
if ( success ) {
|
if ( success ) {
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
setGotGameDict( name );
|
setGotGameDict( name );
|
||||||
}
|
}
|
||||||
|
@ -1452,6 +1471,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
public void invalidateParent()
|
public void invalidateParent()
|
||||||
{
|
{
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
m_view.invalidate();
|
m_view.invalidate();
|
||||||
}
|
}
|
||||||
|
@ -1462,6 +1482,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
{
|
{
|
||||||
final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes );
|
final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes );
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if ( null == msg ) {
|
if ( null == msg ) {
|
||||||
askNoAddrsDelete();
|
askNoAddrsDelete();
|
||||||
|
@ -1627,6 +1648,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
public void requestTime()
|
public void requestTime()
|
||||||
{
|
{
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if ( null != m_jniThread ) {
|
if ( null != m_jniThread ) {
|
||||||
m_jniThread.handleBkgrnd( JNICmd.CMD_DO );
|
m_jniThread.handleBkgrnd( JNICmd.CMD_DO );
|
||||||
|
@ -1678,6 +1700,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
if ( 0 != id ) {
|
if ( 0 != id ) {
|
||||||
final String bonusStr = getString( id );
|
final String bonusStr = getString( id );
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showToast( bonusStr );
|
showToast( bonusStr );
|
||||||
}
|
}
|
||||||
|
@ -1696,6 +1719,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
}
|
}
|
||||||
final String text = expl;
|
final String text = expl;
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showToast( text );
|
showToast( text );
|
||||||
}
|
}
|
||||||
|
@ -1706,6 +1730,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
public void cellSquareHeld( final String words )
|
public void cellSquareHeld( final String words )
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
launchLookup( wordsToArray( words ), m_gi.dictLang );
|
launchLookup( wordsToArray( words ), m_gi.dictLang );
|
||||||
}
|
}
|
||||||
|
@ -1744,19 +1769,25 @@ public class BoardDelegate extends DelegateBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startTP( final Action action,
|
||||||
|
final TilePickAlert.TilePickState tps )
|
||||||
|
{
|
||||||
|
runOnUiThread( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
show( TilePickAlert.newInstance( action, tps ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
// This is supposed to be called from the jni thread
|
// This is supposed to be called from the jni thread
|
||||||
@Override
|
@Override
|
||||||
public void notifyPickTileBlank( int playerNum, int col, int row,
|
public void notifyPickTileBlank( int playerNum, int col, int row,
|
||||||
String[] texts )
|
String[] texts )
|
||||||
{
|
{
|
||||||
final TilePickAlert.TilePickState tps =
|
TilePickAlert.TilePickState tps =
|
||||||
new TilePickAlert.TilePickState( playerNum, texts, col, row );
|
new TilePickAlert.TilePickState( playerNum, texts, col, row );
|
||||||
runOnUiThread( new Runnable() {
|
startTP( Action.BLANK_PICKED, tps );
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show( TilePickAlert.newInstance( Action.BLANK_PICKED, tps ) );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1764,15 +1795,10 @@ public class BoardDelegate extends DelegateBase
|
||||||
int playerNum, int nToPick,
|
int playerNum, int nToPick,
|
||||||
String[] texts, int[] counts )
|
String[] texts, int[] counts )
|
||||||
{
|
{
|
||||||
final TilePickAlert.TilePickState tps
|
TilePickAlert.TilePickState tps
|
||||||
= new TilePickAlert.TilePickState( isInitial, playerNum, nToPick,
|
= new TilePickAlert.TilePickState( isInitial, playerNum, nToPick,
|
||||||
texts, counts );
|
texts, counts );
|
||||||
runOnUiThread( new Runnable() {
|
startTP( Action.TRAY_PICKED, tps );
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show( TilePickAlert.newInstance( Action.TRAY_PICKED, tps ) );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1787,6 +1813,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
if ( 0 <= newTurn ) {
|
if ( 0 <= newTurn ) {
|
||||||
m_mySIS.nMissing = 0;
|
m_mySIS.nMissing = 0;
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
makeNotAgainBuilder( R.string.not_again_turnchanged,
|
makeNotAgainBuilder( R.string.not_again_turnchanged,
|
||||||
R.string.key_notagain_turnchanged )
|
R.string.key_notagain_turnchanged )
|
||||||
|
@ -1801,7 +1828,9 @@ public class BoardDelegate extends DelegateBase
|
||||||
@Override
|
@Override
|
||||||
public boolean engineProgressCallback()
|
public boolean engineProgressCallback()
|
||||||
{
|
{
|
||||||
return ! m_jniThread.busy();
|
// return true if engine should keep going
|
||||||
|
JNIThread jnit = m_jniThread;
|
||||||
|
return jnit != null && !jnit.busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1879,6 +1908,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
if ( asToast ) {
|
if ( asToast ) {
|
||||||
final int residf = resid;
|
final int residf = resid;
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
showToast( residf );
|
showToast( residf );
|
||||||
}
|
}
|
||||||
|
@ -2021,6 +2051,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
String fromPlayer, final int tsSeconds )
|
String fromPlayer, final int tsSeconds )
|
||||||
{
|
{
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
DBUtils.appendChatHistory( m_activity, m_rowid, msg,
|
DBUtils.appendChatHistory( m_activity, m_rowid, msg,
|
||||||
fromIndx, tsSeconds );
|
fromIndx, tsSeconds );
|
||||||
|
@ -2543,6 +2574,7 @@ public class BoardDelegate extends DelegateBase
|
||||||
if ( keepOn ) {
|
if ( keepOn ) {
|
||||||
if ( null == m_screenTimer ) {
|
if ( null == m_screenTimer ) {
|
||||||
m_screenTimer = new Runnable() {
|
m_screenTimer = new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if ( null != m_view ) {
|
if ( null != m_view ) {
|
||||||
m_view.setKeepScreenOn( false );
|
m_view.setKeepScreenOn( false );
|
||||||
|
|
|
@ -126,8 +126,6 @@ public class ConnStatusHandler {
|
||||||
|
|
||||||
private ConnStatusHandler() {}
|
private ConnStatusHandler() {}
|
||||||
|
|
||||||
private static HashMap<CommsConnType,SuccessRecord[]> s_records =
|
|
||||||
new HashMap<CommsConnType,SuccessRecord[]>();
|
|
||||||
private static boolean s_needsSave = false;
|
private static boolean s_needsSave = false;
|
||||||
|
|
||||||
public static void setRect( int left, int top, int right, int bottom )
|
public static void setRect( int left, int top, int right, int bottom )
|
||||||
|
@ -184,7 +182,7 @@ public class ConnStatusHandler {
|
||||||
typ.longName( context ), did ) );
|
typ.longName( context ), did ) );
|
||||||
|
|
||||||
// For sends we list failures too.
|
// For sends we list failures too.
|
||||||
SuccessRecord record = recordFor( typ, false );
|
SuccessRecord record = recordFor( context, typ, false );
|
||||||
tmp = LocUtils.getString( context, record.successNewer?
|
tmp = LocUtils.getString( context, record.successNewer?
|
||||||
R.string.connstat_succ :
|
R.string.connstat_succ :
|
||||||
R.string.connstat_unsucc );
|
R.string.connstat_unsucc );
|
||||||
|
@ -214,7 +212,7 @@ public class ConnStatusHandler {
|
||||||
}
|
}
|
||||||
sb.append( "\n" );
|
sb.append( "\n" );
|
||||||
|
|
||||||
record = recordFor( typ, true );
|
record = recordFor( context, typ, true );
|
||||||
if ( record.haveSuccess() ) {
|
if ( record.haveSuccess() ) {
|
||||||
sb.append( LocUtils.getString( context,
|
sb.append( LocUtils.getString( context,
|
||||||
R.string.connstat_lastreceipt_fmt,
|
R.string.connstat_lastreceipt_fmt,
|
||||||
|
@ -264,7 +262,7 @@ public class ConnStatusHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized( ConnStatusHandler.class ) {
|
synchronized( ConnStatusHandler.class ) {
|
||||||
SuccessRecord record = recordFor( connType, isIn );
|
SuccessRecord record = recordFor( context, connType, isIn );
|
||||||
record.update( success );
|
record.update( success );
|
||||||
}
|
}
|
||||||
invalidateParent();
|
invalidateParent();
|
||||||
|
@ -306,14 +304,14 @@ public class ConnStatusHandler {
|
||||||
|
|
||||||
// Do the background coloring and arrow. Top half first
|
// Do the background coloring and arrow. Top half first
|
||||||
scratchR.bottom -= (2 * quarterHeight);
|
scratchR.bottom -= (2 * quarterHeight);
|
||||||
fillHalf( canvas, scratchR, connTypes, enabled, false );
|
fillHalf( context, canvas, scratchR, connTypes, enabled, false );
|
||||||
scratchR.bottom -= quarterHeight;
|
scratchR.bottom -= quarterHeight;
|
||||||
drawArrow( canvas, res, scratchR, false );
|
drawArrow( canvas, res, scratchR, false );
|
||||||
|
|
||||||
// bottom half and arrow
|
// bottom half and arrow
|
||||||
scratchR.top = s_rect.top + (2 * quarterHeight);
|
scratchR.top = s_rect.top + (2 * quarterHeight);
|
||||||
scratchR.bottom = s_rect.bottom;
|
scratchR.bottom = s_rect.bottom;
|
||||||
fillHalf( canvas, scratchR, connTypes, enabled, true );
|
fillHalf( context, canvas, scratchR, connTypes, enabled, true );
|
||||||
scratchR.top += quarterHeight;
|
scratchR.top += quarterHeight;
|
||||||
drawArrow( canvas, res, scratchR, true );
|
drawArrow( canvas, res, scratchR, true );
|
||||||
|
|
||||||
|
@ -332,11 +330,11 @@ public class ConnStatusHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fillHalf( Canvas canvas, Rect rect,
|
private static void fillHalf( Context context, Canvas canvas, Rect rect,
|
||||||
CommsConnTypeSet connTypes, boolean enabled,
|
CommsConnTypeSet connTypes, boolean enabled,
|
||||||
boolean isIn )
|
boolean isIn )
|
||||||
{
|
{
|
||||||
enabled = enabled && null != newestSuccess( connTypes, isIn );
|
enabled = enabled && null != newestSuccess( context, connTypes, isIn );
|
||||||
s_fillPaint.setColor( enabled ? XWApp.GREEN : XWApp.RED );
|
s_fillPaint.setColor( enabled ? XWApp.GREEN : XWApp.RED );
|
||||||
canvas.drawRect( rect, s_fillPaint );
|
canvas.drawRect( rect, s_fillPaint );
|
||||||
}
|
}
|
||||||
|
@ -359,19 +357,23 @@ public class ConnStatusHandler {
|
||||||
// This gets rid of lint warning, but I don't like it as it
|
// This gets rid of lint warning, but I don't like it as it
|
||||||
// effects the whole method.
|
// effects the whole method.
|
||||||
// @SuppressWarnings("unchecked")
|
// @SuppressWarnings("unchecked")
|
||||||
public static void loadState( Context context )
|
private static HashMap<CommsConnType,SuccessRecord[]> s_records;
|
||||||
|
private static HashMap<CommsConnType,SuccessRecord[]> getRecords( Context context )
|
||||||
{
|
{
|
||||||
synchronized( ConnStatusHandler.class ) {
|
synchronized( ConnStatusHandler.class ) {
|
||||||
s_records = null;
|
if ( s_records == null ) {
|
||||||
String as64 = XWPrefs.getPrefsString( context,
|
String as64 = XWPrefs.getPrefsString( context,
|
||||||
R.string.key_connstat_data );
|
R.string.key_connstat_data );
|
||||||
if ( null != as64 && 0 < as64.length() ) {
|
if ( null != as64 && 0 < as64.length() ) {
|
||||||
s_records = (HashMap<CommsConnType,SuccessRecord[]>)Utils.string64ToSerializable(as64);
|
s_records = (HashMap<CommsConnType,SuccessRecord[]>)Utils.
|
||||||
}
|
string64ToSerializable(as64);
|
||||||
if ( null == s_records ) {
|
}
|
||||||
s_records = new HashMap<CommsConnType,SuccessRecord[]>();
|
if ( null == s_records ) {
|
||||||
|
s_records = new HashMap<CommsConnType,SuccessRecord[]>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return s_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void saveState( final Context context,
|
private static void saveState( final Context context,
|
||||||
|
@ -440,7 +442,8 @@ public class ConnStatusHandler {
|
||||||
icon.draw( canvas );
|
icon.draw( canvas );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SuccessRecord newestSuccess( CommsConnTypeSet connTypes,
|
private static SuccessRecord newestSuccess( Context context,
|
||||||
|
CommsConnTypeSet connTypes,
|
||||||
boolean isIn )
|
boolean isIn )
|
||||||
{
|
{
|
||||||
SuccessRecord result = null;
|
SuccessRecord result = null;
|
||||||
|
@ -448,7 +451,7 @@ public class ConnStatusHandler {
|
||||||
Iterator<CommsConnType> iter = connTypes.iterator();
|
Iterator<CommsConnType> iter = connTypes.iterator();
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
CommsConnType connType = iter.next();
|
CommsConnType connType = iter.next();
|
||||||
SuccessRecord record = recordFor( connType, isIn );
|
SuccessRecord record = recordFor( context, connType, isIn );
|
||||||
if ( record.successNewer ) {
|
if ( record.successNewer ) {
|
||||||
if ( null == result || result.lastSuccess < record.lastSuccess ) {
|
if ( null == result || result.lastSuccess < record.lastSuccess ) {
|
||||||
result = record;
|
result = record;
|
||||||
|
@ -459,14 +462,16 @@ public class ConnStatusHandler {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SuccessRecord recordFor( CommsConnType connType, boolean isIn )
|
private static SuccessRecord recordFor( Context context,
|
||||||
|
CommsConnType connType,
|
||||||
|
boolean isIn )
|
||||||
{
|
{
|
||||||
SuccessRecord[] records = s_records.get( connType );
|
SuccessRecord[] records = getRecords( context ).get( connType );
|
||||||
if ( null == records ) {
|
if ( null == records ) {
|
||||||
records = new SuccessRecord[] { new SuccessRecord(),
|
records = new SuccessRecord[] { new SuccessRecord(),
|
||||||
new SuccessRecord(),
|
new SuccessRecord(),
|
||||||
};
|
};
|
||||||
s_records.put( connType, records );
|
getRecords( context ).put( connType, records );
|
||||||
}
|
}
|
||||||
return records[isIn?0:1];
|
return records[isIn?0:1];
|
||||||
}
|
}
|
||||||
|
@ -474,7 +479,7 @@ public class ConnStatusHandler {
|
||||||
private static void doSave( Context context )
|
private static void doSave( Context context )
|
||||||
{
|
{
|
||||||
synchronized( ConnStatusHandler.class ) {
|
synchronized( ConnStatusHandler.class ) {
|
||||||
String as64 = Utils.serializableToString64( s_records );
|
String as64 = Utils.serializableToString64( getRecords( context ) );
|
||||||
XWPrefs.setPrefsString( context, R.string.key_connstat_data,
|
XWPrefs.setPrefsString( context, R.string.key_connstat_data,
|
||||||
as64 );
|
as64 );
|
||||||
s_needsSave = false;
|
s_needsSave = false;
|
||||||
|
|
|
@ -1183,7 +1183,9 @@ public class GameUtils {
|
||||||
boolean informNow )
|
boolean informNow )
|
||||||
{
|
{
|
||||||
GameSummary summary = DBUtils.getSummary( context, lock );
|
GameSummary summary = DBUtils.getSummary( context, lock );
|
||||||
if ( DeviceRole.SERVER_STANDALONE != summary.serverRole ) {
|
if ( null == summary ) {
|
||||||
|
Log.e( TAG, "tellDied(): can't get summary" );
|
||||||
|
} else if ( DeviceRole.SERVER_STANDALONE != summary.serverRole ) {
|
||||||
int gameID = summary.gameID;
|
int gameID = summary.gameID;
|
||||||
|
|
||||||
GamePtr gamePtr = loadMakeGame( context, lock );
|
GamePtr gamePtr = loadMakeGame( context, lock );
|
||||||
|
|
|
@ -2260,7 +2260,7 @@ public class GamesListDelegate extends ListDelegateBase
|
||||||
{
|
{
|
||||||
String data = NFCUtils.getFromIntent( intent );
|
String data = NFCUtils.getFromIntent( intent );
|
||||||
if ( null != data ) {
|
if ( null != data ) {
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( m_activity, data );
|
NetLaunchInfo nli = NetLaunchInfo.makeFrom( m_activity, data );
|
||||||
if ( nli.isValid() ) {
|
if ( nli.isValid() ) {
|
||||||
startNewNetGame( nli );
|
startNewNetGame( nli );
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,8 @@ public class MultiService {
|
||||||
{
|
{
|
||||||
Assert.assertTrue( isMissingDictIntent( intent ) );
|
Assert.assertTrue( isMissingDictIntent( intent ) );
|
||||||
String nliData = intent.getStringExtra( NLI_DATA );
|
String nliData = intent.getStringExtra( NLI_DATA );
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( context, nliData );
|
NetLaunchInfo nli = NetLaunchInfo.makeFrom( context, nliData );
|
||||||
|
Assert.assertTrue( nli != null || !BuildConfig.DEBUG );
|
||||||
return nli;
|
return nli;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */
|
/* -*- compile-command: "find-and-gradle.sh inXw4Deb"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
|
* Copyright 2009 - 2018 by Eric House (xwords@eehouse.org). All rights
|
||||||
* rights reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -27,8 +27,13 @@ import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -90,7 +95,7 @@ public class NetLaunchInfo implements Serializable {
|
||||||
inviteID = GameUtils.formatGameID( Utils.nextRandomInt() );
|
inviteID = GameUtils.formatGameID( Utils.nextRandomInt() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetLaunchInfo( Context context, String data )
|
private NetLaunchInfo( Context context, String data ) throws JSONException
|
||||||
{
|
{
|
||||||
init( context, data );
|
init( context, data );
|
||||||
}
|
}
|
||||||
|
@ -128,6 +133,31 @@ public class NetLaunchInfo implements Serializable {
|
||||||
return nli;
|
return nli;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static NetLaunchInfo makeFrom( Context context, String data )
|
||||||
|
{
|
||||||
|
NetLaunchInfo nli = null;
|
||||||
|
try {
|
||||||
|
nli = new NetLaunchInfo( context, data );
|
||||||
|
} catch ( JSONException jse ) {
|
||||||
|
Log.ex( TAG, jse );
|
||||||
|
}
|
||||||
|
return nli;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetLaunchInfo makeFrom( Context context, byte[] data )
|
||||||
|
{
|
||||||
|
NetLaunchInfo nli = null;
|
||||||
|
try {
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream( data );
|
||||||
|
DataInputStream dis = new DataInputStream( bais );
|
||||||
|
String nliData = dis.readUTF();
|
||||||
|
nli = NetLaunchInfo.makeFrom( context, nliData );
|
||||||
|
} catch ( java.io.IOException ex ) {
|
||||||
|
Assert.assertFalse( BuildConfig.DEBUG );
|
||||||
|
}
|
||||||
|
return nli;
|
||||||
|
}
|
||||||
|
|
||||||
public NetLaunchInfo( Context context, Uri data )
|
public NetLaunchInfo( Context context, Uri data )
|
||||||
{
|
{
|
||||||
this();
|
this();
|
||||||
|
@ -422,63 +452,58 @@ public class NetLaunchInfo implements Serializable {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init( Context context, String data )
|
private void init( Context context, String data ) throws JSONException
|
||||||
{
|
{
|
||||||
CommsConnTypeSet supported = CommsConnTypeSet.getSupported( context );
|
CommsConnTypeSet supported = CommsConnTypeSet.getSupported( context );
|
||||||
try {
|
JSONObject json = new JSONObject( data );
|
||||||
JSONObject json = new JSONObject( data );
|
|
||||||
|
|
||||||
int flags = json.optInt(ADDRS_KEY, -1);
|
int flags = json.optInt(ADDRS_KEY, -1);
|
||||||
boolean hasAddrs = -1 != flags;
|
boolean hasAddrs = -1 != flags;
|
||||||
m_addrs = hasAddrs ?
|
m_addrs = hasAddrs ?
|
||||||
new CommsConnTypeSet( flags ) : new CommsConnTypeSet();
|
new CommsConnTypeSet( flags ) : new CommsConnTypeSet();
|
||||||
|
|
||||||
lang = json.optInt( MultiService.LANG, -1 );
|
lang = json.optInt( MultiService.LANG, -1 );
|
||||||
forceChannel = json.optInt( MultiService.FORCECHANNEL, 0 );
|
forceChannel = json.optInt( MultiService.FORCECHANNEL, 0 );
|
||||||
dict = json.optString( MultiService.DICT );
|
dict = json.optString( MultiService.DICT );
|
||||||
gameName = json.optString( MultiService.GAMENAME );
|
gameName = json.optString( MultiService.GAMENAME );
|
||||||
nPlayersT = json.optInt( MultiService.NPLAYERST, -1 );
|
nPlayersT = json.optInt( MultiService.NPLAYERST, -1 );
|
||||||
nPlayersH = json.optInt( MultiService.NPLAYERSH, 1 ); // absent ok
|
nPlayersH = json.optInt( MultiService.NPLAYERSH, 1 ); // absent ok
|
||||||
gameID = json.optInt( MultiService.GAMEID, 0 );
|
gameID = json.optInt( MultiService.GAMEID, 0 );
|
||||||
|
|
||||||
// Try each type
|
// Try each type
|
||||||
for ( CommsConnType typ : supported.getTypes() ) {
|
for ( CommsConnType typ : supported.getTypes() ) {
|
||||||
if ( hasAddrs && !m_addrs.contains( typ ) ) {
|
if ( hasAddrs && !m_addrs.contains( typ ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean doAdd;
|
boolean doAdd;
|
||||||
switch ( typ ) {
|
switch ( typ ) {
|
||||||
case COMMS_CONN_BT:
|
case COMMS_CONN_BT:
|
||||||
btAddress = json.optString( MultiService.BT_ADDRESS );
|
btAddress = json.optString( MultiService.BT_ADDRESS );
|
||||||
btName = json.optString( MultiService.BT_NAME );
|
btName = json.optString( MultiService.BT_NAME );
|
||||||
doAdd = !hasAddrs && !btAddress.isEmpty();
|
doAdd = !hasAddrs && !btAddress.isEmpty();
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_RELAY:
|
case COMMS_CONN_RELAY:
|
||||||
room = json.getString( MultiService.ROOM );
|
room = json.getString( MultiService.ROOM );
|
||||||
inviteID = json.optString( MultiService.INVITEID );
|
inviteID = json.optString( MultiService.INVITEID );
|
||||||
doAdd = !hasAddrs && !room.isEmpty();
|
doAdd = !hasAddrs && !room.isEmpty();
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_SMS:
|
case COMMS_CONN_SMS:
|
||||||
phone = json.optString( PHONE_KEY );
|
phone = json.optString( PHONE_KEY );
|
||||||
isGSM = json.optBoolean( GSM_KEY, false );
|
isGSM = json.optBoolean( GSM_KEY, false );
|
||||||
osVers = json.optInt( OSVERS_KEY, 0 );
|
osVers = json.optInt( OSVERS_KEY, 0 );
|
||||||
doAdd = !hasAddrs && !phone.isEmpty();
|
doAdd = !hasAddrs && !phone.isEmpty();
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_P2P:
|
case COMMS_CONN_P2P:
|
||||||
p2pMacAddress = json.optString( P2P_MAC_KEY );
|
p2pMacAddress = json.optString( P2P_MAC_KEY );
|
||||||
doAdd = !hasAddrs && null != p2pMacAddress;
|
doAdd = !hasAddrs && null != p2pMacAddress;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
doAdd = false;
|
doAdd = false;
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
}
|
}
|
||||||
if ( doAdd ) {
|
if ( doAdd ) {
|
||||||
m_addrs.add( typ );
|
m_addrs.add( typ );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch ( JSONException jse ) {
|
|
||||||
Log.ex( TAG, jse );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUnsupported( supported );
|
removeUnsupported( supported );
|
||||||
|
@ -589,6 +614,20 @@ public class NetLaunchInfo implements Serializable {
|
||||||
return makeLaunchJSON();
|
return makeLaunchJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] asByteArray()
|
||||||
|
{
|
||||||
|
byte[] result = null;
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream das = new DataOutputStream( bas );
|
||||||
|
das.writeUTF( makeLaunchJSON() );
|
||||||
|
result = bas.toByteArray();
|
||||||
|
} catch ( java.io.IOException ex ) {
|
||||||
|
Assert.assertFalse( BuildConfig.DEBUG );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static void putExtras( Intent intent, int gameID, String btAddr )
|
public static void putExtras( Intent intent, int gameID, String btAddr )
|
||||||
{
|
{
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
|
|
|
@ -397,7 +397,7 @@ public class RelayService extends XWService
|
||||||
case GOT_INVITE:
|
case GOT_INVITE:
|
||||||
int srcDevID = intent.getIntExtra( INVITE_FROM, 0 );
|
int srcDevID = intent.getIntExtra( INVITE_FROM, 0 );
|
||||||
NetLaunchInfo nli
|
NetLaunchInfo nli
|
||||||
= new NetLaunchInfo( this, intent.getStringExtra(NLI_DATA) );
|
= NetLaunchInfo.makeFrom( this, intent.getStringExtra(NLI_DATA) );
|
||||||
receiveInvitation( srcDevID, nli );
|
receiveInvitation( srcDevID, nli );
|
||||||
break;
|
break;
|
||||||
case SEND:
|
case SEND:
|
||||||
|
@ -820,7 +820,7 @@ public class RelayService extends XWService
|
||||||
Log.d( TAG, "sendInvitation(%d->%d/%s [%s])", srcDevID, destDevID,
|
Log.d( TAG, "sendInvitation(%d->%d/%s [%s])", srcDevID, destDevID,
|
||||||
relayID, nliStr );
|
relayID, nliStr );
|
||||||
|
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( this, nliStr );
|
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliStr );
|
||||||
byte[] nliData = XwJNI.nliToStream( nli );
|
byte[] nliData = XwJNI.nliToStream( nli );
|
||||||
if ( BuildConfig.DEBUG ) {
|
if ( BuildConfig.DEBUG ) {
|
||||||
NetLaunchInfo tmp = XwJNI.nliFromStream( nliData );
|
NetLaunchInfo tmp = XwJNI.nliFromStream( nliData );
|
||||||
|
|
|
@ -41,6 +41,8 @@ import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
import org.eehouse.android.xw4.jni.XwJNI.SMSProtoMsg;
|
||||||
|
import org.eehouse.android.xw4.jni.XwJNI.SMS_CMD;
|
||||||
import org.eehouse.android.xw4.loc.LocUtils;
|
import org.eehouse.android.xw4.loc.LocUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -75,17 +77,13 @@ public class SMSService extends XWService {
|
||||||
private static final String BUFFER = "BUFFER";
|
private static final String BUFFER = "BUFFER";
|
||||||
private static final String BINBUFFER = "BINBUFFER";
|
private static final String BINBUFFER = "BINBUFFER";
|
||||||
private static final String PHONE = "PHONE";
|
private static final String PHONE = "PHONE";
|
||||||
private static final String GAMEDATA_STR = "GD";
|
private static final String GAMEDATA_BA = "GD";
|
||||||
|
|
||||||
private static final String PHONE_RECS_KEY =
|
private static final String PHONE_RECS_KEY =
|
||||||
SMSService.class.getName() + "_PHONES";
|
SMSService.class.getName() + "_PHONES";
|
||||||
|
|
||||||
private static Boolean s_showToasts = null;
|
private static Boolean s_showToasts = null;
|
||||||
|
|
||||||
// All messages are base64-encoded byte arrays. The first byte is
|
|
||||||
// always one of these. What follows depends.
|
|
||||||
private enum SMS_CMD { NONE, INVITE, DATA, DEATH, ACK, };
|
|
||||||
|
|
||||||
private BroadcastReceiver m_sentReceiver;
|
private BroadcastReceiver m_sentReceiver;
|
||||||
private BroadcastReceiver m_receiveReceiver;
|
private BroadcastReceiver m_receiveReceiver;
|
||||||
private OnSharedPreferenceChangeListener m_prefsListener;
|
private OnSharedPreferenceChangeListener m_prefsListener;
|
||||||
|
@ -195,9 +193,9 @@ public class SMSService extends XWService {
|
||||||
{
|
{
|
||||||
Intent intent = getIntentTo( context, SMSAction.INVITE );
|
Intent intent = getIntentTo( context, SMSAction.INVITE );
|
||||||
intent.putExtra( PHONE, phone );
|
intent.putExtra( PHONE, phone );
|
||||||
String asString = nli.toString();
|
Log.w( TAG, "inviteRemote(%s, '%s')", phone, nli );
|
||||||
Log.w( TAG, "inviteRemote(%s, '%s')", phone, asString );
|
byte[] data = nli.asByteArray();
|
||||||
intent.putExtra( GAMEDATA_STR, asString );
|
intent.putExtra( GAMEDATA_BA, data );
|
||||||
context.startService( intent );
|
context.startService( intent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +337,8 @@ public class SMSService extends XWService {
|
||||||
break;
|
break;
|
||||||
case INVITE:
|
case INVITE:
|
||||||
phone = intent.getStringExtra( PHONE );
|
phone = intent.getStringExtra( PHONE );
|
||||||
inviteRemote( phone, intent.getStringExtra( GAMEDATA_STR ) );
|
buffer = intent.getByteArrayExtra( GAMEDATA_BA );
|
||||||
|
inviteRemote( phone, buffer );
|
||||||
break;
|
break;
|
||||||
case ADDED_MISSING:
|
case ADDED_MISSING:
|
||||||
NetLaunchInfo nli
|
NetLaunchInfo nli
|
||||||
|
@ -360,7 +359,7 @@ public class SMSService extends XWService {
|
||||||
break;
|
break;
|
||||||
case RESEND:
|
case RESEND:
|
||||||
phone = intent.getStringExtra( PHONE );
|
phone = intent.getStringExtra( PHONE );
|
||||||
resendFor( phone, null, false );
|
resendFor( phone );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,100 +374,59 @@ public class SMSService extends XWService {
|
||||||
return result;
|
return result;
|
||||||
} // onStartCommand
|
} // onStartCommand
|
||||||
|
|
||||||
private void inviteRemote( String phone, String nliData )
|
private void inviteRemote( String phone, byte[] asBytes )
|
||||||
{
|
{
|
||||||
Log.i( TAG, "inviteRemote()" );
|
resendFor( phone, SMS_CMD.INVITE, 0, asBytes, true );
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
|
||||||
DataOutputStream dos = new DataOutputStream( bas );
|
|
||||||
try {
|
|
||||||
dos.writeUTF( nliData );
|
|
||||||
dos.flush();
|
|
||||||
|
|
||||||
send( SMS_CMD.INVITE, bas.toByteArray(), phone );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Log.ex( TAG, ioe );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ackInvite( String phone, int gameID )
|
private void ackInvite( String phone, int gameID )
|
||||||
{
|
{
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
resendFor( phone, SMS_CMD.ACK_INVITE, gameID, null );
|
||||||
DataOutputStream dos = new DataOutputStream( bas );
|
|
||||||
try {
|
|
||||||
dos.writeInt( gameID );
|
|
||||||
dos.flush();
|
|
||||||
|
|
||||||
send( SMS_CMD.ACK, bas.toByteArray(), phone );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Log.ex( TAG, ioe );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDiedPacket( String phone, int gameID )
|
private void sendDiedPacket( String phone, int gameID )
|
||||||
{
|
{
|
||||||
if ( !s_sentDied.contains(gameID) ) {
|
if ( !s_sentDied.contains(gameID) ) {
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 32 );
|
resendFor( phone, SMS_CMD.DEATH, gameID, null );
|
||||||
DataOutputStream dos = new DataOutputStream( bas );
|
|
||||||
try {
|
|
||||||
dos.writeInt( gameID );
|
|
||||||
dos.flush();
|
|
||||||
send( SMS_CMD.DEATH, bas.toByteArray(), phone );
|
|
||||||
s_sentDied.add( gameID );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Log.ex( TAG, ioe );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sendPacket( String phone, int gameID, byte[] bytes )
|
public int sendPacket( String phone, int gameID, byte[] bytes )
|
||||||
{
|
{
|
||||||
int nSent = -1;
|
resendFor( phone, SMS_CMD.DATA, gameID, bytes );
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
return bytes.length;
|
||||||
DataOutputStream dos = new DataOutputStream( bas );
|
|
||||||
try {
|
|
||||||
dos.writeInt( gameID );
|
|
||||||
dos.write( bytes, 0, bytes.length );
|
|
||||||
dos.flush();
|
|
||||||
send( SMS_CMD.DATA, bas.toByteArray(), phone );
|
|
||||||
nSent = bytes.length;
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Log.ex( TAG, ioe );
|
|
||||||
}
|
|
||||||
return nSent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send( SMS_CMD cmd, byte[] bytes, String phone )
|
private void sendOrRetry( byte[][] msgs, String toPhone, int waitSecs )
|
||||||
throws java.io.IOException
|
|
||||||
{
|
{
|
||||||
Log.d( TAG, "send(%s, len=%d)", cmd, bytes.length );
|
if ( null != msgs ) {
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
sendBuffers( msgs, toPhone );
|
||||||
DataOutputStream dos = new DataOutputStream( bas );
|
|
||||||
dos.writeByte( SMS_PROTO_VERSION );
|
|
||||||
if ( SMS_PROTO_VERSION_WITHPORT <= SMS_PROTO_VERSION ) {
|
|
||||||
dos.writeShort( getNBSPort() );
|
|
||||||
}
|
}
|
||||||
dos.writeByte( cmd.ordinal() );
|
if ( waitSecs > 0 ) {
|
||||||
dos.write( bytes, 0, bytes.length );
|
postResend( toPhone, waitSecs );
|
||||||
dos.flush();
|
}
|
||||||
|
}
|
||||||
byte[] data = bas.toByteArray();
|
|
||||||
|
|
||||||
|
private void resendFor( String toPhone, SMS_CMD cmd, int gameID, byte[] data )
|
||||||
|
{
|
||||||
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( this );
|
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( this );
|
||||||
boolean forceNow = !newSMSEnabled; // || cmd == SMS_CMD.INVITE;
|
boolean forceNow = !newSMSEnabled; // || cmd == SMS_CMD.INVITE;
|
||||||
resendFor( phone, data, forceNow );
|
resendFor( toPhone, cmd, gameID, data, forceNow );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resendFor( String phone, byte[] data, boolean forceNow )
|
private void resendFor( String toPhone )
|
||||||
|
{
|
||||||
|
resendFor( toPhone, SMS_CMD.NONE, 0, null, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resendFor( String toPhone, SMS_CMD cmd, int gameID, byte[] data,
|
||||||
|
boolean forceNow )
|
||||||
{
|
{
|
||||||
int[] waitSecs = { 0 };
|
int[] waitSecs = { 0 };
|
||||||
byte[][] msgs = XwJNI.smsproto_prepOutbound( data, phone, forceNow, waitSecs );
|
byte[][] msgs = XwJNI.smsproto_prepOutbound( cmd, gameID, data, toPhone,
|
||||||
if ( null != msgs ) {
|
getNBSPort(), forceNow,
|
||||||
sendBuffers( msgs, phone );
|
waitSecs );
|
||||||
}
|
sendOrRetry( msgs, toPhone, waitSecs[0] );
|
||||||
if ( waitSecs[0] > 0 ) {
|
|
||||||
Assert.assertFalse( forceNow );
|
|
||||||
postResend( phone, waitSecs[0] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postResend( final String phone, final int waitSecs )
|
private void postResend( final String phone, final int waitSecs )
|
||||||
|
@ -492,97 +450,46 @@ public class SMSService extends XWService {
|
||||||
} ).start();
|
} ).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receive( SMS_CMD cmd, byte[] data, String phone )
|
private void receive( SMSProtoMsg msg, String phone )
|
||||||
{
|
{
|
||||||
Log.i( TAG, "receive(cmd=%s)", cmd.toString() );
|
Log.i( TAG, "receive(cmd=%s)", msg.cmd );
|
||||||
DataInputStream dis =
|
switch( msg.cmd ) {
|
||||||
new DataInputStream( new ByteArrayInputStream(data) );
|
case INVITE:
|
||||||
try {
|
makeForInvite( phone, NetLaunchInfo.makeFrom( this, msg.data ) );
|
||||||
switch( cmd ) {
|
break;
|
||||||
case INVITE:
|
case DATA:
|
||||||
String nliData = dis.readUTF();
|
if ( feedMessage( msg.gameID, msg.data, new CommsAddrRec( phone ) ) ) {
|
||||||
makeForInvite( phone, new NetLaunchInfo( this, nliData ) );
|
SMSResendReceiver.resetTimer( this );
|
||||||
break;
|
|
||||||
case DATA:
|
|
||||||
int gameID = dis.readInt();
|
|
||||||
byte[] rest = new byte[dis.available()];
|
|
||||||
dis.readFully( rest );
|
|
||||||
if ( feedMessage( gameID, rest, new CommsAddrRec( phone ) ) ) {
|
|
||||||
SMSResendReceiver.resetTimer( this );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DEATH:
|
|
||||||
gameID = dis.readInt();
|
|
||||||
postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
|
|
||||||
break;
|
|
||||||
case ACK:
|
|
||||||
gameID = dis.readInt();
|
|
||||||
postEvent( MultiEvent.NEWGAME_SUCCESS,
|
|
||||||
gameID );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.w( TAG, "unexpected cmd %s", cmd.toString() );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} catch ( java.io.IOException ioe ) {
|
break;
|
||||||
Log.ex( TAG, ioe );
|
case DEATH:
|
||||||
|
postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
|
||||||
|
break;
|
||||||
|
case ACK_INVITE:
|
||||||
|
postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w( TAG, "unexpected cmd %s", msg.cmd );
|
||||||
|
Assert.assertFalse( BuildConfig.DEBUG );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveBuffer( byte[] buffer, String senderPhone )
|
private void receiveBuffer( byte[] buffer, String senderPhone )
|
||||||
{
|
{
|
||||||
byte[][] msgs = XwJNI.smsproto_prepInbound( buffer, senderPhone );
|
SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( buffer, senderPhone,
|
||||||
|
getNBSPort() );
|
||||||
if ( null != msgs ) {
|
if ( null != msgs ) {
|
||||||
for ( byte[] msg : msgs ) {
|
for ( SMSProtoMsg msg : msgs ) {
|
||||||
if ( !disAssemble( senderPhone, msg ) ) {
|
receive( msg, senderPhone );
|
||||||
Log.e( TAG, "failed on message from %s", senderPhone );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
postEvent( MultiEvent.SMS_RECEIVE_OK );
|
postEvent( MultiEvent.SMS_RECEIVE_OK );
|
||||||
} else {
|
} else {
|
||||||
Log.w( TAG, "receiveBuffer(): bogus or incomplete message from phone %s",
|
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
|
||||||
senderPhone );
|
senderPhone );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean disAssemble( String senderPhone, byte[] fullMsg )
|
|
||||||
{
|
|
||||||
boolean success = false;
|
|
||||||
DataInputStream dis =
|
|
||||||
new DataInputStream( new ByteArrayInputStream(fullMsg) );
|
|
||||||
try {
|
|
||||||
byte proto = dis.readByte();
|
|
||||||
short myPort = getNBSPort();
|
|
||||||
short gotPort;
|
|
||||||
if ( SMS_PROTO_VERSION_WITHPORT > proto ) {
|
|
||||||
gotPort = myPort;
|
|
||||||
} else {
|
|
||||||
gotPort = dis.readShort();
|
|
||||||
}
|
|
||||||
if ( SMS_PROTO_VERSION < proto ) {
|
|
||||||
Log.w( TAG, "SMSService.disAssemble: bad proto %d from %s;"
|
|
||||||
+ " dropping", proto, senderPhone );
|
|
||||||
postEvent( MultiEvent.BAD_PROTO_SMS, senderPhone );
|
|
||||||
} else if ( gotPort != myPort ) {
|
|
||||||
Log.d( TAG, "disAssemble(): received on port %d"
|
|
||||||
+ " but expected %d", gotPort, myPort );
|
|
||||||
} else {
|
|
||||||
SMS_CMD cmd = SMS_CMD.values()[dis.readByte()];
|
|
||||||
byte[] rest = new byte[dis.available()];
|
|
||||||
dis.readFully( rest );
|
|
||||||
receive( cmd, rest, senderPhone );
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Log.ex( TAG, ioe );
|
|
||||||
} catch ( ArrayIndexOutOfBoundsException oob ) {
|
|
||||||
// enum this older code doesn't know about, or just another app's
|
|
||||||
// message; drop it
|
|
||||||
Log.w( TAG, "disAssemble: dropping message with too-new enum" );
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void postNotification( String phone, int gameID, long rowid )
|
protected void postNotification( String phone, int gameID, long rowid )
|
||||||
{
|
{
|
||||||
|
@ -594,7 +501,8 @@ public class SMSService extends XWService {
|
||||||
|
|
||||||
private void makeForInvite( String phone, NetLaunchInfo nli )
|
private void makeForInvite( String phone, NetLaunchInfo nli )
|
||||||
{
|
{
|
||||||
if ( handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS ) ) {
|
if ( nli != null ) {
|
||||||
|
handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
|
||||||
ackInvite( phone, nli.gameID() );
|
ackInvite( phone, nli.gameID() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,18 @@ public class TilePickAlert extends XWDialogFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel( DialogInterface dialog )
|
||||||
|
{
|
||||||
|
super.onCancel( dialog );
|
||||||
|
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if ( activity instanceof DlgClickNotify ) {
|
||||||
|
DlgClickNotify notify = (DlgClickNotify)activity;
|
||||||
|
notify.onDismissed( m_action );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onDone()
|
private void onDone()
|
||||||
{
|
{
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
|
|
|
@ -760,7 +760,7 @@ public class WiDirService extends XWService {
|
||||||
{
|
{
|
||||||
Log.d( TAG, "handleGotInvite()" );
|
Log.d( TAG, "handleGotInvite()" );
|
||||||
String nliData = intent.getStringExtra( KEY_NLI );
|
String nliData = intent.getStringExtra( KEY_NLI );
|
||||||
NetLaunchInfo nli = new NetLaunchInfo( this, nliData );
|
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliData );
|
||||||
String returnMac = intent.getStringExtra( KEY_SRC );
|
String returnMac = intent.getStringExtra( KEY_SRC );
|
||||||
|
|
||||||
if ( !handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) {
|
if ( !handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) {
|
||||||
|
@ -774,6 +774,12 @@ public class WiDirService extends XWService {
|
||||||
Log.e( TAG, "postNotification() doing nothing" );
|
Log.e( TAG, "postNotification() doing nothing" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MultiMsgSink getSink( long rowid )
|
||||||
|
{
|
||||||
|
return m_sink;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleGameGone( Intent intent )
|
private void handleGameGone( Intent intent )
|
||||||
{
|
{
|
||||||
int gameID = intent.getIntExtra( KEY_GAMEID, 0 );
|
int gameID = intent.getIntExtra( KEY_GAMEID, 0 );
|
||||||
|
|
|
@ -71,8 +71,6 @@ public class XWApp extends Application {
|
||||||
Log.i( TAG, "onCreate(); git_rev=%s", getString( R.string.git_rev ) );
|
Log.i( TAG, "onCreate(); git_rev=%s", getString( R.string.git_rev ) );
|
||||||
DbgUtils.logEnable( this );
|
DbgUtils.logEnable( this );
|
||||||
|
|
||||||
ConnStatusHandler.loadState( this );
|
|
||||||
|
|
||||||
OnBootReceiver.startTimers( this );
|
OnBootReceiver.startTimers( this );
|
||||||
|
|
||||||
boolean mustCheck = Utils.firstBootThisVersion( this );
|
boolean mustCheck = Utils.firstBootThisVersion( this );
|
||||||
|
|
|
@ -89,6 +89,7 @@ abstract class XWService extends Service {
|
||||||
|
|
||||||
abstract void postNotification( String device, int gameID, long rowid );
|
abstract void postNotification( String device, int gameID, long rowid );
|
||||||
|
|
||||||
|
// Return true if able to start game only
|
||||||
protected boolean handleInvitation( NetLaunchInfo nli, String device,
|
protected boolean handleInvitation( NetLaunchInfo nli, String device,
|
||||||
DictFetchOwner dfo )
|
DictFetchOwner dfo )
|
||||||
{
|
{
|
||||||
|
@ -110,6 +111,7 @@ abstract class XWService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
postNotification( device, nli.gameID(), rowid );
|
postNotification( device, nli.gameID(), rowid );
|
||||||
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
Intent intent = MultiService
|
Intent intent = MultiService
|
||||||
.makeMissingDictIntent( this, nli, dfo );
|
.makeMissingDictIntent( this, nli, dfo );
|
||||||
|
@ -118,6 +120,7 @@ abstract class XWService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.d( TAG, "handleInvitation() => %b", success );
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +133,7 @@ abstract class XWService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meant to be overridden
|
// Meant to be overridden
|
||||||
protected MultiMsgSink getSink( long rowid ) { Assert.fail(); return null; }
|
abstract MultiMsgSink getSink( long rowid );
|
||||||
|
|
||||||
protected ReceiveResult receiveMessage( Context context, int gameID,
|
protected ReceiveResult receiveMessage( Context context, int gameID,
|
||||||
MultiMsgSink sink, byte[] msg,
|
MultiMsgSink sink, byte[] msg,
|
||||||
|
|
|
@ -403,17 +403,25 @@ public class XwJNI {
|
||||||
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
|
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
|
||||||
boolean send );
|
boolean send );
|
||||||
|
|
||||||
public static byte[][] smsproto_prepOutbound( byte[] buf, String phone, boolean forceNow,
|
public enum SMS_CMD { NONE, INVITE, DATA, DEATH, ACK_INVITE, };
|
||||||
/*out*/ int[] waitSecs )
|
public static class SMSProtoMsg {
|
||||||
{
|
public SMS_CMD cmd;
|
||||||
int nowSeconds = (int)(System.currentTimeMillis() / 1000);
|
public int gameID;
|
||||||
return smsproto_prepOutbound( getJNI().m_ptr, buf, phone, nowSeconds,
|
public byte[] data; // other cases
|
||||||
forceNow, waitSecs );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[][] smsproto_prepInbound( byte[] data, String fromPhone )
|
public static byte[][]
|
||||||
|
smsproto_prepOutbound( SMS_CMD cmd, int gameID, byte[] buf, String phone,
|
||||||
|
int port, boolean forceNow, /*out*/ int[] waitSecs )
|
||||||
{
|
{
|
||||||
return smsproto_prepInbound( getJNI().m_ptr, data, fromPhone );
|
return smsproto_prepOutbound( getJNI().m_ptr, cmd, gameID, buf, phone,
|
||||||
|
port, forceNow, waitSecs );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SMSProtoMsg[] smsproto_prepInbound( byte[] data,
|
||||||
|
String fromPhone, int wantPort )
|
||||||
|
{
|
||||||
|
return smsproto_prepInbound( getJNI().m_ptr, data, fromPhone, wantPort );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dicts
|
// Dicts
|
||||||
|
@ -502,13 +510,15 @@ public class XwJNI {
|
||||||
private static native int dict_iter_init( int jniState, byte[] dict,
|
private static native int dict_iter_init( int jniState, byte[] dict,
|
||||||
String name, String path );
|
String name, String path );
|
||||||
|
|
||||||
private static native byte[][] smsproto_prepOutbound( int jniState, byte[] buf,
|
private static native byte[][]
|
||||||
String phone, int nowSeconds,
|
smsproto_prepOutbound( int jniState, SMS_CMD cmd, int gameID, byte[] buf,
|
||||||
boolean forceNow,
|
String phone, int port, boolean forceNow,
|
||||||
/*out*/int[] waitSecs );
|
/*out*/int[] waitSecs );
|
||||||
|
|
||||||
private static native byte[][] smsproto_prepInbound( int jniState, byte[] data,
|
private static native SMSProtoMsg[] smsproto_prepInbound( int jniState,
|
||||||
String fromPhone );
|
byte[] data,
|
||||||
|
String fromPhone,
|
||||||
|
int wantPort);
|
||||||
|
|
||||||
private static native boolean haveEnv( int jniState );
|
private static native boolean haveEnv( int jniState );
|
||||||
}
|
}
|
||||||
|
|
|
@ -772,10 +772,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
|
||||||
static jobjectArray
|
static jobjectArray
|
||||||
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
||||||
{
|
{
|
||||||
|
XP_ASSERT( arr->format == FORMAT_NET );
|
||||||
jclass clas = (*env)->FindClass( env, "[B" );
|
jclass clas = (*env)->FindClass( env, "[B" );
|
||||||
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
||||||
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
SMSMsg* msg = &arr->msgs[ii];
|
SMSMsgNet* msg = &arr->u.msgsNet[ii];
|
||||||
jbyteArray arr = makeByteArray( env, msg->len, (const jbyte*)msg->data );
|
jbyteArray arr = makeByteArray( env, msg->len, (const jbyte*)msg->data );
|
||||||
(*env)->SetObjectArrayElement( env, result, ii, arr );
|
(*env)->SetObjectArrayElement( env, result, ii, arr );
|
||||||
deleteLocalRef( env, arr );
|
deleteLocalRef( env, arr );
|
||||||
|
@ -783,15 +784,43 @@ msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static jobjectArray
|
||||||
|
msgArrayToJMsgArray( JNIEnv* env, const SMSMsgArray* arr )
|
||||||
|
{
|
||||||
|
XP_ASSERT( arr->format == FORMAT_LOC );
|
||||||
|
jclass clas = (*env)->FindClass( env, PKG_PATH("jni/XwJNI$SMSProtoMsg") );
|
||||||
|
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
||||||
|
|
||||||
|
jmethodID initId = (*env)->GetMethodID( env, clas, "<init>", "()V" );
|
||||||
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
|
jobject jmsg = (*env)->NewObject( env, clas, initId );
|
||||||
|
|
||||||
|
const SMSMsgLoc* msgsLoc = &arr->u.msgsLoc[ii];
|
||||||
|
intToJenumField( env, jmsg, msgsLoc->cmd, "cmd", PKG_PATH("jni/XwJNI$SMS_CMD") );
|
||||||
|
setInt( env, jmsg, "gameID", msgsLoc->gameID );
|
||||||
|
|
||||||
|
jbyteArray arr = makeByteArray( env, msgsLoc->len,
|
||||||
|
(const jbyte*)msgsLoc->data );
|
||||||
|
setObject( env, jmsg, "data", "[B", arr );
|
||||||
|
deleteLocalRef( env, arr );
|
||||||
|
|
||||||
|
(*env)->SetObjectArrayElement( env, result, ii, jmsg );
|
||||||
|
deleteLocalRef( env, jmsg );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
||||||
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
( JNIEnv* env, jclass C, jint jniGlobalPtr, jobject jCmd, jint jGameID,
|
||||||
jstring jToPhone, jint jNow, jboolean jForce, jintArray jWaitSecsArr )
|
jbyteArray jData, jstring jToPhone, jint jPort, jboolean jForce,
|
||||||
|
jintArray jWaitSecsArr )
|
||||||
{
|
{
|
||||||
jobjectArray result = NULL;
|
jobjectArray result = NULL;
|
||||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||||
map_thread( &globalState->ti, env );
|
map_thread( &globalState->ti, env );
|
||||||
|
|
||||||
|
SMS_CMD cmd = jEnumToInt( env, jCmd );
|
||||||
jbyte* data = NULL;
|
jbyte* data = NULL;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
if ( NULL != jData ) {
|
if ( NULL != jData ) {
|
||||||
|
@ -801,8 +830,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
||||||
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
|
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
|
||||||
|
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, (const XP_U8*)data,
|
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, cmd, jGameID,
|
||||||
len, toPhone, jForce, &waitSecs );
|
(const XP_U8*)data, len,
|
||||||
|
toPhone, jPort, jForce, &waitSecs );
|
||||||
if ( !!arr ) {
|
if ( !!arr ) {
|
||||||
result = msgArrayToByteArrays( env, arr );
|
result = msgArrayToByteArrays( env, arr );
|
||||||
smsproto_freeMsgArray( globalState->smsProto, arr );
|
smsproto_freeMsgArray( globalState->smsProto, arr );
|
||||||
|
@ -821,21 +851,22 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
|
||||||
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
||||||
jstring jFromPhone )
|
jstring jFromPhone, jint jWantPort )
|
||||||
{
|
{
|
||||||
jobjectArray result = NULL;
|
jobjectArray result = NULL;
|
||||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
||||||
map_thread( &globalState->ti, env );
|
|
||||||
|
|
||||||
if ( !!jData ) {
|
if ( !!jData ) {
|
||||||
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||||
|
map_thread( &globalState->ti, env );
|
||||||
|
|
||||||
int len = (*env)->GetArrayLength( env, jData );
|
int len = (*env)->GetArrayLength( env, jData );
|
||||||
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
|
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
|
||||||
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
|
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
|
||||||
|
|
||||||
SMSMsgArray* arr = smsproto_prepInbound( globalState->smsProto, fromPhone,
|
SMSMsgArray* arr = smsproto_prepInbound( globalState->smsProto, fromPhone,
|
||||||
(XP_U8*)data, len );
|
jWantPort, (XP_U8*)data, len );
|
||||||
if ( !!arr ) {
|
if ( !!arr ) {
|
||||||
result = msgArrayToByteArrays( env, arr );
|
result = msgArrayToJMsgArray( env, arr );
|
||||||
smsproto_freeMsgArray( globalState->smsProto, arr );
|
smsproto_freeMsgArray( globalState->smsProto, arr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
xwords4/android/scripts/build-install-rel.sh
Executable file
36
xwords4/android/scripts/build-install-rel.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e -u
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
[ $# -gt 0 ] && echo "ERROR: $1"
|
||||||
|
echo "usage: $0 [--clean|--help]"
|
||||||
|
|
||||||
|
echo "meant for rapid work where a release build's required, this"
|
||||||
|
echo "builds, signs, and installs a Rel build of the xw4 variant"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEAN=''
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case $1 in
|
||||||
|
--clean)
|
||||||
|
CLEAN=clean
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage "unexpected command $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
cd $(dirname $0)/..
|
||||||
|
pwd
|
||||||
|
|
||||||
|
./gradlew $CLEAN asXw4Rel
|
||||||
|
./scripts/sign-align.sh --apk $(find app/build -name '*xw4-release-unsigned-*.apk')
|
||||||
|
adb install -r $(find app/build -name '*xw4-release-signed-*.apk')
|
|
@ -3,24 +3,31 @@
|
||||||
set -e -u
|
set -e -u
|
||||||
|
|
||||||
NODE=xw4
|
NODE=xw4
|
||||||
|
VARIANT=xw4
|
||||||
CLASSPATH=${CLASSPATH:-""}
|
CLASSPATH=${CLASSPATH:-""}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
[ $# -gt 0 ] && echo "Error: $1"
|
[ $# -gt 0 ] && echo "Error: $1"
|
||||||
echo "usage: $0 "
|
echo "usage: $0 [--variant xw4|xw4d]"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
--help) usage
|
--help)
|
||||||
;;
|
usage
|
||||||
*) usage "unexpected flag $1"
|
;;
|
||||||
;;
|
--variant)
|
||||||
|
VARIANT=$2
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage "unexpected flag $1"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
cd $(dirname $0)/../app/build/intermediates/classes/${NODE}/debug
|
cd $(dirname $0)/../app/build/intermediates/classes/${VARIANT}/debug
|
||||||
|
|
||||||
javah -o /tmp/javah$$.txt org.eehouse.android.${NODE}.jni.XwJNI
|
javah -o /tmp/javah$$.txt org.eehouse.android.${NODE}.jni.XwJNI
|
||||||
javap -s org.eehouse.android.${NODE}.jni.XwJNI
|
javap -s org.eehouse.android.${NODE}.jni.XwJNI
|
||||||
|
|
|
@ -36,10 +36,11 @@ echo "# Generated by $0; do not edit!!!" > $TMP_MK
|
||||||
|
|
||||||
[ -n "$USE_CLANG" ] && echo "NDK_TOOLCHAIN_VERSION := clang" >> $TMP_MK
|
[ -n "$USE_CLANG" ] && echo "NDK_TOOLCHAIN_VERSION := clang" >> $TMP_MK
|
||||||
|
|
||||||
|
# TODO: reserach whether armeabi-v7a is better here
|
||||||
if [ -n "$XWORDS_DEBUG_ARMONLY" ]; then
|
if [ -n "$XWORDS_DEBUG_ARMONLY" ]; then
|
||||||
echo "APP_ABI := armeabi-v7a" >> $TMP_MK
|
echo "APP_ABI := armeabi" >> $TMP_MK
|
||||||
elif [ -n "$XWORDS_DEBUG_X86ONLY" ]; then
|
elif [ -n "$XWORDS_DEBUG_X86ONLY" ]; then
|
||||||
echo "APP_ABI := x86" >> $TMP_MK
|
echo "APP_ABI := x86" >> $TMP_MK
|
||||||
else
|
else
|
||||||
echo "APP_ABI := armeabi x86" >> $TMP_MK
|
echo "APP_ABI := armeabi x86" >> $TMP_MK
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -77,6 +77,7 @@ void nli_makeAddrRec( const NetLaunchInfo* invit, CommsAddrRec* addr );
|
||||||
|
|
||||||
void nli_setDevID( NetLaunchInfo* invit, XP_U32 devID );
|
void nli_setDevID( NetLaunchInfo* invit, XP_U32 devID );
|
||||||
void nli_setInviteID( NetLaunchInfo* invit, const XP_UCHAR* inviteID );
|
void nli_setInviteID( NetLaunchInfo* invit, const XP_UCHAR* inviteID );
|
||||||
|
void nli_setGameName( NetLaunchInfo* invit, const XP_UCHAR* gameName );
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -79,6 +79,7 @@ typedef struct ServerVolatiles {
|
||||||
GameOverListener gameOverListener;
|
GameOverListener gameOverListener;
|
||||||
void* gameOverData;
|
void* gameOverData;
|
||||||
XP_Bool showPrevMove;
|
XP_Bool showPrevMove;
|
||||||
|
XP_Bool pickTilesCalled[MAX_NUM_PLAYERS];
|
||||||
} ServerVolatiles;
|
} ServerVolatiles;
|
||||||
|
|
||||||
typedef struct ServerNonvolatiles {
|
typedef struct ServerNonvolatiles {
|
||||||
|
@ -1062,6 +1063,8 @@ server_tilesPicked( ServerCtxt* server, XP_U16 player,
|
||||||
const TrayTileSet* newTilesP )
|
const TrayTileSet* newTilesP )
|
||||||
{
|
{
|
||||||
XP_ASSERT( 0 == model_getNumTilesInTray( server->vol.model, player ) );
|
XP_ASSERT( 0 == model_getNumTilesInTray( server->vol.model, player ) );
|
||||||
|
XP_ASSERT( server->vol.pickTilesCalled[player] );
|
||||||
|
server->vol.pickTilesCalled[player] = XP_FALSE;
|
||||||
|
|
||||||
TrayTileSet newTiles = *newTilesP;
|
TrayTileSet newTiles = *newTilesP;
|
||||||
pool_removeTiles( server->pool, &newTiles );
|
pool_removeTiles( server->pool, &newTiles );
|
||||||
|
@ -1089,12 +1092,19 @@ informNeedPickTiles( ServerCtxt* server, XP_Bool initial, XP_U16 turn,
|
||||||
XP_Bool asking = nToPick > 0;
|
XP_Bool asking = nToPick > 0;
|
||||||
|
|
||||||
if ( asking ) {
|
if ( asking ) {
|
||||||
for ( Tile tile = 0; tile < nFaces; ++tile ) {
|
/* We need to make sure we only call util_informNeedPickTiles once
|
||||||
faces[tile] = dict_getTileString( dict, tile );
|
without it returning. Even if server_do() is called a lot. */
|
||||||
counts[tile] = pool_getNTilesLeftFor( server->pool, tile );
|
if ( server->vol.pickTilesCalled[turn] ) {
|
||||||
|
XP_LOGF( "%s(): already asking for %d", __func__, turn );
|
||||||
|
} else {
|
||||||
|
server->vol.pickTilesCalled[turn] = XP_TRUE;
|
||||||
|
for ( Tile tile = 0; tile < nFaces; ++tile ) {
|
||||||
|
faces[tile] = dict_getTileString( dict, tile );
|
||||||
|
counts[tile] = pool_getNTilesLeftFor( server->pool, tile );
|
||||||
|
}
|
||||||
|
util_informNeedPickTiles( server->vol.util, initial, turn,
|
||||||
|
nToPick, nFaces, faces, counts );
|
||||||
}
|
}
|
||||||
util_informNeedPickTiles( server->vol.util, initial, turn,
|
|
||||||
nToPick, nFaces, faces, counts );
|
|
||||||
}
|
}
|
||||||
return asking;
|
return asking;
|
||||||
}
|
}
|
||||||
|
@ -1923,6 +1933,7 @@ makePoolOnce( ServerCtxt* server )
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
assignTilesToAll( ServerCtxt* server )
|
assignTilesToAll( ServerCtxt* server )
|
||||||
{
|
{
|
||||||
|
LOG_FUNC();
|
||||||
XP_Bool allDone = XP_TRUE;
|
XP_Bool allDone = XP_TRUE;
|
||||||
XP_U16 numAssigned;
|
XP_U16 numAssigned;
|
||||||
XP_U16 ii;
|
XP_U16 ii;
|
||||||
|
@ -1962,6 +1973,7 @@ assignTilesToAll( ServerCtxt* server )
|
||||||
}
|
}
|
||||||
sortTilesIf( server, ii );
|
sortTilesIf( server, ii );
|
||||||
}
|
}
|
||||||
|
LOG_RETURNF( "%d", allDone );
|
||||||
return allDone;
|
return allDone;
|
||||||
} /* assignTilesToAll */
|
} /* assignTilesToAll */
|
||||||
|
|
||||||
|
@ -2466,6 +2478,7 @@ server_commitMove( ServerCtxt* server, TrayTileSet* newTilesP )
|
||||||
XP_ASSERT( turn >= 0 );
|
XP_ASSERT( turn >= 0 );
|
||||||
|
|
||||||
pool_removeTiles( server->pool, &newTiles );
|
pool_removeTiles( server->pool, &newTiles );
|
||||||
|
server->vol.pickTilesCalled[turn] = XP_FALSE;
|
||||||
|
|
||||||
nTilesMoved = model_getCurrentMoveCount( model, turn );
|
nTilesMoved = model_getCurrentMoveCount( model, turn );
|
||||||
fetchTiles( server, turn, nTilesMoved, NULL, &newTiles );
|
fetchTiles( server, turn, nTilesMoved, NULL, &newTiles );
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
/* PENDING: Might want to make SEND_NOW_SIZE smaller; might as well send now
|
/* PENDING: Might want to make SEND_NOW_SIZE smaller; might as well send now
|
||||||
if even the smallest new message is likely to put us over. */
|
if even the smallest new message is likely to put us over. */
|
||||||
# define SEND_NOW_SIZE MAX_LEN_BINARY
|
# define SEND_NOW_SIZE MAX_LEN_BINARY
|
||||||
|
|
||||||
|
/* To match the SMSService format */
|
||||||
|
# define SMS_PROTO_VERSION_JAVA 1
|
||||||
|
|
||||||
# define SMS_PROTO_VERSION 1
|
# define SMS_PROTO_VERSION 1
|
||||||
# define SMS_PROTO_VERSION_COMBO 2
|
# define SMS_PROTO_VERSION_COMBO 2
|
||||||
|
|
||||||
|
@ -38,7 +42,7 @@
|
||||||
|
|
||||||
typedef struct _MsgRec {
|
typedef struct _MsgRec {
|
||||||
XP_U32 createSeconds;
|
XP_U32 createSeconds;
|
||||||
SMSMsg msg;
|
SMSMsgNet msgNet;
|
||||||
} MsgRec;
|
} MsgRec;
|
||||||
|
|
||||||
typedef struct _ToPhoneRec {
|
typedef struct _ToPhoneRec {
|
||||||
|
@ -82,15 +86,18 @@ struct SMSProto {
|
||||||
#define KEY_NEXTID PERSIST_KEY("nextID")
|
#define KEY_NEXTID PERSIST_KEY("nextID")
|
||||||
|
|
||||||
static int nextMsgID( SMSProto* state );
|
static int nextMsgID( SMSProto* state );
|
||||||
static SMSMsgArray* toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld );
|
static XWStreamCtxt* mkStream( SMSProto* state );
|
||||||
|
static SMSMsgArray* toNetMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld );
|
||||||
static ToPhoneRec* getForPhone( SMSProto* state, const XP_UCHAR* phone,
|
static ToPhoneRec* getForPhone( SMSProto* state, const XP_UCHAR* phone,
|
||||||
XP_Bool create );
|
XP_Bool create );
|
||||||
static void addToRec( SMSProto* state, ToPhoneRec* rec, const XP_U8* buf,
|
static void addToOutRec( SMSProto* state, ToPhoneRec* rec, SMS_CMD cmd,
|
||||||
XP_U16 buflen, XP_U32 nowSeconds );
|
XP_U16 port, XP_U32 gameID, const XP_U8* buf,
|
||||||
|
XP_U16 buflen, XP_U32 nowSeconds );
|
||||||
static void addMessage( SMSProto* state, const XP_UCHAR* fromPhone, int msgID,
|
static void addMessage( SMSProto* state, const XP_UCHAR* fromPhone, int msgID,
|
||||||
int indx, int count, const XP_U8* data, XP_U16 len );
|
int indx, int count, const XP_U8* data, XP_U16 len );
|
||||||
static SMSMsgArray* completeMsgs( SMSProto* state, SMSMsgArray* arr,
|
static SMSMsgArray* completeMsgs( SMSProto* state, SMSMsgArray* arr,
|
||||||
const XP_UCHAR* fromPhone, int msgID );
|
const XP_UCHAR* fromPhone, XP_U16 wantPort,
|
||||||
|
int msgID );
|
||||||
static void savePartials( SMSProto* state );
|
static void savePartials( SMSProto* state );
|
||||||
static void restorePartials( SMSProto* state );
|
static void restorePartials( SMSProto* state );
|
||||||
static void rmFromPhoneRec( SMSProto* state, int fromPhoneIndex );
|
static void rmFromPhoneRec( SMSProto* state, int fromPhoneIndex );
|
||||||
|
@ -149,6 +156,48 @@ smsproto_free( SMSProto* state )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
headerToStream( XWStreamCtxt* stream, SMS_CMD cmd, XP_U16 port, XP_U32 gameID )
|
||||||
|
{
|
||||||
|
// XP_LOGF( "%s(cmd: %d; gameID: %d)", __func__, cmd, gameID );
|
||||||
|
stream_putU8( stream, SMS_PROTO_VERSION_JAVA );
|
||||||
|
stream_putU16( stream, port );
|
||||||
|
stream_putU8( stream, cmd );
|
||||||
|
switch ( cmd ) {
|
||||||
|
case NONE:
|
||||||
|
XP_ASSERT(0);
|
||||||
|
break;
|
||||||
|
case INVITE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stream_putU32( stream, gameID );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
headerFromStream( XWStreamCtxt* stream, SMS_CMD* cmd, XP_U16* port, XP_U32* gameID )
|
||||||
|
{
|
||||||
|
XP_Bool success = XP_FALSE;
|
||||||
|
XP_U8 tmp;
|
||||||
|
|
||||||
|
if ( stream_gotU8( stream, &tmp )
|
||||||
|
&& tmp == SMS_PROTO_VERSION_JAVA
|
||||||
|
&& stream_gotU16( stream, port )
|
||||||
|
&& stream_gotU8( stream, &tmp ) ) {
|
||||||
|
*cmd = tmp;
|
||||||
|
switch( *cmd ) {
|
||||||
|
case INVITE:
|
||||||
|
success = XP_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
success = stream_gotU32( stream, gameID );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XP_LOGF( "%s() => cmd: %d; gameID: %d", __func__, *cmd, *gameID );
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/* Maintain a list of pending messages per phone number. When called and it's
|
/* Maintain a list of pending messages per phone number. When called and it's
|
||||||
* been at least some amount of time since we last added something, or at
|
* been at least some amount of time since we last added something, or at
|
||||||
* least some longer time since the oldest message was added, return an array
|
* least some longer time since the oldest message was added, return an array
|
||||||
|
@ -159,26 +208,27 @@ smsproto_free( SMSProto* state )
|
||||||
* UtilCtxt around.
|
* UtilCtxt around.
|
||||||
*/
|
*/
|
||||||
SMSMsgArray*
|
SMSMsgArray*
|
||||||
smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
smsproto_prepOutbound( SMSProto* state, SMS_CMD cmd, XP_U32 gameID,
|
||||||
XP_U16 buflen, const XP_UCHAR* toPhone,
|
const void* buf, XP_U16 buflen, const XP_UCHAR* toPhone,
|
||||||
XP_Bool forceOld, XP_U16* waitSecsP )
|
int toPort, XP_Bool forceOld, XP_U16* waitSecsP )
|
||||||
{
|
{
|
||||||
|
XP_USE( toPort );
|
||||||
SMSMsgArray* result = NULL;
|
SMSMsgArray* result = NULL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
XP_UCHAR* checksum = dutil_md5sum( state->dutil, buf, buflen );
|
XP_UCHAR* checksum = dutil_md5sum( state->dutil, buf, buflen );
|
||||||
XP_LOGF( "%s(): len=%d, sum=%s, toPhone=%s", __func__, buflen,
|
XP_LOGF( "%s(cmd=%d, gameID=%d): len=%d, sum=%s, toPhone=%s", __func__, cmd,
|
||||||
checksum, toPhone );
|
gameID, buflen, checksum, toPhone );
|
||||||
XP_FREEP( state->mpool, &checksum );
|
XP_FREEP( state->mpool, &checksum );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
checkThread( state );
|
checkThread( state );
|
||||||
ToPhoneRec* rec = getForPhone( state, toPhone, !!buf );
|
ToPhoneRec* rec = getForPhone( state, toPhone, cmd != NONE );
|
||||||
|
|
||||||
/* First, add the new message (if present) to the array */
|
/* First, add the new message (if present) to the array */
|
||||||
XP_U32 nowSeconds = dutil_getCurSeconds( state->dutil );
|
XP_U32 nowSeconds = dutil_getCurSeconds( state->dutil );
|
||||||
if ( !!buf ) {
|
if ( cmd != NONE ) {
|
||||||
addToRec( state, rec, buf, buflen, nowSeconds );
|
addToOutRec( state, rec, cmd, toPort, gameID, buf, buflen, nowSeconds );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rec will be non-null if there's something in it */
|
/* rec will be non-null if there's something in it */
|
||||||
|
@ -191,7 +241,7 @@ smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( doSend ) {
|
if ( doSend ) {
|
||||||
result = toMsgs( state, rec, forceOld );
|
result = toNetMsgs( state, rec, forceOld );
|
||||||
freeForPhone( state, toPhone );
|
freeForPhone( state, toPhone );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,27 +257,45 @@ smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
static SMSMsgArray*
|
static SMSMsgArray*
|
||||||
appendMsg( SMSProto* state, SMSMsgArray* arr, SMSMsg* msg )
|
appendLocMsg( SMSProto* state, SMSMsgArray* arr, SMSMsgLoc* msg )
|
||||||
{
|
{
|
||||||
if ( NULL == arr ) {
|
if ( NULL == arr ) {
|
||||||
arr = XP_CALLOC( state->mpool, sizeof(*arr) );
|
arr = XP_CALLOC( state->mpool, sizeof(*arr) );
|
||||||
|
arr->format = FORMAT_LOC;
|
||||||
|
} else {
|
||||||
|
XP_ASSERT( arr->format == FORMAT_LOC );
|
||||||
}
|
}
|
||||||
|
|
||||||
arr->msgs = XP_REALLOC( state->mpool, arr->msgs,
|
arr->u.msgsLoc = XP_REALLOC( state->mpool, arr->u.msgsLoc,
|
||||||
(arr->nMsgs + 1) * sizeof(*arr->msgs) );
|
(arr->nMsgs + 1) * sizeof(*arr->u.msgsLoc) );
|
||||||
arr->msgs[arr->nMsgs++] = *msg;
|
arr->u.msgsLoc[arr->nMsgs++] = *msg;
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SMSMsgArray*
|
||||||
|
appendNetMsg( SMSProto* state, SMSMsgArray* arr, SMSMsgNet* msg )
|
||||||
|
{
|
||||||
|
if ( NULL == arr ) {
|
||||||
|
arr = XP_CALLOC( state->mpool, sizeof(*arr) );
|
||||||
|
arr->format = FORMAT_NET;
|
||||||
|
} else {
|
||||||
|
XP_ASSERT( arr->format == FORMAT_NET );
|
||||||
|
}
|
||||||
|
|
||||||
|
arr->u.msgsNet = XP_REALLOC( state->mpool, arr->u.msgsNet,
|
||||||
|
(arr->nMsgs + 1) * sizeof(*arr->u.msgsNet) );
|
||||||
|
arr->u.msgsNet[arr->nMsgs++] = *msg;
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMSMsgArray*
|
SMSMsgArray*
|
||||||
smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
||||||
const XP_U8* data, XP_U16 len )
|
XP_U16 wantPort, const XP_U8* data, XP_U16 len )
|
||||||
{
|
{
|
||||||
XP_LOGF( "%s(): len=%d, fromPhone=%s", __func__, len, fromPhone );
|
XP_LOGF( "%s(): len=%d, fromPhone=%s", __func__, len, fromPhone );
|
||||||
checkThread( state );
|
checkThread( state );
|
||||||
|
|
||||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
XWStreamCtxt* stream = mkStream( state );
|
||||||
dutil_getVTManager(state->dutil) );
|
|
||||||
stream_putBytes( stream, data, len );
|
stream_putBytes( stream, data, len );
|
||||||
|
|
||||||
SMSMsgArray* result = NULL;
|
SMSMsgArray* result = NULL;
|
||||||
|
@ -244,7 +312,7 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
||||||
XP_U8 buf[len];
|
XP_U8 buf[len];
|
||||||
stream_getBytes( stream, buf, len );
|
stream_getBytes( stream, buf, len );
|
||||||
addMessage( state, fromPhone, msgID, indx, count, buf, len );
|
addMessage( state, fromPhone, msgID, indx, count, buf, len );
|
||||||
result = completeMsgs( state, result, fromPhone, msgID );
|
result = completeMsgs( state, result, fromPhone, wantPort, msgID );
|
||||||
savePartials( state );
|
savePartials( state );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,19 +321,39 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
||||||
XP_U8 oneLen, msgID;
|
XP_U8 oneLen, msgID;
|
||||||
while ( stream_gotU8( stream, &oneLen )
|
while ( stream_gotU8( stream, &oneLen )
|
||||||
&& stream_gotU8( stream, &msgID ) ) {
|
&& stream_gotU8( stream, &msgID ) ) {
|
||||||
XP_U8 buf[oneLen];
|
XP_U8 tmp[oneLen];
|
||||||
if ( stream_gotBytes( stream, buf, oneLen ) ) {
|
stream_getBytes( stream, tmp, oneLen );
|
||||||
SMSMsg msg = { .len = oneLen,
|
|
||||||
.msgID = msgID,
|
XWStreamCtxt* msgStream = mkStream( state );
|
||||||
.data = XP_MALLOC( state->mpool, oneLen ),
|
stream_putBytes( msgStream, tmp, oneLen );
|
||||||
};
|
|
||||||
XP_MEMCPY( msg.data, buf, oneLen );
|
XP_U32 gameID;
|
||||||
result = appendMsg( state, result, &msg );
|
XP_U16 port;
|
||||||
|
SMS_CMD cmd;
|
||||||
|
if ( headerFromStream( msgStream, &cmd, &port, &gameID ) ) {
|
||||||
|
XP_U16 msgLen = stream_getSize( msgStream );
|
||||||
|
XP_U8 buf[msgLen];
|
||||||
|
if ( stream_gotBytes( msgStream, buf, msgLen ) ) {
|
||||||
|
if ( port == wantPort ) {
|
||||||
|
SMSMsgLoc msg = { .len = msgLen,
|
||||||
|
.cmd = cmd,
|
||||||
|
.gameID = gameID,
|
||||||
|
.data = XP_MALLOC( state->mpool, msgLen ),
|
||||||
|
};
|
||||||
|
XP_MEMCPY( msg.data, buf, msgLen );
|
||||||
|
result = appendLocMsg( state, result, &msg );
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "%s(): expected port %d, got %d", __func__,
|
||||||
|
wantPort, port );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
stream_destroy( msgStream );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
/* Don't assert! happens all the time */
|
||||||
XP_LOGF( "%s(): unexpected proto %d", __func__, proto );
|
XP_LOGF( "%s(): unexpected proto %d", __func__, proto );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -283,17 +371,31 @@ smsproto_freeMsgArray( SMSProto* state, SMSMsgArray* arr )
|
||||||
checkThread( state );
|
checkThread( state );
|
||||||
|
|
||||||
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
XP_FREEP( state->mpool, &arr->msgs[ii].data );
|
XP_U8** ptr = arr->format == FORMAT_LOC
|
||||||
|
? &arr->u.msgsLoc[ii].data : &arr->u.msgsNet[ii].data;
|
||||||
|
XP_FREEP( state->mpool, ptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_FREEP( state->mpool, &arr->msgs );
|
void** ptr;
|
||||||
|
switch( arr->format ) {
|
||||||
|
case FORMAT_LOC:
|
||||||
|
ptr = (void**)&arr->u.msgsLoc;
|
||||||
|
break;
|
||||||
|
case FORMAT_NET:
|
||||||
|
ptr = (void**)&arr->u.msgsNet;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XP_ASSERT(0);
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
XP_FREEP( state->mpool, ptr );
|
||||||
XP_FREEP( state->mpool, &arr );
|
XP_FREEP( state->mpool, &arr );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
freeMsg( SMSProto* state, MsgRec** msgp )
|
freeMsg( SMSProto* state, MsgRec** msgp )
|
||||||
{
|
{
|
||||||
XP_FREEP( state->mpool, &(*msgp)->msg.data );
|
XP_FREEP( state->mpool, &(*msgp)->msgNet.data );
|
||||||
XP_FREEP( state->mpool, msgp );
|
XP_FREEP( state->mpool, msgp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,20 +455,28 @@ freeForPhone( SMSProto* state, const XP_UCHAR* phone )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
addToRec( SMSProto* state, ToPhoneRec* rec, const XP_U8* buf, XP_U16 buflen,
|
addToOutRec( SMSProto* state, ToPhoneRec* rec, SMS_CMD cmd,
|
||||||
XP_U32 nowSeconds )
|
XP_U16 port, XP_U32 gameID, const XP_U8* buf, XP_U16 buflen,
|
||||||
|
XP_U32 nowSeconds )
|
||||||
{
|
{
|
||||||
|
XWStreamCtxt* stream = mkStream( state );
|
||||||
|
headerToStream( stream, cmd, port, gameID );
|
||||||
|
stream_putBytes( stream, buf, buflen );
|
||||||
|
|
||||||
MsgRec* mRec = XP_CALLOC( state->mpool, sizeof(*rec) );
|
MsgRec* mRec = XP_CALLOC( state->mpool, sizeof(*rec) );
|
||||||
mRec->msg.len = buflen;
|
XP_U16 len = stream_getSize( stream );
|
||||||
mRec->msg.data = XP_MALLOC( state->mpool, buflen );
|
mRec->msgNet.len = len;
|
||||||
XP_MEMCPY( mRec->msg.data, buf, buflen );
|
mRec->msgNet.data = XP_MALLOC( state->mpool, len );
|
||||||
|
XP_MEMCPY( mRec->msgNet.data, stream_getPtr(stream), len );
|
||||||
|
stream_destroy( stream );
|
||||||
|
|
||||||
mRec->createSeconds = nowSeconds;
|
mRec->createSeconds = nowSeconds;
|
||||||
|
|
||||||
rec->msgs = XP_REALLOC( state->mpool, rec->msgs, (1 + rec->nMsgs) * sizeof(*rec->msgs) );
|
rec->msgs = XP_REALLOC( state->mpool, rec->msgs, (1 + rec->nMsgs) * sizeof(*rec->msgs) );
|
||||||
rec->msgs[rec->nMsgs++] = mRec;
|
rec->msgs[rec->nMsgs++] = mRec;
|
||||||
rec->totalSize += buflen;
|
rec->totalSize += len;
|
||||||
XP_LOGF( "%s(): added msg to %s of len %d; total now %d", __func__, rec->phone,
|
XP_LOGF( "%s(): added msg to %s of len %d; total now %d", __func__, rec->phone,
|
||||||
buflen, rec->totalSize );
|
len, rec->totalSize );
|
||||||
|
|
||||||
if ( rec->nMsgs == 1 ) {
|
if ( rec->nMsgs == 1 ) {
|
||||||
rec->createSeconds = nowSeconds;
|
rec->createSeconds = nowSeconds;
|
||||||
|
@ -513,9 +623,7 @@ savePartials( SMSProto* state )
|
||||||
{
|
{
|
||||||
checkThread( state );
|
checkThread( state );
|
||||||
|
|
||||||
XWStreamCtxt* stream
|
XWStreamCtxt* stream = mkStream( state );
|
||||||
= mem_stream_make_raw( MPPARM(state->mpool)
|
|
||||||
dutil_getVTManager(state->dutil) );
|
|
||||||
stream_putU8( stream, PARTIALS_FORMAT );
|
stream_putU8( stream, PARTIALS_FORMAT );
|
||||||
|
|
||||||
stream_putU8( stream, state->nFromPhones );
|
stream_putU8( stream, state->nFromPhones );
|
||||||
|
@ -553,8 +661,8 @@ savePartials( SMSProto* state )
|
||||||
static void
|
static void
|
||||||
restorePartials( SMSProto* state )
|
restorePartials( SMSProto* state )
|
||||||
{
|
{
|
||||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
XWStreamCtxt* stream = mkStream( state );
|
||||||
dutil_getVTManager(state->dutil) );
|
|
||||||
dutil_loadStream( state->dutil, KEY_PARTIALS, stream );
|
dutil_loadStream( state->dutil, KEY_PARTIALS, stream );
|
||||||
if ( stream_getSize( stream ) >= 1
|
if ( stream_getSize( stream ) >= 1
|
||||||
&& PARTIALS_FORMAT == stream_getU8( stream ) ) {
|
&& PARTIALS_FORMAT == stream_getU8( stream ) ) {
|
||||||
|
@ -585,7 +693,7 @@ restorePartials( SMSProto* state )
|
||||||
|
|
||||||
static SMSMsgArray*
|
static SMSMsgArray*
|
||||||
completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
||||||
int msgID )
|
XP_U16 wantPort, int msgID )
|
||||||
{
|
{
|
||||||
int fromPhoneIndex, msgIDIndex;
|
int fromPhoneIndex, msgIDIndex;
|
||||||
MsgIDRec* rec = getMsgIDRec( state, fromPhone, msgID, XP_FALSE,
|
MsgIDRec* rec = getMsgIDRec( state, fromPhone, msgID, XP_FALSE,
|
||||||
|
@ -607,16 +715,30 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( haveAll ) {
|
if ( haveAll ) {
|
||||||
SMSMsg msg = { .len = len,
|
XWStreamCtxt* stream = mkStream( state );
|
||||||
.msgID = msgID,
|
|
||||||
.data = XP_MALLOC( state->mpool, len ),
|
|
||||||
};
|
|
||||||
XP_U8* ptr = msg.data;
|
|
||||||
for ( int ii = 0; ii < rec->count; ++ii ) {
|
for ( int ii = 0; ii < rec->count; ++ii ) {
|
||||||
XP_MEMCPY( ptr, rec->parts[ii].data, rec->parts[ii].len );
|
stream_putBytes( stream, rec->parts[ii].data, rec->parts[ii].len );
|
||||||
ptr += rec->parts[ii].len;
|
|
||||||
}
|
}
|
||||||
arr = appendMsg( state, arr, &msg );
|
|
||||||
|
XP_U32 gameID;
|
||||||
|
XP_U16 port;
|
||||||
|
SMS_CMD cmd;
|
||||||
|
if ( headerFromStream( stream, &cmd, &port, &gameID ) ) {
|
||||||
|
XP_U16 len = stream_getSize( stream );
|
||||||
|
SMSMsgLoc msg = { .len = len,
|
||||||
|
.cmd = cmd,
|
||||||
|
.gameID = gameID,
|
||||||
|
.data = XP_MALLOC( state->mpool, len ),
|
||||||
|
};
|
||||||
|
if ( stream_gotBytes( stream, msg.data, len ) && port == wantPort ) {
|
||||||
|
arr = appendLocMsg( state, arr, &msg );
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "%s(): expected port %d, got %d", __func__,
|
||||||
|
wantPort, port );
|
||||||
|
XP_FREEP( state->mpool, &msg.data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream_destroy( stream );
|
||||||
|
|
||||||
freeMsgIDRec( state, rec, fromPhoneIndex, msgIDIndex );
|
freeMsgIDRec( state, rec, fromPhoneIndex, msgIDIndex );
|
||||||
}
|
}
|
||||||
|
@ -625,13 +747,13 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
||||||
}
|
}
|
||||||
|
|
||||||
static SMSMsgArray*
|
static SMSMsgArray*
|
||||||
toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
toNetMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||||
{
|
{
|
||||||
SMSMsgArray* result = NULL;
|
SMSMsgArray* result = NULL;
|
||||||
|
|
||||||
for ( XP_U16 ii = 0; ii < rec->nMsgs; ) {
|
for ( XP_U16 ii = 0; ii < rec->nMsgs; ) {
|
||||||
// XP_LOGF( "%s(): looking at msg %d of %d", __func__, ii, rec->nMsgs );
|
// XP_LOGF( "%s(): looking at msg %d of %d", __func__, ii, rec->nMsgs );
|
||||||
XP_U16 count = (rec->msgs[ii]->msg.len + (MAX_LEN_BINARY-1)) / MAX_LEN_BINARY;
|
XP_U16 count = (rec->msgs[ii]->msgNet.len + (MAX_LEN_BINARY-1)) / MAX_LEN_BINARY;
|
||||||
|
|
||||||
/* First, see if this message and some number of its neighbors can be
|
/* First, see if this message and some number of its neighbors can be
|
||||||
combined */
|
combined */
|
||||||
|
@ -639,7 +761,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
if ( count == 1 && !forceOld ) {
|
if ( count == 1 && !forceOld ) {
|
||||||
for ( ; last < rec->nMsgs; ++last ) {
|
for ( ; last < rec->nMsgs; ++last ) {
|
||||||
int nextLen = rec->msgs[last]->msg.len;
|
int nextLen = rec->msgs[last]->msgNet.len;
|
||||||
if ( sum + nextLen > MAX_LEN_BINARY ) {
|
if ( sum + nextLen > MAX_LEN_BINARY ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -654,23 +776,23 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||||
last - 1, nMsgs );
|
last - 1, nMsgs );
|
||||||
}
|
}
|
||||||
int len = 1 + sum + (nMsgs * 2); /* 1: len & msgID */
|
int len = 1 + sum + (nMsgs * 2); /* 1: len & msgID */
|
||||||
SMSMsg newMsg = { .len = len,
|
SMSMsgNet newMsg = { .len = len,
|
||||||
.data = XP_MALLOC( state->mpool, len )
|
.data = XP_MALLOC( state->mpool, len )
|
||||||
};
|
};
|
||||||
int indx = 0;
|
int indx = 0;
|
||||||
newMsg.data[indx++] = SMS_PROTO_VERSION_COMBO;
|
newMsg.data[indx++] = SMS_PROTO_VERSION_COMBO;
|
||||||
for ( int jj = ii; jj < last; ++jj ) {
|
for ( int jj = ii; jj < last; ++jj ) {
|
||||||
const SMSMsg* msg = &rec->msgs[jj]->msg;
|
const SMSMsgNet* msg = &rec->msgs[jj]->msgNet;
|
||||||
newMsg.data[indx++] = msg->len;
|
newMsg.data[indx++] = msg->len;
|
||||||
newMsg.data[indx++] = nextMsgID( state );
|
newMsg.data[indx++] = nextMsgID( state );
|
||||||
XP_MEMCPY( &newMsg.data[indx], msg->data, msg->len ); /* bad! */
|
XP_MEMCPY( &newMsg.data[indx], msg->data, msg->len ); /* bad! */
|
||||||
indx += msg->len;
|
indx += msg->len;
|
||||||
}
|
}
|
||||||
result = appendMsg( state, result, &newMsg );
|
result = appendNetMsg( state, result, &newMsg );
|
||||||
ii = last;
|
ii = last;
|
||||||
} else {
|
} else {
|
||||||
int msgID = nextMsgID( state );
|
int msgID = nextMsgID( state );
|
||||||
const SMSMsg* msg = &rec->msgs[ii]->msg;
|
const SMSMsgNet* msg = &rec->msgs[ii]->msgNet;
|
||||||
XP_U8* nextStart = msg->data;
|
XP_U8* nextStart = msg->data;
|
||||||
XP_U16 lenLeft = msg->len;
|
XP_U16 lenLeft = msg->len;
|
||||||
for ( XP_U16 indx = 0; indx < count; ++indx ) {
|
for ( XP_U16 indx = 0; indx < count; ++indx ) {
|
||||||
|
@ -681,8 +803,8 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||||
}
|
}
|
||||||
lenLeft -= useLen;
|
lenLeft -= useLen;
|
||||||
|
|
||||||
SMSMsg newMsg = { .len = useLen + 4,
|
SMSMsgNet newMsg = { .len = useLen + 4,
|
||||||
.data = XP_MALLOC( state->mpool, useLen + 4 )
|
.data = XP_MALLOC( state->mpool, useLen + 4 )
|
||||||
};
|
};
|
||||||
newMsg.data[0] = SMS_PROTO_VERSION;
|
newMsg.data[0] = SMS_PROTO_VERSION;
|
||||||
newMsg.data[1] = msgID;
|
newMsg.data[1] = msgID;
|
||||||
|
@ -691,7 +813,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||||
XP_MEMCPY( newMsg.data + 4, nextStart, useLen );
|
XP_MEMCPY( newMsg.data + 4, nextStart, useLen );
|
||||||
nextStart += useLen;
|
nextStart += useLen;
|
||||||
|
|
||||||
result = appendMsg( state, result, &newMsg );
|
result = appendNetMsg( state, result, &newMsg );
|
||||||
}
|
}
|
||||||
++ii;
|
++ii;
|
||||||
}
|
}
|
||||||
|
@ -710,6 +832,14 @@ nextMsgID( SMSProto* state )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static XWStreamCtxt*
|
||||||
|
mkStream( SMSProto* state )
|
||||||
|
{
|
||||||
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
||||||
|
dutil_getVTManager(state->dutil) );
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void
|
static void
|
||||||
checkThread( SMSProto* state )
|
checkThread( SMSProto* state )
|
||||||
|
@ -745,17 +875,19 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop until all the messages are ready. */
|
/* Loop until all the messages are ready. */
|
||||||
|
const XP_U32 gameID = 12344321;
|
||||||
|
const int port = 1;
|
||||||
for ( XP_Bool firstTime = XP_TRUE; ; firstTime = XP_FALSE) {
|
for ( XP_Bool firstTime = XP_TRUE; ; firstTime = XP_FALSE) {
|
||||||
XP_Bool allDone = XP_TRUE;
|
XP_Bool allDone = XP_TRUE;
|
||||||
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
if ( firstTime ) {
|
if ( firstTime ) {
|
||||||
XP_U16 len = (ii + 1) * 30;
|
XP_U16 len = (ii + 1) * 30;
|
||||||
arrs[ii] = smsproto_prepOutbound( state, (XP_U8*)buf, len, phones[ii],
|
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, buf, len, phones[ii],
|
||||||
forceOld, &waitSecs );
|
port, forceOld, &waitSecs );
|
||||||
} else if ( NULL == arrs[ii]) {
|
} else if ( NULL == arrs[ii]) {
|
||||||
arrs[ii] = smsproto_prepOutbound( state, NULL, 0, phones[ii],
|
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, NULL, 0, phones[ii],
|
||||||
forceOld, &waitSecs );
|
port, forceOld, &waitSecs );
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -772,13 +904,17 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
||||||
XP_Bool haveOne = XP_FALSE;
|
XP_Bool haveOne = XP_FALSE;
|
||||||
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
||||||
if (!!arrs[ii] && indx < arrs[ii]->nMsgs) {
|
if (!!arrs[ii] && indx < arrs[ii]->nMsgs) {
|
||||||
|
XP_ASSERT( arrs[ii]->format == FORMAT_NET );
|
||||||
haveOne = XP_TRUE;
|
haveOne = XP_TRUE;
|
||||||
SMSMsgArray* outArr = smsproto_prepInbound( state, phones[ii],
|
SMSMsgArray* outArr = smsproto_prepInbound( state, phones[ii], port,
|
||||||
arrs[ii]->msgs[indx].data,
|
arrs[ii]->u.msgsNet[indx].data,
|
||||||
arrs[ii]->msgs[indx].len );
|
arrs[ii]->u.msgsNet[indx].len );
|
||||||
if ( !!outArr ) {
|
if ( !!outArr ) {
|
||||||
SMSMsg* msg = &outArr->msgs[0];
|
XP_ASSERT( outArr->format == FORMAT_LOC );
|
||||||
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
SMSMsgLoc* msg = &outArr->u.msgsLoc[0];
|
||||||
|
XP_ASSERT( msg->gameID == gameID );
|
||||||
|
XP_ASSERT( msg->cmd == DATA );
|
||||||
|
// XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
||||||
XP_ASSERT( outArr->nMsgs == 1 );
|
XP_ASSERT( outArr->nMsgs == 1 );
|
||||||
XP_ASSERT( 0 == memcmp(buf, msg->data, (ii + 1) * 30) );
|
XP_ASSERT( 0 == memcmp(buf, msg->data, (ii + 1) * 30) );
|
||||||
smsproto_freeMsgArray( state, outArr );
|
smsproto_freeMsgArray( state, outArr );
|
||||||
|
@ -796,8 +932,8 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
||||||
/* Now let's send a bunch of small messages that should get combined */
|
/* Now let's send a bunch of small messages that should get combined */
|
||||||
for ( int nUsed = 0; ; ++nUsed ) {
|
for ( int nUsed = 0; ; ++nUsed ) {
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
SMSMsgArray* sendArr = smsproto_prepOutbound( state, (XP_U8*)&buf[nUsed],
|
SMSMsgArray* sendArr = smsproto_prepOutbound( state, DATA, gameID, &buf[nUsed],
|
||||||
smallSiz, phones[0],
|
smallSiz, phones[0], port,
|
||||||
XP_FALSE, &waitSecs );
|
XP_FALSE, &waitSecs );
|
||||||
if ( sendArr == NULL ) {
|
if ( sendArr == NULL ) {
|
||||||
XP_LOGF( "%s(): msg[%d] of len %d sent; still not ready", __func__, nUsed, smallSiz );
|
XP_LOGF( "%s(): msg[%d] of len %d sent; still not ready", __func__, nUsed, smallSiz );
|
||||||
|
@ -805,17 +941,21 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_ASSERT( waitSecs == 0 );
|
XP_ASSERT( waitSecs == 0 );
|
||||||
|
XP_ASSERT( sendArr->format == FORMAT_NET );
|
||||||
int totalBack = 0;
|
int totalBack = 0;
|
||||||
for ( int jj = 0; jj < sendArr->nMsgs; ++jj ) {
|
for ( int jj = 0; jj < sendArr->nMsgs; ++jj ) {
|
||||||
SMSMsgArray* recvArr = smsproto_prepInbound( state, phones[0],
|
SMSMsgArray* recvArr = smsproto_prepInbound( state, phones[0], port,
|
||||||
sendArr->msgs[jj].data,
|
sendArr->u.msgsNet[jj].data,
|
||||||
sendArr->msgs[jj].len );
|
sendArr->u.msgsNet[jj].len );
|
||||||
|
|
||||||
if ( !!recvArr ) {
|
if ( !!recvArr ) {
|
||||||
|
XP_ASSERT( recvArr->format == FORMAT_LOC );
|
||||||
XP_LOGF( "%s(): got %d msgs (from %d)", __func__, recvArr->nMsgs, nUsed + 1 );
|
XP_LOGF( "%s(): got %d msgs (from %d)", __func__, recvArr->nMsgs, nUsed + 1 );
|
||||||
for ( int kk = 0; kk < recvArr->nMsgs; ++kk ) {
|
for ( int kk = 0; kk < recvArr->nMsgs; ++kk ) {
|
||||||
SMSMsg* msg = &recvArr->msgs[kk];
|
SMSMsgLoc* msg = &recvArr->u.msgsLoc[kk];
|
||||||
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
// XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
||||||
|
XP_ASSERT( msg->gameID == gameID );
|
||||||
|
XP_ASSERT( msg->cmd == DATA );
|
||||||
XP_ASSERT( msg->len == smallSiz );
|
XP_ASSERT( msg->len == smallSiz );
|
||||||
XP_ASSERT( 0 == memcmp( msg->data, &buf[totalBack], smallSiz ) );
|
XP_ASSERT( 0 == memcmp( msg->data, &buf[totalBack], smallSiz ) );
|
||||||
++totalBack;
|
++totalBack;
|
||||||
|
@ -833,25 +973,55 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
||||||
/* Now let's add a too-long message and unpack only the first part. Make
|
/* Now let's add a too-long message and unpack only the first part. Make
|
||||||
sure it's cleaned up correctly */
|
sure it's cleaned up correctly */
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
SMSMsgArray* arr = smsproto_prepOutbound( state, (XP_U8*)buf, 200, "33333", XP_TRUE, &waitSecs );
|
SMSMsgArray* arr = smsproto_prepOutbound( state, DATA, gameID, buf, 200, "33333",
|
||||||
|
port, XP_TRUE, &waitSecs );
|
||||||
XP_ASSERT( !!arr && arr->nMsgs > 1 );
|
XP_ASSERT( !!arr && arr->nMsgs > 1 );
|
||||||
/* add only part 1 */
|
/* add only part 1 */
|
||||||
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->msgs[0].data, arr->msgs[0].len );
|
SMSMsgArray* out = smsproto_prepInbound( state, "33333", port, arr->u.msgsNet[0].data,
|
||||||
|
arr->u.msgsNet[0].len );
|
||||||
XP_ASSERT( !out );
|
XP_ASSERT( !out );
|
||||||
smsproto_freeMsgArray( state, arr );
|
smsproto_freeMsgArray( state, arr );
|
||||||
|
|
||||||
|
/* Try the no-buffer messages */
|
||||||
|
XP_LOGF( "%s(): trying DEATH", __func__ );
|
||||||
|
arr = smsproto_prepOutbound( state, DEATH, gameID, NULL, 0, "33333",
|
||||||
|
port, XP_TRUE, &waitSecs );
|
||||||
|
XP_ASSERT( arr->format == FORMAT_NET );
|
||||||
|
out = smsproto_prepInbound( state, "33333", port,
|
||||||
|
arr->u.msgsNet[0].data,
|
||||||
|
arr->u.msgsNet[0].len );
|
||||||
|
XP_ASSERT( out->format == FORMAT_LOC );
|
||||||
|
XP_ASSERT( out->u.msgsLoc[0].cmd == DEATH );
|
||||||
|
XP_ASSERT( out->u.msgsLoc[0].gameID == gameID );
|
||||||
|
smsproto_freeMsgArray( state, arr );
|
||||||
|
smsproto_freeMsgArray( state, out );
|
||||||
|
XP_LOGF( "%s(): DEATH checked out", __func__ );
|
||||||
|
|
||||||
|
/* Test port mismatch */
|
||||||
|
arr = smsproto_prepOutbound( state, DEATH, gameID, NULL, 0, "33333",
|
||||||
|
port, XP_TRUE, &waitSecs );
|
||||||
|
XP_ASSERT( arr->format == FORMAT_NET );
|
||||||
|
out = smsproto_prepInbound( state, "33333", port + 1,
|
||||||
|
arr->u.msgsNet[0].data,
|
||||||
|
arr->u.msgsNet[0].len );
|
||||||
|
XP_ASSERT( out == NULL );
|
||||||
|
smsproto_freeMsgArray( state, arr );
|
||||||
|
XP_LOGF( "%s(): mismatched port test done", __func__ );
|
||||||
|
|
||||||
/* now a message that's unpacked across multiple sessions to test store/load */
|
/* now a message that's unpacked across multiple sessions to test store/load */
|
||||||
XP_LOGF( "%s(): testing store/restore", __func__ );
|
XP_LOGF( "%s(): testing store/restore", __func__ );
|
||||||
arr = smsproto_prepOutbound( state, (XP_U8*)buf, 200, "33333", XP_TRUE, &waitSecs );
|
arr = smsproto_prepOutbound( state, DATA, gameID, (XP_U8*)buf, 200, "33333",
|
||||||
|
port, XP_TRUE, &waitSecs );
|
||||||
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->msgs[ii].data,
|
SMSMsgArray* out = smsproto_prepInbound( state, "33333", port,
|
||||||
arr->msgs[ii].len );
|
arr->u.msgsNet[ii].data,
|
||||||
|
arr->u.msgsNet[ii].len );
|
||||||
if ( !!out ) {
|
if ( !!out ) {
|
||||||
XP_ASSERT( out->nMsgs == 1);
|
XP_ASSERT( out->nMsgs == 1);
|
||||||
|
XP_ASSERT( out->format == FORMAT_LOC );
|
||||||
XP_LOGF( "%s(): got the message on the %dth loop", __func__, ii );
|
XP_LOGF( "%s(): got the message on the %dth loop", __func__, ii );
|
||||||
XP_ASSERT( out->msgs[0].len == 200 );
|
XP_ASSERT( out->u.msgsLoc[0].len == 200 );
|
||||||
XP_ASSERT( 0 == memcmp( out->msgs[0].data, buf, 200 ) );
|
XP_ASSERT( 0 == memcmp( out->u.msgsLoc[0].data, buf, 200 ) );
|
||||||
smsproto_freeMsgArray( state, out );
|
smsproto_freeMsgArray( state, out );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,23 +44,44 @@
|
||||||
|
|
||||||
#include "xptypes.h"
|
#include "xptypes.h"
|
||||||
#include "mempool.h" /* debug only */
|
#include "mempool.h" /* debug only */
|
||||||
|
#include "nli.h"
|
||||||
|
|
||||||
typedef struct SMSProto SMSProto;
|
typedef struct SMSProto SMSProto;
|
||||||
|
|
||||||
typedef struct _SMSMsg {
|
typedef enum { NONE, INVITE, DATA, DEATH, ACK_INVITE, } SMS_CMD;
|
||||||
|
|
||||||
|
/* Unpacked/local format with relevant fields exposed */
|
||||||
|
typedef struct _SMSMsgLoc {
|
||||||
|
// XP_U16 msgID;
|
||||||
|
SMS_CMD cmd;
|
||||||
|
XP_U32 gameID;
|
||||||
|
XP_U16 len;
|
||||||
|
XP_U8* data; // will be NetLaunchInfo* if cmd == INVITE
|
||||||
|
} SMSMsgLoc;
|
||||||
|
|
||||||
|
/* Flattened format suitable for transmission over wire. Encapsulates Loc
|
||||||
|
format data */
|
||||||
|
typedef struct _SMSMsgNet {
|
||||||
|
// XP_U16 msgID;
|
||||||
XP_U16 len;
|
XP_U16 len;
|
||||||
XP_U16 msgID;
|
|
||||||
XP_U8* data;
|
XP_U8* data;
|
||||||
} SMSMsg;
|
} SMSMsgNet;
|
||||||
|
|
||||||
|
typedef enum { FORMAT_NONE, FORMAT_LOC, FORMAT_NET } SMS_FORMAT;
|
||||||
|
|
||||||
typedef struct _SMSMsgArray {
|
typedef struct _SMSMsgArray {
|
||||||
XP_U16 nMsgs;
|
XP_U16 nMsgs;
|
||||||
SMSMsg* msgs;
|
SMS_FORMAT format;
|
||||||
|
union {
|
||||||
|
SMSMsgNet* msgsNet;
|
||||||
|
SMSMsgLoc* msgsLoc;
|
||||||
|
} u;
|
||||||
} SMSMsgArray;
|
} SMSMsgArray;
|
||||||
|
|
||||||
struct SMSProto* smsproto_init( MPFORMAL XW_DUtilCtxt* dutil );
|
struct SMSProto* smsproto_init( MPFORMAL XW_DUtilCtxt* dutil );
|
||||||
void smsproto_free( SMSProto* state );
|
void smsproto_free( SMSProto* state );
|
||||||
|
|
||||||
|
|
||||||
/* Return ptr to structure if one's ready to be sent, otherwise null. Caller *
|
/* Return ptr to structure if one's ready to be sent, otherwise null. Caller *
|
||||||
* should interpret null as meaning it's meant to call again. To support that,
|
* should interpret null as meaning it's meant to call again. To support that,
|
||||||
* null buf is legit.
|
* null buf is legit.
|
||||||
|
@ -68,14 +89,16 @@ void smsproto_free( SMSProto* state );
|
||||||
* When send() returns a non-null value, that value must be passed to
|
* When send() returns a non-null value, that value must be passed to
|
||||||
* freeMsgArray() or there will be leakage.
|
* freeMsgArray() or there will be leakage.
|
||||||
*/
|
*/
|
||||||
SMSMsgArray* smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
|
||||||
XP_U16 buflen, const XP_UCHAR* toPhone,
|
SMSMsgArray* smsproto_prepOutbound( SMSProto* state, SMS_CMD cmd,
|
||||||
|
XP_U32 gameID, const void* buf, XP_U16 buflen,
|
||||||
|
const XP_UCHAR* toPhone, int port,
|
||||||
XP_Bool forceOld, XP_U16* waitSecs );
|
XP_Bool forceOld, XP_U16* waitSecs );
|
||||||
|
|
||||||
/* When a message is received, pass it in for reassambly. Non-null return
|
/* When a message is received, pass it in for reassambly. Non-null return
|
||||||
means one or more messages is ready for consumption. */
|
means one or more messages is ready for consumption. */
|
||||||
SMSMsgArray* smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
SMSMsgArray* smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
||||||
const XP_U8* data, XP_U16 len );
|
XP_U16 wantPort, const XP_U8* data, XP_U16 len );
|
||||||
|
|
||||||
void smsproto_freeMsgArray( SMSProto* state, SMSMsgArray* arr );
|
void smsproto_freeMsgArray( SMSProto* state, SMSMsgArray* arr );
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,26 @@ stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr )
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
stream_gotU16( XWStreamCtxt* stream, XP_U16* ptr )
|
||||||
|
{
|
||||||
|
XP_Bool success = sizeof(*ptr) <= stream_getSize( stream );
|
||||||
|
if ( success ) {
|
||||||
|
*ptr = stream_getU16( stream );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
stream_gotU32( XWStreamCtxt* stream, XP_U32* ptr )
|
||||||
|
{
|
||||||
|
XP_Bool success = sizeof(*ptr) <= stream_getSize( stream );
|
||||||
|
if ( success ) {
|
||||||
|
*ptr = stream_getU32( stream );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
XP_Bool
|
XP_Bool
|
||||||
stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len )
|
stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len )
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,8 @@ XP_U16 stringFromStreamHere( XWStreamCtxt* stream, XP_UCHAR* buf, XP_U16 len );
|
||||||
void stringToStream( XWStreamCtxt* stream, const XP_UCHAR* str );
|
void stringToStream( XWStreamCtxt* stream, const XP_UCHAR* str );
|
||||||
|
|
||||||
XP_Bool stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr );
|
XP_Bool stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr );
|
||||||
|
XP_Bool stream_gotU32( XWStreamCtxt* stream, XP_U32* ptr );
|
||||||
|
XP_Bool stream_gotU16( XWStreamCtxt* stream, XP_U16* ptr );
|
||||||
XP_Bool stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len );
|
XP_Bool stream_gotBytes( XWStreamCtxt* stream, void* ptr, XP_U16 len );
|
||||||
|
|
||||||
XP_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr
|
XP_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr
|
||||||
|
|
|
@ -1659,8 +1659,7 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
||||||
gchar gameName[64];
|
gchar gameName[64];
|
||||||
snprintf( gameName, VSIZE(gameName), "Game %d", cGlobals->gi->gameID );
|
snprintf( gameName, VSIZE(gameName), "Game %d", cGlobals->gi->gameID );
|
||||||
|
|
||||||
linux_sms_invite( cGlobals->params, cGlobals->gi, &addr, gameName,
|
linux_sms_invite( cGlobals->params, &nli,
|
||||||
nPlayers, forceChannel,
|
|
||||||
addrs->u.sms.phone, addrs->u.sms.port );
|
addrs->u.sms.phone, addrs->u.sms.port );
|
||||||
}
|
}
|
||||||
if ( 0 != devID || !!relayID ) {
|
if ( 0 != devID || !!relayID ) {
|
||||||
|
|
|
@ -746,26 +746,29 @@ gtkNoticeRcvd( void* closure )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName),
|
/* smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName), */
|
||||||
XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName,
|
/* XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName, */
|
||||||
XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel,
|
/* XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel, */
|
||||||
|
/* const CommsAddrRec* returnAddr ) */
|
||||||
|
smsInviteReceived( void* closure, const NetLaunchInfo* nli,
|
||||||
const CommsAddrRec* returnAddr )
|
const CommsAddrRec* returnAddr )
|
||||||
{
|
{
|
||||||
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
||||||
LaunchParams* params = apg->params;
|
LaunchParams* params = apg->params;
|
||||||
XP_LOGF( "%s(gameName=%s, gameID=%d, dictName=%s, nPlayers=%d, "
|
XP_LOGF( "%s(gameName=%s, gameID=%d, dictName=%s, nPlayers=%d, "
|
||||||
"nHere=%d, forceChannel=%d)", __func__, gameName, gameID, dictName,
|
"nHere=%d, forceChannel=%d)", __func__, nli->gameName,
|
||||||
nPlayers, nHere, forceChannel );
|
nli->gameID, nli->dict, nli->nPlayersT,
|
||||||
|
nli->nPlayersH, nli->forceChannel );
|
||||||
|
|
||||||
CurGameInfo gi = {0};
|
CurGameInfo gi = {0};
|
||||||
gi_copy( MPPARM(params->mpool) &gi, ¶ms->pgi );
|
gi_copy( MPPARM(params->mpool) &gi, ¶ms->pgi );
|
||||||
|
|
||||||
gi_setNPlayers( &gi, nPlayers, nHere );
|
gi_setNPlayers( &gi, nli->nPlayersT, nli->nPlayersH );
|
||||||
gi.gameID = gameID;
|
gi.gameID = nli->gameID;
|
||||||
gi.dictLang = dictLang;
|
gi.dictLang = nli->lang;
|
||||||
gi.forceChannel = forceChannel;
|
gi.forceChannel = nli->forceChannel;
|
||||||
gi.serverRole = SERVER_ISCLIENT; /* recipient of invitation is client */
|
gi.serverRole = SERVER_ISCLIENT; /* recipient of invitation is client */
|
||||||
replaceStringIfDifferent( params->mpool, &gi.dictName, dictName );
|
replaceStringIfDifferent( params->mpool, &gi.dictName, nli->dict );
|
||||||
|
|
||||||
GtkGameGlobals* globals = malloc( sizeof(*globals) );
|
GtkGameGlobals* globals = malloc( sizeof(*globals) );
|
||||||
params->needsNewGame = XP_FALSE;
|
params->needsNewGame = XP_FALSE;
|
||||||
|
|
|
@ -68,12 +68,10 @@ typedef struct _LinSMSData {
|
||||||
SMSProto* protoState;
|
SMSProto* protoState;
|
||||||
} LinSMSData;
|
} LinSMSData;
|
||||||
|
|
||||||
static void doSend( LaunchParams* params, const XP_U8* buf,
|
|
||||||
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
|
|
||||||
XP_U32 gameID );
|
|
||||||
static gboolean retrySend( gpointer data );
|
static gboolean retrySend( gpointer data );
|
||||||
static void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
static void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
|
||||||
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID );
|
XP_U16 waitSecs, const XP_UCHAR* phone, XP_U16 port,
|
||||||
|
XP_U32 gameID );
|
||||||
static gint check_for_files( gpointer data );
|
static gint check_for_files( gpointer data );
|
||||||
static gint check_for_files_once( gpointer data );
|
static gint check_for_files_once( gpointer data );
|
||||||
|
|
||||||
|
@ -85,13 +83,7 @@ formatQueuePath( const XP_UCHAR* phone, XP_U16 port, XP_UCHAR* path,
|
||||||
snprintf( path, pathlen, "%s/%s_%d", SMS_DIR, phone, port );
|
snprintf( path, pathlen, "%s/%s_%d", SMS_DIR, phone, port );
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum { NONE, INVITE, DATA, DEATH, ACK, } SMS_CMD;
|
|
||||||
#define SMS_PROTO_VERSION 0
|
|
||||||
|
|
||||||
|
|
||||||
static LinSMSData* getStorage( LaunchParams* params );
|
static LinSMSData* getStorage( LaunchParams* params );
|
||||||
static void writeHeader( XWStreamCtxt* stream, SMS_CMD cmd );
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lock_queue( LinSMSData* storage )
|
lock_queue( LinSMSData* storage )
|
||||||
|
@ -114,7 +106,7 @@ unlock_queue( LinSMSData* storage )
|
||||||
}
|
}
|
||||||
|
|
||||||
static XP_S16
|
static XP_S16
|
||||||
write_fake_sms( LaunchParams* params, XWStreamCtxt* stream,
|
write_fake_sms( LaunchParams* params, const void* buf, XP_U16 buflen,
|
||||||
const XP_UCHAR* phone, XP_U16 port )
|
const XP_UCHAR* phone, XP_U16 port )
|
||||||
{
|
{
|
||||||
XP_S16 nSent;
|
XP_S16 nSent;
|
||||||
|
@ -122,13 +114,11 @@ write_fake_sms( LaunchParams* params, XWStreamCtxt* stream,
|
||||||
XP_Bool skipWrite = pct < params->smsSendFailPct;
|
XP_Bool skipWrite = pct < params->smsSendFailPct;
|
||||||
|
|
||||||
if ( skipWrite ) {
|
if ( skipWrite ) {
|
||||||
nSent = stream_getSize( stream );
|
nSent = buflen;
|
||||||
XP_LOGF( "%s(): dropping sms msg of len %d to phone %s", __func__,
|
XP_LOGF( "%s(): dropping sms msg of len %d to phone %s", __func__,
|
||||||
nSent, phone );
|
nSent, phone );
|
||||||
} else {
|
} else {
|
||||||
LinSMSData* storage = getStorage( params );
|
LinSMSData* storage = getStorage( params );
|
||||||
const XP_U8* buf = stream_getPtr( stream );
|
|
||||||
XP_U16 buflen = stream_getSize( stream );
|
|
||||||
XP_LOGF( "%s(phone=%s, port=%d, len=%d)", __func__, phone,
|
XP_LOGF( "%s(phone=%s, port=%d, len=%d)", __func__, phone,
|
||||||
port, buflen );
|
port, buflen );
|
||||||
|
|
||||||
|
@ -236,81 +226,38 @@ decodeAndDelete( LinSMSData* storage, const gchar* name,
|
||||||
return nRead;
|
return nRead;
|
||||||
} /* decodeAndDelete */
|
} /* decodeAndDelete */
|
||||||
|
|
||||||
static void
|
|
||||||
dispatch_invite( LinSMSData* storage, XP_U16 XP_UNUSED(proto),
|
|
||||||
XWStreamCtxt* stream, CommsAddrRec* addr )
|
|
||||||
{
|
|
||||||
XP_UCHAR gameName[256];
|
|
||||||
XP_UCHAR dictName[256];
|
|
||||||
|
|
||||||
XP_U32 gameID = stream_getU32( stream );
|
|
||||||
XP_LOGF( "%s: got gameID %d", __func__, gameID );
|
|
||||||
stringFromStreamHere( stream, gameName, VSIZE(gameName) );
|
|
||||||
XP_U32 dictLang = stream_getU32( stream );
|
|
||||||
stringFromStreamHere( stream, dictName, VSIZE(dictName) );
|
|
||||||
XP_U8 nMissing = stream_getU8( stream );
|
|
||||||
XP_U8 nPlayers = stream_getU8( stream );
|
|
||||||
XP_U16 forceChannel = stream_getU8( stream );
|
|
||||||
|
|
||||||
addrFromStream( addr, stream );
|
|
||||||
|
|
||||||
(*storage->procs->inviteReceived)( storage->procClosure, gameName,
|
|
||||||
gameID, dictLang, dictName, nPlayers,
|
|
||||||
nMissing, forceChannel, addr );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dispatch_data( LinSMSData* storage, XP_U16 XP_UNUSED(proto),
|
|
||||||
XWStreamCtxt* stream, const CommsAddrRec* addr )
|
|
||||||
{
|
|
||||||
LOG_FUNC();
|
|
||||||
|
|
||||||
XP_U32 gameID = stream_getU32( stream );
|
|
||||||
XP_U16 len = stream_getSize( stream );
|
|
||||||
XP_U8 data[len];
|
|
||||||
stream_getBytes( stream, data, len );
|
|
||||||
|
|
||||||
const XP_UCHAR* fromPhone = addr->u.sms.phone;
|
|
||||||
SMSMsgArray* arr = smsproto_prepInbound( storage->protoState, fromPhone,
|
|
||||||
data, len );
|
|
||||||
if ( NULL != arr ) {
|
|
||||||
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
|
||||||
SMSMsg* msg = &arr->msgs[ii];
|
|
||||||
(*storage->procs->msgReceived)( storage->procClosure, addr, gameID,
|
|
||||||
msg->data, msg->len );
|
|
||||||
}
|
|
||||||
smsproto_freeMsgArray( storage->protoState, arr );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parseAndDispatch( LaunchParams* params, uint8_t* buf, int len,
|
parseAndDispatch( LaunchParams* params, uint8_t* buf, int len,
|
||||||
CommsAddrRec* addr )
|
CommsAddrRec* addr )
|
||||||
{
|
{
|
||||||
LinSMSData* storage = getStorage( params );
|
LinSMSData* storage = getStorage( params );
|
||||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
const XP_UCHAR* fromPhone = addr->u.sms.phone;
|
||||||
params->vtMgr );
|
SMSMsgArray* arr = smsproto_prepInbound( storage->protoState, fromPhone,
|
||||||
stream_setVersion( stream, CUR_STREAM_VERS );
|
storage->myPort, buf, len );
|
||||||
stream_putBytes( stream, buf, len );
|
if ( NULL != arr ) {
|
||||||
|
XP_ASSERT( arr->format == FORMAT_LOC );
|
||||||
XP_U8 proto = stream_getU8( stream );
|
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
XP_ASSERT( SMS_PROTO_VERSION == proto );
|
SMSMsgLoc* msg = &arr->u.msgsLoc[ii];
|
||||||
XP_U8 cmd = stream_getU8( stream );
|
switch ( msg->cmd ) {
|
||||||
switch( cmd ) {
|
case DATA:
|
||||||
case INVITE:
|
(*storage->procs->msgReceived)( storage->procClosure, addr,
|
||||||
dispatch_invite( storage, proto, stream, addr );
|
msg->gameID,
|
||||||
break;
|
msg->data, msg->len );
|
||||||
case DATA:
|
break;
|
||||||
dispatch_data( storage, proto, stream, addr );
|
case INVITE:
|
||||||
break;
|
(*storage->procs->inviteReceived)( storage->procClosure,
|
||||||
case DEATH:
|
(NetLaunchInfo*)msg->data, addr );
|
||||||
case ACK:
|
/* gameName, */
|
||||||
break;
|
/* gameID, dictLang, dictName, nPlayers, */
|
||||||
default:
|
/* nMissing, forceChannel, addr ); */
|
||||||
XP_ASSERT( 0 );
|
break;
|
||||||
|
default:
|
||||||
|
XP_ASSERT(0); /* implement me!! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
smsproto_freeMsgArray( storage->protoState, arr );
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_destroy( stream );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -341,28 +288,18 @@ linux_sms_init( LaunchParams* params, const gchar* myPhone, XP_U16 myPort,
|
||||||
} /* linux_sms_init */
|
} /* linux_sms_init */
|
||||||
|
|
||||||
void
|
void
|
||||||
linux_sms_invite( LaunchParams* params, const CurGameInfo* gi,
|
linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
|
||||||
const CommsAddrRec* addr, const gchar* gameName,
|
|
||||||
XP_U16 nMissing, int forceChannel,
|
|
||||||
const gchar* toPhone, int toPort )
|
const gchar* toPhone, int toPort )
|
||||||
{
|
{
|
||||||
LOG_FUNC();
|
LOG_FUNC();
|
||||||
XWStreamCtxt* stream;
|
LinSMSData* storage = getStorage( params );
|
||||||
stream = mem_stream_make_raw( MPPARM(params->mpool) params->vtMgr );
|
|
||||||
writeHeader( stream, INVITE );
|
|
||||||
stream_putU32( stream, gi->gameID );
|
|
||||||
stringToStream( stream, gameName );
|
|
||||||
stream_putU32( stream, gi->dictLang );
|
|
||||||
stringToStream( stream, gi->dictName );
|
|
||||||
stream_putU8( stream, nMissing );
|
|
||||||
stream_putU8( stream, gi->nPlayers );
|
|
||||||
stream_putU8( stream, forceChannel );
|
|
||||||
|
|
||||||
addrToStream( stream, addr );
|
XP_U16 waitSecs;
|
||||||
|
SMSMsgArray* arr
|
||||||
write_fake_sms( params, stream, toPhone, toPort );
|
= smsproto_prepOutbound( storage->protoState, INVITE, nli->gameID, nli,
|
||||||
|
sizeof(*nli), toPhone, toPort, XP_FALSE,
|
||||||
stream_destroy( stream );
|
&waitSecs );
|
||||||
|
sendOrRetry( params, arr, INVITE, waitSecs, toPhone, toPort, nli->gameID );
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_S16
|
XP_S16
|
||||||
|
@ -372,43 +309,32 @@ linux_sms_send( LaunchParams* params, const XP_U8* buf,
|
||||||
{
|
{
|
||||||
LinSMSData* storage = getStorage( params );
|
LinSMSData* storage = getStorage( params );
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, buf, buflen,
|
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, DATA, gameID,
|
||||||
phone, XP_TRUE, &waitSecs );
|
buf, buflen, phone, port,
|
||||||
sendOrRetry( params, arr, waitSecs, phone, port, gameID );
|
XP_TRUE, &waitSecs );
|
||||||
|
sendOrRetry( params, arr, DATA, waitSecs, phone, port, gameID );
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
doSend( LaunchParams* params, const XP_U8* buf,
|
|
||||||
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
|
|
||||||
XP_U32 gameID )
|
|
||||||
{
|
|
||||||
XP_LOGF( "%s(len=%d)", __func__, buflen );
|
|
||||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
|
||||||
params->vtMgr );
|
|
||||||
writeHeader( stream, DATA );
|
|
||||||
stream_putU32( stream, gameID );
|
|
||||||
stream_putBytes( stream, buf, buflen );
|
|
||||||
|
|
||||||
(void)write_fake_sms( params, stream, phone, port );
|
|
||||||
stream_destroy( stream );
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _RetryClosure {
|
typedef struct _RetryClosure {
|
||||||
LaunchParams* params;
|
LaunchParams* params;
|
||||||
|
SMS_CMD cmd;
|
||||||
XP_U16 port;
|
XP_U16 port;
|
||||||
XP_U32 gameID;
|
XP_U32 gameID;
|
||||||
XP_UCHAR phone[32];
|
XP_UCHAR phone[32];
|
||||||
} RetryClosure;
|
} RetryClosure;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
|
||||||
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID )
|
XP_U16 waitSecs, const XP_UCHAR* phone, XP_U16 port,
|
||||||
|
XP_U32 gameID )
|
||||||
{
|
{
|
||||||
if ( !!arr ) {
|
if ( !!arr ) {
|
||||||
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||||
SMSMsg* msg = &arr->msgs[ii];
|
const SMSMsgNet* msg = &arr->u.msgsNet[ii];
|
||||||
doSend( params, msg->data, msg->len, phone, port, gameID );
|
// doSend( params, msg->data, msg->len, phone, port, gameID );
|
||||||
|
(void)write_fake_sms( params, msg->data, msg->len,
|
||||||
|
phone, port );
|
||||||
}
|
}
|
||||||
|
|
||||||
LinSMSData* storage = getStorage( params );
|
LinSMSData* storage = getStorage( params );
|
||||||
|
@ -420,6 +346,7 @@ sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
||||||
XP_STRCAT( closure->phone, phone );
|
XP_STRCAT( closure->phone, phone );
|
||||||
closure->port = port;
|
closure->port = port;
|
||||||
closure->gameID = gameID;
|
closure->gameID = gameID;
|
||||||
|
closure->cmd = cmd;
|
||||||
g_timeout_add_seconds( 5, retrySend, closure );
|
g_timeout_add_seconds( 5, retrySend, closure );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,9 +357,11 @@ retrySend( gpointer data )
|
||||||
RetryClosure* closure = (RetryClosure*)data;
|
RetryClosure* closure = (RetryClosure*)data;
|
||||||
LinSMSData* storage = getStorage( closure->params );
|
LinSMSData* storage = getStorage( closure->params );
|
||||||
XP_U16 waitSecs;
|
XP_U16 waitSecs;
|
||||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, NULL, 0,
|
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, closure->cmd,
|
||||||
closure->phone, XP_TRUE, &waitSecs );
|
closure->gameID, NULL, 0,
|
||||||
sendOrRetry( closure->params, arr, waitSecs, closure->phone,
|
closure->phone, closure->port,
|
||||||
|
XP_TRUE, &waitSecs );
|
||||||
|
sendOrRetry( closure->params, arr, closure->cmd, waitSecs, closure->phone,
|
||||||
closure->port, closure->gameID );
|
closure->port, closure->gameID );
|
||||||
XP_FREEP( closure->params->mpool, &closure );
|
XP_FREEP( closure->params->mpool, &closure );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -538,11 +467,4 @@ getStorage( LaunchParams* params )
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
writeHeader( XWStreamCtxt* stream, SMS_CMD cmd )
|
|
||||||
{
|
|
||||||
stream_putU8( stream, SMS_PROTO_VERSION );
|
|
||||||
stream_putU8( stream, cmd );
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* XWFEATURE_SMS */
|
#endif /* XWFEATURE_SMS */
|
||||||
|
|
|
@ -23,12 +23,10 @@
|
||||||
#ifdef XWFEATURE_SMS
|
#ifdef XWFEATURE_SMS
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "nli.h"
|
||||||
|
|
||||||
typedef struct _SMSProcs {
|
typedef struct _SMSProcs {
|
||||||
void (*inviteReceived)( void* closure, const XP_UCHAR* gameName,
|
void (*inviteReceived)( void* closure, const NetLaunchInfo* nli,
|
||||||
XP_U32 gameID, XP_U16 dictLang,
|
|
||||||
const XP_UCHAR* dictName, XP_U16 nPlayers,
|
|
||||||
XP_U16 nHere, XP_U16 forceChannel,
|
|
||||||
const CommsAddrRec* returnAddr );
|
const CommsAddrRec* returnAddr );
|
||||||
void (*msgReceived)( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
void (*msgReceived)( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
||||||
const XP_U8* buf, XP_U16 len );
|
const XP_U8* buf, XP_U16 len );
|
||||||
|
@ -45,9 +43,7 @@ void linux_sms_init( LaunchParams* params, const gchar* phone,
|
||||||
XP_S16 linux_sms_send( LaunchParams* params, const XP_U8* buf,
|
XP_S16 linux_sms_send( LaunchParams* params, const XP_U8* buf,
|
||||||
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
|
XP_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
|
||||||
XP_U32 gameID );
|
XP_U32 gameID );
|
||||||
void linux_sms_invite( LaunchParams* params, const CurGameInfo* info,
|
void linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
|
||||||
const CommsAddrRec* addr, const gchar* gameName,
|
|
||||||
XP_U16 nMissing, int forceChannel,
|
|
||||||
const gchar* phone, int port );
|
const gchar* phone, int port );
|
||||||
void linux_sms_cleanup( LaunchParams* params );
|
void linux_sms_cleanup( LaunchParams* params );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue