mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +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
|
||||
- platform-tools
|
||||
- build-tools-27.0.3
|
||||
- android-26
|
||||
- android-23
|
||||
licenses:
|
||||
- android-sdk-preview-license-.+
|
||||
- android-sdk-license-.+
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
def INITIAL_CLIENT_VERS = 8
|
||||
def VERSION_CODE_BASE = 133
|
||||
def VERSION_NAME = '4.4.137'
|
||||
def VERSION_CODE_BASE = 135
|
||||
def VERSION_NAME = '4.4.139'
|
||||
def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY")
|
||||
def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID")
|
||||
def BUILD_INFO_NAME = "build-info.txt"
|
||||
|
@ -33,7 +33,7 @@ android {
|
|||
buildToolsVersion '27.0.3'
|
||||
defaultConfig {
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 26
|
||||
targetSdkVersion 23
|
||||
versionCode VERSION_CODE_BASE
|
||||
versionName VERSION_NAME
|
||||
}
|
||||
|
@ -92,7 +92,6 @@ android {
|
|||
}
|
||||
xw4d {
|
||||
dimension "variant"
|
||||
minSdkVersion 8
|
||||
applicationId "org.eehouse.android.xw4dbg"
|
||||
manifestPlaceholders = [ FABRIC_API_KEY: "$FABRIC_API_KEY", APP_ID: applicationId, ]
|
||||
resValue "string", "app_name", "CrossDbg"
|
||||
|
@ -223,7 +222,7 @@ task copyStrings(type: Exec) {
|
|||
|
||||
task ndkSetup(type: Exec) {
|
||||
workingDir '../'
|
||||
commandLine "./scripts/ndksetup.sh", "--with-clang"
|
||||
commandLine "./scripts/ndksetup.sh", "--with-clang", "--arm-only"
|
||||
}
|
||||
|
||||
task myPreBuild(dependsOn: ['ndkSetup', 'mkImages', 'copyStrings', 'mkXml']) {
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
</style>
|
||||
</head>
|
||||
<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">
|
||||
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
||||
|
@ -25,12 +25,10 @@
|
|||
|
||||
<h3>New with this release</h3>
|
||||
<ul>
|
||||
<li>Add new SMS-handling code. One feature isn't compatible with
|
||||
the previous release so it won't be activated until there's been
|
||||
time for everybody to upgrade.</li>
|
||||
<li>Include new Catalan translations</li>
|
||||
<li>Fix bug causing (rarely) unending notifications of wordlist
|
||||
upgrade</li>
|
||||
<li>Don't put up multiple tile pickers. (This feature is rarely
|
||||
used, but had apparently been broken for a while.)</li>
|
||||
<li>Fix two more bugs reported by users (Thanks!)</li>
|
||||
<li>Include new translations for Catalan and Norwegian</li>
|
||||
</ul>
|
||||
|
||||
<p>(The full changelog
|
||||
|
|
|
@ -365,7 +365,7 @@ public class BTService extends XWService {
|
|||
break;
|
||||
case INVITE:
|
||||
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() );
|
||||
String btAddr = intent.getStringExtra( ADDR_KEY );
|
||||
m_sender.add( new BTQueueElem( BTCmd.INVITE, nli, btAddr ) );
|
||||
|
@ -545,7 +545,7 @@ public class BTService extends XWService {
|
|||
NetLaunchInfo nli;
|
||||
if ( BT_PROTO_JSONS == proto ) {
|
||||
String asJson = is.readUTF();
|
||||
nli = new NetLaunchInfo( BTService.this, asJson );
|
||||
nli = NetLaunchInfo.makeFrom( BTService.this, asJson );
|
||||
} else {
|
||||
short len = is.readShort();
|
||||
byte[] nliData = new byte[len];
|
||||
|
@ -1106,11 +1106,17 @@ public class BTService extends XWService {
|
|||
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
|
||||
}
|
||||
|
||||
@Override
|
||||
MultiMsgSink getSink( long rowid )
|
||||
{
|
||||
return m_btMsgSink;
|
||||
}
|
||||
|
||||
private BTCmd makeOrNotify( NetLaunchInfo nli, String btName,
|
||||
String btAddr )
|
||||
{
|
||||
BTCmd result;
|
||||
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) {
|
||||
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) { // here
|
||||
result = BTCmd.INVITE_ACCPT;
|
||||
} else {
|
||||
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
|
||||
|
|
|
@ -115,7 +115,7 @@ public class BoardDelegate extends DelegateBase
|
|||
private BoardUtilCtxt m_utils;
|
||||
private boolean m_gameOver = false;
|
||||
|
||||
private JNIThread m_jniThread;
|
||||
private volatile JNIThread m_jniThread;
|
||||
private JNIThread m_jniThreadRef;
|
||||
private JNIThread.GameStateInfo m_gsi;
|
||||
|
||||
|
@ -136,6 +136,7 @@ public class BoardDelegate extends DelegateBase
|
|||
m_when = when;
|
||||
m_handle = handle;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
m_timers[m_why] = null;
|
||||
if ( null != m_jniThread ) {
|
||||
|
@ -1117,6 +1118,7 @@ public class BoardDelegate extends DelegateBase
|
|||
|
||||
case ENABLE_SMS_DO:
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
retrySMSInvites( params );
|
||||
}
|
||||
|
@ -1164,6 +1166,7 @@ public class BoardDelegate extends DelegateBase
|
|||
case ENABLE_RELAY_DO_OR:
|
||||
if ( m_dropOnDismiss ) {
|
||||
postDelayed( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
askDropRelay();
|
||||
}
|
||||
|
@ -1174,6 +1177,16 @@ public class BoardDelegate extends DelegateBase
|
|||
finish();
|
||||
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:
|
||||
handled = false;
|
||||
}
|
||||
|
@ -1257,17 +1270,20 @@ public class BoardDelegate extends DelegateBase
|
|||
@SuppressWarnings("fallthrough")
|
||||
public void eventOccurred( MultiService.MultiEvent event, final Object ... args )
|
||||
{
|
||||
boolean doStopProgress = false;
|
||||
switch( event ) {
|
||||
case MESSAGE_ACCEPTED:
|
||||
case MESSAGE_REFUSED:
|
||||
ConnStatusHandler.
|
||||
updateStatusIn( m_activity, this, CommsConnType.COMMS_CONN_BT,
|
||||
MultiService.MultiEvent.MESSAGE_ACCEPTED == event);
|
||||
doStopProgress = true;
|
||||
break;
|
||||
case MESSAGE_NOGAME:
|
||||
int gameID = (Integer)args[0];
|
||||
if ( gameID == m_gi.gameID ) {
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showDialogFragment( DlgID.DLG_DELETED );
|
||||
}
|
||||
|
@ -1285,13 +1301,11 @@ public class BoardDelegate extends DelegateBase
|
|||
Log.w( TAG, "failed to create game" );
|
||||
break;
|
||||
case NEWGAME_DUP_REJECTED:
|
||||
if ( m_progressShown ) {
|
||||
m_progressShown = false;
|
||||
stopProgress(); // in case it's a BT invite
|
||||
}
|
||||
doStopProgress = true;
|
||||
final String msg =
|
||||
getString( R.string.err_dup_invite_fmt, (String)args[0] );
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeOkOnlyBuilder( msg ).show();
|
||||
}
|
||||
|
@ -1311,13 +1325,15 @@ public class BoardDelegate extends DelegateBase
|
|||
break;
|
||||
|
||||
default:
|
||||
if ( m_progressShown ) {
|
||||
m_progressShown = false;
|
||||
stopProgress(); // in case it's a BT invite
|
||||
}
|
||||
doStopProgress = true; // in case it's a BT invite
|
||||
super.eventOccurred( event, args );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( doStopProgress && m_progressShown ) {
|
||||
m_progressShown = false;
|
||||
stopProgress();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
@ -1328,6 +1344,7 @@ public class BoardDelegate extends DelegateBase
|
|||
final boolean allHere, final int nMissing )
|
||||
{
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleConndMessage( room, devOrder, allHere, nMissing ); // from here too
|
||||
}
|
||||
|
@ -1381,6 +1398,7 @@ public class BoardDelegate extends DelegateBase
|
|||
final int strIDf = strID;
|
||||
final DlgID dlgIDf = dlgID;
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showDialogFragment( dlgIDf, R.string.relay_alert,
|
||||
getString( strIDf ) );
|
||||
|
@ -1397,6 +1415,7 @@ public class BoardDelegate extends DelegateBase
|
|||
{
|
||||
if ( success ) {
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setGotGameDict( name );
|
||||
}
|
||||
|
@ -1452,6 +1471,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void invalidateParent()
|
||||
{
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_view.invalidate();
|
||||
}
|
||||
|
@ -1462,6 +1482,7 @@ public class BoardDelegate extends DelegateBase
|
|||
{
|
||||
final String msg = ConnStatusHandler.getStatusText( m_activity, m_connTypes );
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ( null == msg ) {
|
||||
askNoAddrsDelete();
|
||||
|
@ -1627,6 +1648,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void requestTime()
|
||||
{
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ( null != m_jniThread ) {
|
||||
m_jniThread.handleBkgrnd( JNICmd.CMD_DO );
|
||||
|
@ -1678,6 +1700,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( 0 != id ) {
|
||||
final String bonusStr = getString( id );
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showToast( bonusStr );
|
||||
}
|
||||
|
@ -1696,6 +1719,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
final String text = expl;
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showToast( text );
|
||||
}
|
||||
|
@ -1706,6 +1730,7 @@ public class BoardDelegate extends DelegateBase
|
|||
public void cellSquareHeld( final String words )
|
||||
{
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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
|
||||
@Override
|
||||
public void notifyPickTileBlank( int playerNum, int col, int row,
|
||||
String[] texts )
|
||||
{
|
||||
final TilePickAlert.TilePickState tps =
|
||||
TilePickAlert.TilePickState tps =
|
||||
new TilePickAlert.TilePickState( playerNum, texts, col, row );
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
show( TilePickAlert.newInstance( Action.BLANK_PICKED, tps ) );
|
||||
}
|
||||
} );
|
||||
startTP( Action.BLANK_PICKED, tps );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1764,15 +1795,10 @@ public class BoardDelegate extends DelegateBase
|
|||
int playerNum, int nToPick,
|
||||
String[] texts, int[] counts )
|
||||
{
|
||||
final TilePickAlert.TilePickState tps
|
||||
TilePickAlert.TilePickState tps
|
||||
= new TilePickAlert.TilePickState( isInitial, playerNum, nToPick,
|
||||
texts, counts );
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
show( TilePickAlert.newInstance( Action.TRAY_PICKED, tps ) );
|
||||
}
|
||||
} );
|
||||
startTP( Action.TRAY_PICKED, tps );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1787,6 +1813,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( 0 <= newTurn ) {
|
||||
m_mySIS.nMissing = 0;
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeNotAgainBuilder( R.string.not_again_turnchanged,
|
||||
R.string.key_notagain_turnchanged )
|
||||
|
@ -1801,7 +1828,9 @@ public class BoardDelegate extends DelegateBase
|
|||
@Override
|
||||
public boolean engineProgressCallback()
|
||||
{
|
||||
return ! m_jniThread.busy();
|
||||
// return true if engine should keep going
|
||||
JNIThread jnit = m_jniThread;
|
||||
return jnit != null && !jnit.busy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1879,6 +1908,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( asToast ) {
|
||||
final int residf = resid;
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showToast( residf );
|
||||
}
|
||||
|
@ -2021,6 +2051,7 @@ public class BoardDelegate extends DelegateBase
|
|||
String fromPlayer, final int tsSeconds )
|
||||
{
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DBUtils.appendChatHistory( m_activity, m_rowid, msg,
|
||||
fromIndx, tsSeconds );
|
||||
|
@ -2543,6 +2574,7 @@ public class BoardDelegate extends DelegateBase
|
|||
if ( keepOn ) {
|
||||
if ( null == m_screenTimer ) {
|
||||
m_screenTimer = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ( null != m_view ) {
|
||||
m_view.setKeepScreenOn( false );
|
||||
|
|
|
@ -126,8 +126,6 @@ public class ConnStatusHandler {
|
|||
|
||||
private ConnStatusHandler() {}
|
||||
|
||||
private static HashMap<CommsConnType,SuccessRecord[]> s_records =
|
||||
new HashMap<CommsConnType,SuccessRecord[]>();
|
||||
private static boolean s_needsSave = false;
|
||||
|
||||
public static void setRect( int left, int top, int right, int bottom )
|
||||
|
@ -184,7 +182,7 @@ public class ConnStatusHandler {
|
|||
typ.longName( context ), did ) );
|
||||
|
||||
// For sends we list failures too.
|
||||
SuccessRecord record = recordFor( typ, false );
|
||||
SuccessRecord record = recordFor( context, typ, false );
|
||||
tmp = LocUtils.getString( context, record.successNewer?
|
||||
R.string.connstat_succ :
|
||||
R.string.connstat_unsucc );
|
||||
|
@ -214,7 +212,7 @@ public class ConnStatusHandler {
|
|||
}
|
||||
sb.append( "\n" );
|
||||
|
||||
record = recordFor( typ, true );
|
||||
record = recordFor( context, typ, true );
|
||||
if ( record.haveSuccess() ) {
|
||||
sb.append( LocUtils.getString( context,
|
||||
R.string.connstat_lastreceipt_fmt,
|
||||
|
@ -264,7 +262,7 @@ public class ConnStatusHandler {
|
|||
}
|
||||
|
||||
synchronized( ConnStatusHandler.class ) {
|
||||
SuccessRecord record = recordFor( connType, isIn );
|
||||
SuccessRecord record = recordFor( context, connType, isIn );
|
||||
record.update( success );
|
||||
}
|
||||
invalidateParent();
|
||||
|
@ -306,14 +304,14 @@ public class ConnStatusHandler {
|
|||
|
||||
// Do the background coloring and arrow. Top half first
|
||||
scratchR.bottom -= (2 * quarterHeight);
|
||||
fillHalf( canvas, scratchR, connTypes, enabled, false );
|
||||
fillHalf( context, canvas, scratchR, connTypes, enabled, false );
|
||||
scratchR.bottom -= quarterHeight;
|
||||
drawArrow( canvas, res, scratchR, false );
|
||||
|
||||
// bottom half and arrow
|
||||
scratchR.top = s_rect.top + (2 * quarterHeight);
|
||||
scratchR.bottom = s_rect.bottom;
|
||||
fillHalf( canvas, scratchR, connTypes, enabled, true );
|
||||
fillHalf( context, canvas, scratchR, connTypes, enabled, true );
|
||||
scratchR.top += quarterHeight;
|
||||
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,
|
||||
boolean isIn )
|
||||
{
|
||||
enabled = enabled && null != newestSuccess( connTypes, isIn );
|
||||
enabled = enabled && null != newestSuccess( context, connTypes, isIn );
|
||||
s_fillPaint.setColor( enabled ? XWApp.GREEN : XWApp.RED );
|
||||
canvas.drawRect( rect, s_fillPaint );
|
||||
}
|
||||
|
@ -359,20 +357,24 @@ public class ConnStatusHandler {
|
|||
// This gets rid of lint warning, but I don't like it as it
|
||||
// effects the whole method.
|
||||
// @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 ) {
|
||||
s_records = null;
|
||||
if ( s_records == null ) {
|
||||
String as64 = XWPrefs.getPrefsString( context,
|
||||
R.string.key_connstat_data );
|
||||
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[]>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return s_records;
|
||||
}
|
||||
|
||||
private static void saveState( final Context context,
|
||||
ConnStatusCBacks cbcks )
|
||||
|
@ -440,7 +442,8 @@ public class ConnStatusHandler {
|
|||
icon.draw( canvas );
|
||||
}
|
||||
|
||||
private static SuccessRecord newestSuccess( CommsConnTypeSet connTypes,
|
||||
private static SuccessRecord newestSuccess( Context context,
|
||||
CommsConnTypeSet connTypes,
|
||||
boolean isIn )
|
||||
{
|
||||
SuccessRecord result = null;
|
||||
|
@ -448,7 +451,7 @@ public class ConnStatusHandler {
|
|||
Iterator<CommsConnType> iter = connTypes.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
CommsConnType connType = iter.next();
|
||||
SuccessRecord record = recordFor( connType, isIn );
|
||||
SuccessRecord record = recordFor( context, connType, isIn );
|
||||
if ( record.successNewer ) {
|
||||
if ( null == result || result.lastSuccess < record.lastSuccess ) {
|
||||
result = record;
|
||||
|
@ -459,14 +462,16 @@ public class ConnStatusHandler {
|
|||
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 ) {
|
||||
records = new SuccessRecord[] { new SuccessRecord(),
|
||||
new SuccessRecord(),
|
||||
};
|
||||
s_records.put( connType, records );
|
||||
getRecords( context ).put( connType, records );
|
||||
}
|
||||
return records[isIn?0:1];
|
||||
}
|
||||
|
@ -474,7 +479,7 @@ public class ConnStatusHandler {
|
|||
private static void doSave( Context context )
|
||||
{
|
||||
synchronized( ConnStatusHandler.class ) {
|
||||
String as64 = Utils.serializableToString64( s_records );
|
||||
String as64 = Utils.serializableToString64( getRecords( context ) );
|
||||
XWPrefs.setPrefsString( context, R.string.key_connstat_data,
|
||||
as64 );
|
||||
s_needsSave = false;
|
||||
|
|
|
@ -1183,7 +1183,9 @@ public class GameUtils {
|
|||
boolean informNow )
|
||||
{
|
||||
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;
|
||||
|
||||
GamePtr gamePtr = loadMakeGame( context, lock );
|
||||
|
|
|
@ -2260,7 +2260,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
{
|
||||
String data = NFCUtils.getFromIntent( intent );
|
||||
if ( null != data ) {
|
||||
NetLaunchInfo nli = new NetLaunchInfo( m_activity, data );
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( m_activity, data );
|
||||
if ( nli.isValid() ) {
|
||||
startNewNetGame( nli );
|
||||
}
|
||||
|
|
|
@ -149,7 +149,8 @@ public class MultiService {
|
|||
{
|
||||
Assert.assertTrue( isMissingDictIntent( intent ) );
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
* rights reserved.
|
||||
* Copyright 2009 - 2018 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* 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.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.Serializable;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
@ -90,7 +95,7 @@ public class NetLaunchInfo implements Serializable {
|
|||
inviteID = GameUtils.formatGameID( Utils.nextRandomInt() );
|
||||
}
|
||||
|
||||
public NetLaunchInfo( Context context, String data )
|
||||
private NetLaunchInfo( Context context, String data ) throws JSONException
|
||||
{
|
||||
init( context, data );
|
||||
}
|
||||
|
@ -128,6 +133,31 @@ public class NetLaunchInfo implements Serializable {
|
|||
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 )
|
||||
{
|
||||
this();
|
||||
|
@ -422,10 +452,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
return result;
|
||||
}
|
||||
|
||||
private void init( Context context, String data )
|
||||
private void init( Context context, String data ) throws JSONException
|
||||
{
|
||||
CommsConnTypeSet supported = CommsConnTypeSet.getSupported( context );
|
||||
try {
|
||||
JSONObject json = new JSONObject( data );
|
||||
|
||||
int flags = json.optInt(ADDRS_KEY, -1);
|
||||
|
@ -477,10 +506,6 @@ public class NetLaunchInfo implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
} catch ( JSONException jse ) {
|
||||
Log.ex( TAG, jse );
|
||||
}
|
||||
|
||||
removeUnsupported( supported );
|
||||
|
||||
calcValid();
|
||||
|
@ -589,6 +614,20 @@ public class NetLaunchInfo implements Serializable {
|
|||
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 )
|
||||
{
|
||||
Assert.fail();
|
||||
|
|
|
@ -397,7 +397,7 @@ public class RelayService extends XWService
|
|||
case GOT_INVITE:
|
||||
int srcDevID = intent.getIntExtra( INVITE_FROM, 0 );
|
||||
NetLaunchInfo nli
|
||||
= new NetLaunchInfo( this, intent.getStringExtra(NLI_DATA) );
|
||||
= NetLaunchInfo.makeFrom( this, intent.getStringExtra(NLI_DATA) );
|
||||
receiveInvitation( srcDevID, nli );
|
||||
break;
|
||||
case SEND:
|
||||
|
@ -820,7 +820,7 @@ public class RelayService extends XWService
|
|||
Log.d( TAG, "sendInvitation(%d->%d/%s [%s])", srcDevID, destDevID,
|
||||
relayID, nliStr );
|
||||
|
||||
NetLaunchInfo nli = new NetLaunchInfo( this, nliStr );
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliStr );
|
||||
byte[] nliData = XwJNI.nliToStream( nli );
|
||||
if ( BuildConfig.DEBUG ) {
|
||||
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.CommsConnType;
|
||||
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 java.io.ByteArrayInputStream;
|
||||
|
@ -75,17 +77,13 @@ public class SMSService extends XWService {
|
|||
private static final String BUFFER = "BUFFER";
|
||||
private static final String BINBUFFER = "BINBUFFER";
|
||||
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 =
|
||||
SMSService.class.getName() + "_PHONES";
|
||||
|
||||
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_receiveReceiver;
|
||||
private OnSharedPreferenceChangeListener m_prefsListener;
|
||||
|
@ -195,9 +193,9 @@ public class SMSService extends XWService {
|
|||
{
|
||||
Intent intent = getIntentTo( context, SMSAction.INVITE );
|
||||
intent.putExtra( PHONE, phone );
|
||||
String asString = nli.toString();
|
||||
Log.w( TAG, "inviteRemote(%s, '%s')", phone, asString );
|
||||
intent.putExtra( GAMEDATA_STR, asString );
|
||||
Log.w( TAG, "inviteRemote(%s, '%s')", phone, nli );
|
||||
byte[] data = nli.asByteArray();
|
||||
intent.putExtra( GAMEDATA_BA, data );
|
||||
context.startService( intent );
|
||||
}
|
||||
|
||||
|
@ -339,7 +337,8 @@ public class SMSService extends XWService {
|
|||
break;
|
||||
case INVITE:
|
||||
phone = intent.getStringExtra( PHONE );
|
||||
inviteRemote( phone, intent.getStringExtra( GAMEDATA_STR ) );
|
||||
buffer = intent.getByteArrayExtra( GAMEDATA_BA );
|
||||
inviteRemote( phone, buffer );
|
||||
break;
|
||||
case ADDED_MISSING:
|
||||
NetLaunchInfo nli
|
||||
|
@ -360,7 +359,7 @@ public class SMSService extends XWService {
|
|||
break;
|
||||
case RESEND:
|
||||
phone = intent.getStringExtra( PHONE );
|
||||
resendFor( phone, null, false );
|
||||
resendFor( phone );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,100 +374,59 @@ public class SMSService extends XWService {
|
|||
return result;
|
||||
} // onStartCommand
|
||||
|
||||
private void inviteRemote( String phone, String nliData )
|
||||
private void inviteRemote( String phone, byte[] asBytes )
|
||||
{
|
||||
Log.i( TAG, "inviteRemote()" );
|
||||
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 );
|
||||
}
|
||||
resendFor( phone, SMS_CMD.INVITE, 0, asBytes, true );
|
||||
}
|
||||
|
||||
private void ackInvite( String phone, int gameID )
|
||||
{
|
||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
||||
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 );
|
||||
}
|
||||
resendFor( phone, SMS_CMD.ACK_INVITE, gameID, null );
|
||||
}
|
||||
|
||||
private void sendDiedPacket( String phone, int gameID )
|
||||
{
|
||||
if ( !s_sentDied.contains(gameID) ) {
|
||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 32 );
|
||||
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 );
|
||||
}
|
||||
resendFor( phone, SMS_CMD.DEATH, gameID, null );
|
||||
}
|
||||
}
|
||||
|
||||
public int sendPacket( String phone, int gameID, byte[] bytes )
|
||||
{
|
||||
int nSent = -1;
|
||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
||||
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;
|
||||
resendFor( phone, SMS_CMD.DATA, gameID, bytes );
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
private void send( SMS_CMD cmd, byte[] bytes, String phone )
|
||||
throws java.io.IOException
|
||||
private void sendOrRetry( byte[][] msgs, String toPhone, int waitSecs )
|
||||
{
|
||||
Log.d( TAG, "send(%s, len=%d)", cmd, bytes.length );
|
||||
ByteArrayOutputStream bas = new ByteArrayOutputStream( 128 );
|
||||
DataOutputStream dos = new DataOutputStream( bas );
|
||||
dos.writeByte( SMS_PROTO_VERSION );
|
||||
if ( SMS_PROTO_VERSION_WITHPORT <= SMS_PROTO_VERSION ) {
|
||||
dos.writeShort( getNBSPort() );
|
||||
if ( null != msgs ) {
|
||||
sendBuffers( msgs, toPhone );
|
||||
}
|
||||
if ( waitSecs > 0 ) {
|
||||
postResend( toPhone, waitSecs );
|
||||
}
|
||||
}
|
||||
dos.writeByte( cmd.ordinal() );
|
||||
dos.write( bytes, 0, bytes.length );
|
||||
dos.flush();
|
||||
|
||||
byte[] data = bas.toByteArray();
|
||||
|
||||
private void resendFor( String toPhone, SMS_CMD cmd, int gameID, byte[] data )
|
||||
{
|
||||
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( this );
|
||||
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 };
|
||||
byte[][] msgs = XwJNI.smsproto_prepOutbound( data, phone, forceNow, waitSecs );
|
||||
if ( null != msgs ) {
|
||||
sendBuffers( msgs, phone );
|
||||
}
|
||||
if ( waitSecs[0] > 0 ) {
|
||||
Assert.assertFalse( forceNow );
|
||||
postResend( phone, waitSecs[0] );
|
||||
}
|
||||
byte[][] msgs = XwJNI.smsproto_prepOutbound( cmd, gameID, data, toPhone,
|
||||
getNBSPort(), forceNow,
|
||||
waitSecs );
|
||||
sendOrRetry( msgs, toPhone, waitSecs[0] );
|
||||
}
|
||||
|
||||
private void postResend( final String phone, final int waitSecs )
|
||||
|
@ -492,97 +450,46 @@ public class SMSService extends XWService {
|
|||
} ).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() );
|
||||
DataInputStream dis =
|
||||
new DataInputStream( new ByteArrayInputStream(data) );
|
||||
try {
|
||||
switch( cmd ) {
|
||||
Log.i( TAG, "receive(cmd=%s)", msg.cmd );
|
||||
switch( msg.cmd ) {
|
||||
case INVITE:
|
||||
String nliData = dis.readUTF();
|
||||
makeForInvite( phone, new NetLaunchInfo( this, nliData ) );
|
||||
makeForInvite( phone, NetLaunchInfo.makeFrom( this, msg.data ) );
|
||||
break;
|
||||
case DATA:
|
||||
int gameID = dis.readInt();
|
||||
byte[] rest = new byte[dis.available()];
|
||||
dis.readFully( rest );
|
||||
if ( feedMessage( gameID, rest, new CommsAddrRec( phone ) ) ) {
|
||||
if ( feedMessage( msg.gameID, msg.data, new CommsAddrRec( phone ) ) ) {
|
||||
SMSResendReceiver.resetTimer( this );
|
||||
}
|
||||
break;
|
||||
case DEATH:
|
||||
gameID = dis.readInt();
|
||||
postEvent( MultiEvent.MESSAGE_NOGAME, gameID );
|
||||
postEvent( MultiEvent.MESSAGE_NOGAME, msg.gameID );
|
||||
break;
|
||||
case ACK:
|
||||
gameID = dis.readInt();
|
||||
postEvent( MultiEvent.NEWGAME_SUCCESS,
|
||||
gameID );
|
||||
case ACK_INVITE:
|
||||
postEvent( MultiEvent.NEWGAME_SUCCESS, msg.gameID );
|
||||
break;
|
||||
default:
|
||||
Log.w( TAG, "unexpected cmd %s", cmd.toString() );
|
||||
Log.w( TAG, "unexpected cmd %s", msg.cmd );
|
||||
Assert.assertFalse( BuildConfig.DEBUG );
|
||||
break;
|
||||
}
|
||||
} catch ( java.io.IOException ioe ) {
|
||||
Log.ex( TAG, ioe );
|
||||
}
|
||||
}
|
||||
|
||||
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 ) {
|
||||
for ( byte[] msg : msgs ) {
|
||||
if ( !disAssemble( senderPhone, msg ) ) {
|
||||
Log.e( TAG, "failed on message from %s", senderPhone );
|
||||
}
|
||||
for ( SMSProtoMsg msg : msgs ) {
|
||||
receive( msg, senderPhone );
|
||||
}
|
||||
postEvent( MultiEvent.SMS_RECEIVE_OK );
|
||||
} else {
|
||||
Log.w( TAG, "receiveBuffer(): bogus or incomplete message from phone %s",
|
||||
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
|
||||
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
|
||||
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 )
|
||||
{
|
||||
if ( handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS ) ) {
|
||||
if ( nli != null ) {
|
||||
handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
|
||||
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()
|
||||
{
|
||||
Activity activity = getActivity();
|
||||
|
|
|
@ -760,7 +760,7 @@ public class WiDirService extends XWService {
|
|||
{
|
||||
Log.d( TAG, "handleGotInvite()" );
|
||||
String nliData = intent.getStringExtra( KEY_NLI );
|
||||
NetLaunchInfo nli = new NetLaunchInfo( this, nliData );
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( this, nliData );
|
||||
String returnMac = intent.getStringExtra( KEY_SRC );
|
||||
|
||||
if ( !handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) {
|
||||
|
@ -774,6 +774,12 @@ public class WiDirService extends XWService {
|
|||
Log.e( TAG, "postNotification() doing nothing" );
|
||||
}
|
||||
|
||||
@Override
|
||||
MultiMsgSink getSink( long rowid )
|
||||
{
|
||||
return m_sink;
|
||||
}
|
||||
|
||||
private void handleGameGone( Intent intent )
|
||||
{
|
||||
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 ) );
|
||||
DbgUtils.logEnable( this );
|
||||
|
||||
ConnStatusHandler.loadState( this );
|
||||
|
||||
OnBootReceiver.startTimers( this );
|
||||
|
||||
boolean mustCheck = Utils.firstBootThisVersion( this );
|
||||
|
|
|
@ -89,6 +89,7 @@ abstract class XWService extends Service {
|
|||
|
||||
abstract void postNotification( String device, int gameID, long rowid );
|
||||
|
||||
// Return true if able to start game only
|
||||
protected boolean handleInvitation( NetLaunchInfo nli, String device,
|
||||
DictFetchOwner dfo )
|
||||
{
|
||||
|
@ -110,6 +111,7 @@ abstract class XWService extends Service {
|
|||
}
|
||||
|
||||
postNotification( device, nli.gameID(), rowid );
|
||||
success = true;
|
||||
} else {
|
||||
Intent intent = MultiService
|
||||
.makeMissingDictIntent( this, nli, dfo );
|
||||
|
@ -118,6 +120,7 @@ abstract class XWService extends Service {
|
|||
}
|
||||
}
|
||||
}
|
||||
Log.d( TAG, "handleInvitation() => %b", success );
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -130,7 +133,7 @@ abstract class XWService extends Service {
|
|||
}
|
||||
|
||||
// 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,
|
||||
MultiMsgSink sink, byte[] msg,
|
||||
|
|
|
@ -403,17 +403,25 @@ public class XwJNI {
|
|||
public static native boolean comms_getAddrDisabled( GamePtr gamePtr, CommsConnType typ,
|
||||
boolean send );
|
||||
|
||||
public static byte[][] smsproto_prepOutbound( byte[] buf, String phone, boolean forceNow,
|
||||
/*out*/ int[] waitSecs )
|
||||
{
|
||||
int nowSeconds = (int)(System.currentTimeMillis() / 1000);
|
||||
return smsproto_prepOutbound( getJNI().m_ptr, buf, phone, nowSeconds,
|
||||
forceNow, waitSecs );
|
||||
public enum SMS_CMD { NONE, INVITE, DATA, DEATH, ACK_INVITE, };
|
||||
public static class SMSProtoMsg {
|
||||
public SMS_CMD cmd;
|
||||
public int gameID;
|
||||
public byte[] data; // other cases
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -502,13 +510,15 @@ public class XwJNI {
|
|||
private static native int dict_iter_init( int jniState, byte[] dict,
|
||||
String name, String path );
|
||||
|
||||
private static native byte[][] smsproto_prepOutbound( int jniState, byte[] buf,
|
||||
String phone, int nowSeconds,
|
||||
boolean forceNow,
|
||||
private static native byte[][]
|
||||
smsproto_prepOutbound( int jniState, SMS_CMD cmd, int gameID, byte[] buf,
|
||||
String phone, int port, boolean forceNow,
|
||||
/*out*/int[] waitSecs );
|
||||
|
||||
private static native byte[][] smsproto_prepInbound( int jniState, byte[] data,
|
||||
String fromPhone );
|
||||
private static native SMSProtoMsg[] smsproto_prepInbound( int jniState,
|
||||
byte[] data,
|
||||
String fromPhone,
|
||||
int wantPort);
|
||||
|
||||
private static native boolean haveEnv( int jniState );
|
||||
}
|
||||
|
|
|
@ -772,10 +772,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
|
|||
static jobjectArray
|
||||
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
||||
{
|
||||
XP_ASSERT( arr->format == FORMAT_NET );
|
||||
jclass clas = (*env)->FindClass( env, "[B" );
|
||||
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
||||
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 );
|
||||
(*env)->SetObjectArrayElement( env, result, ii, arr );
|
||||
deleteLocalRef( env, arr );
|
||||
|
@ -783,15 +784,43 @@ msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
|||
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
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
||||
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
||||
jstring jToPhone, jint jNow, jboolean jForce, jintArray jWaitSecsArr )
|
||||
( JNIEnv* env, jclass C, jint jniGlobalPtr, jobject jCmd, jint jGameID,
|
||||
jbyteArray jData, jstring jToPhone, jint jPort, jboolean jForce,
|
||||
jintArray jWaitSecsArr )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
map_thread( &globalState->ti, env );
|
||||
|
||||
SMS_CMD cmd = jEnumToInt( env, jCmd );
|
||||
jbyte* data = NULL;
|
||||
int len = 0;
|
||||
if ( NULL != jData ) {
|
||||
|
@ -801,8 +830,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
|||
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
|
||||
|
||||
XP_U16 waitSecs;
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, (const XP_U8*)data,
|
||||
len, toPhone, jForce, &waitSecs );
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, cmd, jGameID,
|
||||
(const XP_U8*)data, len,
|
||||
toPhone, jPort, jForce, &waitSecs );
|
||||
if ( !!arr ) {
|
||||
result = msgArrayToByteArrays( env, arr );
|
||||
smsproto_freeMsgArray( globalState->smsProto, arr );
|
||||
|
@ -821,21 +851,22 @@ Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
|||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
|
||||
( JNIEnv* env, jclass C, jint jniGlobalPtr, jbyteArray jData,
|
||||
jstring jFromPhone )
|
||||
jstring jFromPhone, jint jWantPort )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
|
||||
if ( !!jData ) {
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
map_thread( &globalState->ti, env );
|
||||
|
||||
if ( !!jData ) {
|
||||
int len = (*env)->GetArrayLength( env, jData );
|
||||
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
|
||||
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
|
||||
|
||||
SMSMsgArray* arr = smsproto_prepInbound( globalState->smsProto, fromPhone,
|
||||
(XP_U8*)data, len );
|
||||
jWantPort, (XP_U8*)data, len );
|
||||
if ( !!arr ) {
|
||||
result = msgArrayToByteArrays( env, arr );
|
||||
result = msgArrayToJMsgArray( env, 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
|
||||
|
||||
NODE=xw4
|
||||
VARIANT=xw4
|
||||
CLASSPATH=${CLASSPATH:-""}
|
||||
|
||||
usage() {
|
||||
[ $# -gt 0 ] && echo "Error: $1"
|
||||
echo "usage: $0 "
|
||||
echo "usage: $0 [--variant xw4|xw4d]"
|
||||
exit 1
|
||||
}
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--help) usage
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*) usage "unexpected flag $1"
|
||||
--variant)
|
||||
VARIANT=$2
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
usage "unexpected flag $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
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
|
||||
javap -s org.eehouse.android.${NODE}.jni.XwJNI
|
||||
|
|
|
@ -36,8 +36,9 @@ echo "# Generated by $0; do not edit!!!" > $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
|
||||
echo "APP_ABI := armeabi-v7a" >> $TMP_MK
|
||||
echo "APP_ABI := armeabi" >> $TMP_MK
|
||||
elif [ -n "$XWORDS_DEBUG_X86ONLY" ]; then
|
||||
echo "APP_ABI := x86" >> $TMP_MK
|
||||
else
|
||||
|
|
|
@ -77,6 +77,7 @@ void nli_makeAddrRec( const NetLaunchInfo* invit, CommsAddrRec* addr );
|
|||
|
||||
void nli_setDevID( NetLaunchInfo* invit, XP_U32 devID );
|
||||
void nli_setInviteID( NetLaunchInfo* invit, const XP_UCHAR* inviteID );
|
||||
void nli_setGameName( NetLaunchInfo* invit, const XP_UCHAR* gameName );
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct ServerVolatiles {
|
|||
GameOverListener gameOverListener;
|
||||
void* gameOverData;
|
||||
XP_Bool showPrevMove;
|
||||
XP_Bool pickTilesCalled[MAX_NUM_PLAYERS];
|
||||
} ServerVolatiles;
|
||||
|
||||
typedef struct ServerNonvolatiles {
|
||||
|
@ -1062,6 +1063,8 @@ server_tilesPicked( ServerCtxt* server, XP_U16 player,
|
|||
const TrayTileSet* newTilesP )
|
||||
{
|
||||
XP_ASSERT( 0 == model_getNumTilesInTray( server->vol.model, player ) );
|
||||
XP_ASSERT( server->vol.pickTilesCalled[player] );
|
||||
server->vol.pickTilesCalled[player] = XP_FALSE;
|
||||
|
||||
TrayTileSet newTiles = *newTilesP;
|
||||
pool_removeTiles( server->pool, &newTiles );
|
||||
|
@ -1089,6 +1092,12 @@ informNeedPickTiles( ServerCtxt* server, XP_Bool initial, XP_U16 turn,
|
|||
XP_Bool asking = nToPick > 0;
|
||||
|
||||
if ( asking ) {
|
||||
/* We need to make sure we only call util_informNeedPickTiles once
|
||||
without it returning. Even if server_do() is called a lot. */
|
||||
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 );
|
||||
|
@ -1096,6 +1105,7 @@ informNeedPickTiles( ServerCtxt* server, XP_Bool initial, XP_U16 turn,
|
|||
util_informNeedPickTiles( server->vol.util, initial, turn,
|
||||
nToPick, nFaces, faces, counts );
|
||||
}
|
||||
}
|
||||
return asking;
|
||||
}
|
||||
|
||||
|
@ -1923,6 +1933,7 @@ makePoolOnce( ServerCtxt* server )
|
|||
static XP_Bool
|
||||
assignTilesToAll( ServerCtxt* server )
|
||||
{
|
||||
LOG_FUNC();
|
||||
XP_Bool allDone = XP_TRUE;
|
||||
XP_U16 numAssigned;
|
||||
XP_U16 ii;
|
||||
|
@ -1962,6 +1973,7 @@ assignTilesToAll( ServerCtxt* server )
|
|||
}
|
||||
sortTilesIf( server, ii );
|
||||
}
|
||||
LOG_RETURNF( "%d", allDone );
|
||||
return allDone;
|
||||
} /* assignTilesToAll */
|
||||
|
||||
|
@ -2466,6 +2478,7 @@ server_commitMove( ServerCtxt* server, TrayTileSet* newTilesP )
|
|||
XP_ASSERT( turn >= 0 );
|
||||
|
||||
pool_removeTiles( server->pool, &newTiles );
|
||||
server->vol.pickTilesCalled[turn] = XP_FALSE;
|
||||
|
||||
nTilesMoved = model_getCurrentMoveCount( model, turn );
|
||||
fetchTiles( server, turn, nTilesMoved, NULL, &newTiles );
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
/* 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. */
|
||||
# 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_COMBO 2
|
||||
|
||||
|
@ -38,7 +42,7 @@
|
|||
|
||||
typedef struct _MsgRec {
|
||||
XP_U32 createSeconds;
|
||||
SMSMsg msg;
|
||||
SMSMsgNet msgNet;
|
||||
} MsgRec;
|
||||
|
||||
typedef struct _ToPhoneRec {
|
||||
|
@ -82,15 +86,18 @@ struct SMSProto {
|
|||
#define KEY_NEXTID PERSIST_KEY("nextID")
|
||||
|
||||
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,
|
||||
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 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,
|
||||
int indx, int count, const XP_U8* data, XP_U16 len );
|
||||
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 restorePartials( SMSProto* state );
|
||||
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
|
||||
* 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
|
||||
|
@ -159,26 +208,27 @@ smsproto_free( SMSProto* state )
|
|||
* UtilCtxt around.
|
||||
*/
|
||||
SMSMsgArray*
|
||||
smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
||||
XP_U16 buflen, const XP_UCHAR* toPhone,
|
||||
XP_Bool forceOld, XP_U16* waitSecsP )
|
||||
smsproto_prepOutbound( SMSProto* state, SMS_CMD cmd, XP_U32 gameID,
|
||||
const void* buf, XP_U16 buflen, const XP_UCHAR* toPhone,
|
||||
int toPort, XP_Bool forceOld, XP_U16* waitSecsP )
|
||||
{
|
||||
XP_USE( toPort );
|
||||
SMSMsgArray* result = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
XP_UCHAR* checksum = dutil_md5sum( state->dutil, buf, buflen );
|
||||
XP_LOGF( "%s(): len=%d, sum=%s, toPhone=%s", __func__, buflen,
|
||||
checksum, toPhone );
|
||||
XP_LOGF( "%s(cmd=%d, gameID=%d): len=%d, sum=%s, toPhone=%s", __func__, cmd,
|
||||
gameID, buflen, checksum, toPhone );
|
||||
XP_FREEP( state->mpool, &checksum );
|
||||
#endif
|
||||
|
||||
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 */
|
||||
XP_U32 nowSeconds = dutil_getCurSeconds( state->dutil );
|
||||
if ( !!buf ) {
|
||||
addToRec( state, rec, buf, buflen, nowSeconds );
|
||||
if ( cmd != NONE ) {
|
||||
addToOutRec( state, rec, cmd, toPort, gameID, buf, buflen, nowSeconds );
|
||||
}
|
||||
|
||||
/* 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 ) {
|
||||
result = toMsgs( state, rec, forceOld );
|
||||
result = toNetMsgs( state, rec, forceOld );
|
||||
freeForPhone( state, toPhone );
|
||||
}
|
||||
|
||||
|
@ -207,27 +257,45 @@ smsproto_prepOutbound( SMSProto* state, const XP_U8* buf,
|
|||
}
|
||||
|
||||
static SMSMsgArray*
|
||||
appendMsg( SMSProto* state, SMSMsgArray* arr, SMSMsg* msg )
|
||||
appendLocMsg( SMSProto* state, SMSMsgArray* arr, SMSMsgLoc* msg )
|
||||
{
|
||||
if ( NULL == 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->nMsgs + 1) * sizeof(*arr->msgs) );
|
||||
arr->msgs[arr->nMsgs++] = *msg;
|
||||
arr->u.msgsLoc = XP_REALLOC( state->mpool, arr->u.msgsLoc,
|
||||
(arr->nMsgs + 1) * sizeof(*arr->u.msgsLoc) );
|
||||
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;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
XP_LOGF( "%s(): len=%d, fromPhone=%s", __func__, len, fromPhone );
|
||||
checkThread( state );
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
||||
dutil_getVTManager(state->dutil) );
|
||||
XWStreamCtxt* stream = mkStream( state );
|
||||
stream_putBytes( stream, data, len );
|
||||
|
||||
SMSMsgArray* result = NULL;
|
||||
|
@ -244,7 +312,7 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
|||
XP_U8 buf[len];
|
||||
stream_getBytes( stream, 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 );
|
||||
}
|
||||
}
|
||||
|
@ -253,19 +321,39 @@ smsproto_prepInbound( SMSProto* state, const XP_UCHAR* fromPhone,
|
|||
XP_U8 oneLen, msgID;
|
||||
while ( stream_gotU8( stream, &oneLen )
|
||||
&& stream_gotU8( stream, &msgID ) ) {
|
||||
XP_U8 buf[oneLen];
|
||||
if ( stream_gotBytes( stream, buf, oneLen ) ) {
|
||||
SMSMsg msg = { .len = oneLen,
|
||||
.msgID = msgID,
|
||||
.data = XP_MALLOC( state->mpool, oneLen ),
|
||||
XP_U8 tmp[oneLen];
|
||||
stream_getBytes( stream, tmp, oneLen );
|
||||
|
||||
XWStreamCtxt* msgStream = mkStream( state );
|
||||
stream_putBytes( msgStream, tmp, oneLen );
|
||||
|
||||
XP_U32 gameID;
|
||||
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, oneLen );
|
||||
result = appendMsg( state, result, &msg );
|
||||
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;
|
||||
default:
|
||||
/* Don't assert! happens all the time */
|
||||
XP_LOGF( "%s(): unexpected proto %d", __func__, proto );
|
||||
break;
|
||||
}
|
||||
|
@ -283,17 +371,31 @@ smsproto_freeMsgArray( SMSProto* state, SMSMsgArray* arr )
|
|||
checkThread( state );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
static void
|
||||
freeMsg( SMSProto* state, MsgRec** msgp )
|
||||
{
|
||||
XP_FREEP( state->mpool, &(*msgp)->msg.data );
|
||||
XP_FREEP( state->mpool, &(*msgp)->msgNet.data );
|
||||
XP_FREEP( state->mpool, msgp );
|
||||
}
|
||||
|
||||
|
@ -353,20 +455,28 @@ freeForPhone( SMSProto* state, const XP_UCHAR* phone )
|
|||
}
|
||||
|
||||
static void
|
||||
addToRec( SMSProto* state, ToPhoneRec* rec, const XP_U8* buf, XP_U16 buflen,
|
||||
addToOutRec( SMSProto* state, ToPhoneRec* rec, SMS_CMD cmd,
|
||||
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) );
|
||||
mRec->msg.len = buflen;
|
||||
mRec->msg.data = XP_MALLOC( state->mpool, buflen );
|
||||
XP_MEMCPY( mRec->msg.data, buf, buflen );
|
||||
XP_U16 len = stream_getSize( stream );
|
||||
mRec->msgNet.len = len;
|
||||
mRec->msgNet.data = XP_MALLOC( state->mpool, len );
|
||||
XP_MEMCPY( mRec->msgNet.data, stream_getPtr(stream), len );
|
||||
stream_destroy( stream );
|
||||
|
||||
mRec->createSeconds = nowSeconds;
|
||||
|
||||
rec->msgs = XP_REALLOC( state->mpool, rec->msgs, (1 + rec->nMsgs) * sizeof(*rec->msgs) );
|
||||
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,
|
||||
buflen, rec->totalSize );
|
||||
len, rec->totalSize );
|
||||
|
||||
if ( rec->nMsgs == 1 ) {
|
||||
rec->createSeconds = nowSeconds;
|
||||
|
@ -513,9 +623,7 @@ savePartials( SMSProto* state )
|
|||
{
|
||||
checkThread( state );
|
||||
|
||||
XWStreamCtxt* stream
|
||||
= mem_stream_make_raw( MPPARM(state->mpool)
|
||||
dutil_getVTManager(state->dutil) );
|
||||
XWStreamCtxt* stream = mkStream( state );
|
||||
stream_putU8( stream, PARTIALS_FORMAT );
|
||||
|
||||
stream_putU8( stream, state->nFromPhones );
|
||||
|
@ -553,8 +661,8 @@ savePartials( SMSProto* state )
|
|||
static void
|
||||
restorePartials( SMSProto* state )
|
||||
{
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
||||
dutil_getVTManager(state->dutil) );
|
||||
XWStreamCtxt* stream = mkStream( state );
|
||||
|
||||
dutil_loadStream( state->dutil, KEY_PARTIALS, stream );
|
||||
if ( stream_getSize( stream ) >= 1
|
||||
&& PARTIALS_FORMAT == stream_getU8( stream ) ) {
|
||||
|
@ -585,7 +693,7 @@ restorePartials( SMSProto* state )
|
|||
|
||||
static SMSMsgArray*
|
||||
completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
||||
int msgID )
|
||||
XP_U16 wantPort, int msgID )
|
||||
{
|
||||
int fromPhoneIndex, msgIDIndex;
|
||||
MsgIDRec* rec = getMsgIDRec( state, fromPhone, msgID, XP_FALSE,
|
||||
|
@ -607,16 +715,30 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
|||
}
|
||||
|
||||
if ( haveAll ) {
|
||||
SMSMsg msg = { .len = len,
|
||||
.msgID = msgID,
|
||||
XWStreamCtxt* stream = mkStream( state );
|
||||
for ( int ii = 0; ii < rec->count; ++ii ) {
|
||||
stream_putBytes( stream, rec->parts[ii].data, rec->parts[ii].len );
|
||||
}
|
||||
|
||||
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 ),
|
||||
};
|
||||
XP_U8* ptr = msg.data;
|
||||
for ( int ii = 0; ii < rec->count; ++ii ) {
|
||||
XP_MEMCPY( ptr, rec->parts[ii].data, rec->parts[ii].len );
|
||||
ptr += rec->parts[ii].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 );
|
||||
}
|
||||
arr = appendMsg( state, arr, &msg );
|
||||
}
|
||||
stream_destroy( stream );
|
||||
|
||||
freeMsgIDRec( state, rec, fromPhoneIndex, msgIDIndex );
|
||||
}
|
||||
|
@ -625,13 +747,13 @@ completeMsgs( SMSProto* state, SMSMsgArray* arr, const XP_UCHAR* fromPhone,
|
|||
}
|
||||
|
||||
static SMSMsgArray*
|
||||
toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||
toNetMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
||||
{
|
||||
SMSMsgArray* result = NULL;
|
||||
|
||||
for ( XP_U16 ii = 0; 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
|
||||
combined */
|
||||
|
@ -639,7 +761,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
|||
int sum = 0;
|
||||
if ( count == 1 && !forceOld ) {
|
||||
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 ) {
|
||||
break;
|
||||
}
|
||||
|
@ -654,23 +776,23 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
|||
last - 1, nMsgs );
|
||||
}
|
||||
int len = 1 + sum + (nMsgs * 2); /* 1: len & msgID */
|
||||
SMSMsg newMsg = { .len = len,
|
||||
SMSMsgNet newMsg = { .len = len,
|
||||
.data = XP_MALLOC( state->mpool, len )
|
||||
};
|
||||
int indx = 0;
|
||||
newMsg.data[indx++] = SMS_PROTO_VERSION_COMBO;
|
||||
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++] = nextMsgID( state );
|
||||
XP_MEMCPY( &newMsg.data[indx], msg->data, msg->len ); /* bad! */
|
||||
indx += msg->len;
|
||||
}
|
||||
result = appendMsg( state, result, &newMsg );
|
||||
result = appendNetMsg( state, result, &newMsg );
|
||||
ii = last;
|
||||
} else {
|
||||
int msgID = nextMsgID( state );
|
||||
const SMSMsg* msg = &rec->msgs[ii]->msg;
|
||||
const SMSMsgNet* msg = &rec->msgs[ii]->msgNet;
|
||||
XP_U8* nextStart = msg->data;
|
||||
XP_U16 lenLeft = msg->len;
|
||||
for ( XP_U16 indx = 0; indx < count; ++indx ) {
|
||||
|
@ -681,7 +803,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
|||
}
|
||||
lenLeft -= useLen;
|
||||
|
||||
SMSMsg newMsg = { .len = useLen + 4,
|
||||
SMSMsgNet newMsg = { .len = useLen + 4,
|
||||
.data = XP_MALLOC( state->mpool, useLen + 4 )
|
||||
};
|
||||
newMsg.data[0] = SMS_PROTO_VERSION;
|
||||
|
@ -691,7 +813,7 @@ toMsgs( SMSProto* state, ToPhoneRec* rec, XP_Bool forceOld )
|
|||
XP_MEMCPY( newMsg.data + 4, nextStart, useLen );
|
||||
nextStart += useLen;
|
||||
|
||||
result = appendMsg( state, result, &newMsg );
|
||||
result = appendNetMsg( state, result, &newMsg );
|
||||
}
|
||||
++ii;
|
||||
}
|
||||
|
@ -710,6 +832,14 @@ nextMsgID( SMSProto* state )
|
|||
return result;
|
||||
}
|
||||
|
||||
static XWStreamCtxt*
|
||||
mkStream( SMSProto* state )
|
||||
{
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(state->mpool)
|
||||
dutil_getVTManager(state->dutil) );
|
||||
return stream;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
checkThread( SMSProto* state )
|
||||
|
@ -745,17 +875,19 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
|||
}
|
||||
|
||||
/* 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) {
|
||||
XP_Bool allDone = XP_TRUE;
|
||||
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
||||
XP_U16 waitSecs;
|
||||
if ( firstTime ) {
|
||||
XP_U16 len = (ii + 1) * 30;
|
||||
arrs[ii] = smsproto_prepOutbound( state, (XP_U8*)buf, len, phones[ii],
|
||||
forceOld, &waitSecs );
|
||||
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, buf, len, phones[ii],
|
||||
port, forceOld, &waitSecs );
|
||||
} else if ( NULL == arrs[ii]) {
|
||||
arrs[ii] = smsproto_prepOutbound( state, NULL, 0, phones[ii],
|
||||
forceOld, &waitSecs );
|
||||
arrs[ii] = smsproto_prepOutbound( state, DATA, gameID, NULL, 0, phones[ii],
|
||||
port, forceOld, &waitSecs );
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
@ -772,13 +904,17 @@ smsproto_runTests( MPFORMAL XW_DUtilCtxt* dutil )
|
|||
XP_Bool haveOne = XP_FALSE;
|
||||
for ( int ii = 0; ii < VSIZE(arrs); ++ii ) {
|
||||
if (!!arrs[ii] && indx < arrs[ii]->nMsgs) {
|
||||
XP_ASSERT( arrs[ii]->format == FORMAT_NET );
|
||||
haveOne = XP_TRUE;
|
||||
SMSMsgArray* outArr = smsproto_prepInbound( state, phones[ii],
|
||||
arrs[ii]->msgs[indx].data,
|
||||
arrs[ii]->msgs[indx].len );
|
||||
SMSMsgArray* outArr = smsproto_prepInbound( state, phones[ii], port,
|
||||
arrs[ii]->u.msgsNet[indx].data,
|
||||
arrs[ii]->u.msgsNet[indx].len );
|
||||
if ( !!outArr ) {
|
||||
SMSMsg* msg = &outArr->msgs[0];
|
||||
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
||||
XP_ASSERT( outArr->format == FORMAT_LOC );
|
||||
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( 0 == memcmp(buf, msg->data, (ii + 1) * 30) );
|
||||
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 */
|
||||
for ( int nUsed = 0; ; ++nUsed ) {
|
||||
XP_U16 waitSecs;
|
||||
SMSMsgArray* sendArr = smsproto_prepOutbound( state, (XP_U8*)&buf[nUsed],
|
||||
smallSiz, phones[0],
|
||||
SMSMsgArray* sendArr = smsproto_prepOutbound( state, DATA, gameID, &buf[nUsed],
|
||||
smallSiz, phones[0], port,
|
||||
XP_FALSE, &waitSecs );
|
||||
if ( sendArr == NULL ) {
|
||||
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( sendArr->format == FORMAT_NET );
|
||||
int totalBack = 0;
|
||||
for ( int jj = 0; jj < sendArr->nMsgs; ++jj ) {
|
||||
SMSMsgArray* recvArr = smsproto_prepInbound( state, phones[0],
|
||||
sendArr->msgs[jj].data,
|
||||
sendArr->msgs[jj].len );
|
||||
SMSMsgArray* recvArr = smsproto_prepInbound( state, phones[0], port,
|
||||
sendArr->u.msgsNet[jj].data,
|
||||
sendArr->u.msgsNet[jj].len );
|
||||
|
||||
if ( !!recvArr ) {
|
||||
XP_ASSERT( recvArr->format == FORMAT_LOC );
|
||||
XP_LOGF( "%s(): got %d msgs (from %d)", __func__, recvArr->nMsgs, nUsed + 1 );
|
||||
for ( int kk = 0; kk < recvArr->nMsgs; ++kk ) {
|
||||
SMSMsg* msg = &recvArr->msgs[kk];
|
||||
XP_LOGF( "%s(): got msgID %d", __func__, msg->msgID );
|
||||
SMSMsgLoc* msg = &recvArr->u.msgsLoc[kk];
|
||||
// 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( 0 == memcmp( msg->data, &buf[totalBack], smallSiz ) );
|
||||
++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
|
||||
sure it's cleaned up correctly */
|
||||
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 );
|
||||
/* 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 );
|
||||
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 */
|
||||
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 ) {
|
||||
SMSMsgArray* out = smsproto_prepInbound( state, "33333", arr->msgs[ii].data,
|
||||
arr->msgs[ii].len );
|
||||
SMSMsgArray* out = smsproto_prepInbound( state, "33333", port,
|
||||
arr->u.msgsNet[ii].data,
|
||||
arr->u.msgsNet[ii].len );
|
||||
if ( !!out ) {
|
||||
XP_ASSERT( out->nMsgs == 1);
|
||||
XP_ASSERT( out->format == FORMAT_LOC );
|
||||
XP_LOGF( "%s(): got the message on the %dth loop", __func__, ii );
|
||||
XP_ASSERT( out->msgs[0].len == 200 );
|
||||
XP_ASSERT( 0 == memcmp( out->msgs[0].data, buf, 200 ) );
|
||||
XP_ASSERT( out->u.msgsLoc[0].len == 200 );
|
||||
XP_ASSERT( 0 == memcmp( out->u.msgsLoc[0].data, buf, 200 ) );
|
||||
smsproto_freeMsgArray( state, out );
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -44,23 +44,44 @@
|
|||
|
||||
#include "xptypes.h"
|
||||
#include "mempool.h" /* debug only */
|
||||
#include "nli.h"
|
||||
|
||||
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 msgID;
|
||||
XP_U8* data;
|
||||
} SMSMsg;
|
||||
} SMSMsgNet;
|
||||
|
||||
typedef enum { FORMAT_NONE, FORMAT_LOC, FORMAT_NET } SMS_FORMAT;
|
||||
|
||||
typedef struct _SMSMsgArray {
|
||||
XP_U16 nMsgs;
|
||||
SMSMsg* msgs;
|
||||
SMS_FORMAT format;
|
||||
union {
|
||||
SMSMsgNet* msgsNet;
|
||||
SMSMsgLoc* msgsLoc;
|
||||
} u;
|
||||
} SMSMsgArray;
|
||||
|
||||
struct SMSProto* smsproto_init( MPFORMAL XW_DUtilCtxt* dutil );
|
||||
void smsproto_free( SMSProto* state );
|
||||
|
||||
|
||||
/* 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,
|
||||
* 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
|
||||
* 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 );
|
||||
|
||||
/* When a message is received, pass it in for reassambly. Non-null return
|
||||
means one or more messages is ready for consumption. */
|
||||
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 );
|
||||
|
||||
|
|
|
@ -189,6 +189,26 @@ stream_gotU8( XWStreamCtxt* stream, XP_U8* ptr )
|
|||
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
|
||||
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 );
|
||||
|
||||
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_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr
|
||||
|
|
|
@ -1659,8 +1659,7 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
|||
gchar gameName[64];
|
||||
snprintf( gameName, VSIZE(gameName), "Game %d", cGlobals->gi->gameID );
|
||||
|
||||
linux_sms_invite( cGlobals->params, cGlobals->gi, &addr, gameName,
|
||||
nPlayers, forceChannel,
|
||||
linux_sms_invite( cGlobals->params, &nli,
|
||||
addrs->u.sms.phone, addrs->u.sms.port );
|
||||
}
|
||||
if ( 0 != devID || !!relayID ) {
|
||||
|
|
|
@ -746,26 +746,29 @@ gtkNoticeRcvd( void* closure )
|
|||
}
|
||||
|
||||
static void
|
||||
smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName),
|
||||
XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName,
|
||||
XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel,
|
||||
/* smsInviteReceived( void* closure, const XP_UCHAR* XP_UNUSED_DBG(gameName), */
|
||||
/* XP_U32 gameID, XP_U16 dictLang, const XP_UCHAR* dictName, */
|
||||
/* XP_U16 nPlayers, XP_U16 nHere, XP_U16 forceChannel, */
|
||||
/* const CommsAddrRec* returnAddr ) */
|
||||
smsInviteReceived( void* closure, const NetLaunchInfo* nli,
|
||||
const CommsAddrRec* returnAddr )
|
||||
{
|
||||
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
||||
LaunchParams* params = apg->params;
|
||||
XP_LOGF( "%s(gameName=%s, gameID=%d, dictName=%s, nPlayers=%d, "
|
||||
"nHere=%d, forceChannel=%d)", __func__, gameName, gameID, dictName,
|
||||
nPlayers, nHere, forceChannel );
|
||||
"nHere=%d, forceChannel=%d)", __func__, nli->gameName,
|
||||
nli->gameID, nli->dict, nli->nPlayersT,
|
||||
nli->nPlayersH, nli->forceChannel );
|
||||
|
||||
CurGameInfo gi = {0};
|
||||
gi_copy( MPPARM(params->mpool) &gi, ¶ms->pgi );
|
||||
|
||||
gi_setNPlayers( &gi, nPlayers, nHere );
|
||||
gi.gameID = gameID;
|
||||
gi.dictLang = dictLang;
|
||||
gi.forceChannel = forceChannel;
|
||||
gi_setNPlayers( &gi, nli->nPlayersT, nli->nPlayersH );
|
||||
gi.gameID = nli->gameID;
|
||||
gi.dictLang = nli->lang;
|
||||
gi.forceChannel = nli->forceChannel;
|
||||
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) );
|
||||
params->needsNewGame = XP_FALSE;
|
||||
|
|
|
@ -68,12 +68,10 @@ typedef struct _LinSMSData {
|
|||
SMSProto* protoState;
|
||||
} 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 void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
||||
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID );
|
||||
static void sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
|
||||
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_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 );
|
||||
}
|
||||
|
||||
typedef enum { NONE, INVITE, DATA, DEATH, ACK, } SMS_CMD;
|
||||
#define SMS_PROTO_VERSION 0
|
||||
|
||||
|
||||
static LinSMSData* getStorage( LaunchParams* params );
|
||||
static void writeHeader( XWStreamCtxt* stream, SMS_CMD cmd );
|
||||
|
||||
|
||||
static void
|
||||
lock_queue( LinSMSData* storage )
|
||||
|
@ -114,7 +106,7 @@ unlock_queue( LinSMSData* storage )
|
|||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
XP_S16 nSent;
|
||||
|
@ -122,13 +114,11 @@ write_fake_sms( LaunchParams* params, XWStreamCtxt* stream,
|
|||
XP_Bool skipWrite = pct < params->smsSendFailPct;
|
||||
|
||||
if ( skipWrite ) {
|
||||
nSent = stream_getSize( stream );
|
||||
nSent = buflen;
|
||||
XP_LOGF( "%s(): dropping sms msg of len %d to phone %s", __func__,
|
||||
nSent, phone );
|
||||
} else {
|
||||
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,
|
||||
port, buflen );
|
||||
|
||||
|
@ -236,81 +226,38 @@ decodeAndDelete( LinSMSData* storage, const gchar* name,
|
|||
return nRead;
|
||||
} /* 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
|
||||
parseAndDispatch( LaunchParams* params, uint8_t* buf, int len,
|
||||
CommsAddrRec* addr )
|
||||
{
|
||||
LinSMSData* storage = getStorage( params );
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
||||
params->vtMgr );
|
||||
stream_setVersion( stream, CUR_STREAM_VERS );
|
||||
stream_putBytes( stream, buf, len );
|
||||
|
||||
XP_U8 proto = stream_getU8( stream );
|
||||
XP_ASSERT( SMS_PROTO_VERSION == proto );
|
||||
XP_U8 cmd = stream_getU8( stream );
|
||||
switch( cmd ) {
|
||||
case INVITE:
|
||||
dispatch_invite( storage, proto, stream, addr );
|
||||
break;
|
||||
const XP_UCHAR* fromPhone = addr->u.sms.phone;
|
||||
SMSMsgArray* arr = smsproto_prepInbound( storage->protoState, fromPhone,
|
||||
storage->myPort, buf, len );
|
||||
if ( NULL != arr ) {
|
||||
XP_ASSERT( arr->format == FORMAT_LOC );
|
||||
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||
SMSMsgLoc* msg = &arr->u.msgsLoc[ii];
|
||||
switch ( msg->cmd ) {
|
||||
case DATA:
|
||||
dispatch_data( storage, proto, stream, addr );
|
||||
(*storage->procs->msgReceived)( storage->procClosure, addr,
|
||||
msg->gameID,
|
||||
msg->data, msg->len );
|
||||
break;
|
||||
case DEATH:
|
||||
case ACK:
|
||||
case INVITE:
|
||||
(*storage->procs->inviteReceived)( storage->procClosure,
|
||||
(NetLaunchInfo*)msg->data, addr );
|
||||
/* gameName, */
|
||||
/* gameID, dictLang, dictName, nPlayers, */
|
||||
/* nMissing, forceChannel, addr ); */
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT( 0 );
|
||||
XP_ASSERT(0); /* implement me!! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
smsproto_freeMsgArray( storage->protoState, arr );
|
||||
}
|
||||
|
||||
stream_destroy( stream );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -341,28 +288,18 @@ linux_sms_init( LaunchParams* params, const gchar* myPhone, XP_U16 myPort,
|
|||
} /* linux_sms_init */
|
||||
|
||||
void
|
||||
linux_sms_invite( LaunchParams* params, const CurGameInfo* gi,
|
||||
const CommsAddrRec* addr, const gchar* gameName,
|
||||
XP_U16 nMissing, int forceChannel,
|
||||
linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
|
||||
const gchar* toPhone, int toPort )
|
||||
{
|
||||
LOG_FUNC();
|
||||
XWStreamCtxt* stream;
|
||||
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 );
|
||||
LinSMSData* storage = getStorage( params );
|
||||
|
||||
addrToStream( stream, addr );
|
||||
|
||||
write_fake_sms( params, stream, toPhone, toPort );
|
||||
|
||||
stream_destroy( stream );
|
||||
XP_U16 waitSecs;
|
||||
SMSMsgArray* arr
|
||||
= smsproto_prepOutbound( storage->protoState, INVITE, nli->gameID, nli,
|
||||
sizeof(*nli), toPhone, toPort, XP_FALSE,
|
||||
&waitSecs );
|
||||
sendOrRetry( params, arr, INVITE, waitSecs, toPhone, toPort, nli->gameID );
|
||||
}
|
||||
|
||||
XP_S16
|
||||
|
@ -372,43 +309,32 @@ linux_sms_send( LaunchParams* params, const XP_U8* buf,
|
|||
{
|
||||
LinSMSData* storage = getStorage( params );
|
||||
XP_U16 waitSecs;
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, buf, buflen,
|
||||
phone, XP_TRUE, &waitSecs );
|
||||
sendOrRetry( params, arr, waitSecs, phone, port, gameID );
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, DATA, gameID,
|
||||
buf, buflen, phone, port,
|
||||
XP_TRUE, &waitSecs );
|
||||
sendOrRetry( params, arr, DATA, waitSecs, phone, port, gameID );
|
||||
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 {
|
||||
LaunchParams* params;
|
||||
SMS_CMD cmd;
|
||||
XP_U16 port;
|
||||
XP_U32 gameID;
|
||||
XP_UCHAR phone[32];
|
||||
} RetryClosure;
|
||||
|
||||
static void
|
||||
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
||||
const XP_UCHAR* phone, XP_U16 port, XP_U32 gameID )
|
||||
sendOrRetry( LaunchParams* params, SMSMsgArray* arr, SMS_CMD cmd,
|
||||
XP_U16 waitSecs, const XP_UCHAR* phone, XP_U16 port,
|
||||
XP_U32 gameID )
|
||||
{
|
||||
if ( !!arr ) {
|
||||
for ( XP_U16 ii = 0; ii < arr->nMsgs; ++ii ) {
|
||||
SMSMsg* msg = &arr->msgs[ii];
|
||||
doSend( params, msg->data, msg->len, phone, port, gameID );
|
||||
const SMSMsgNet* msg = &arr->u.msgsNet[ii];
|
||||
// doSend( params, msg->data, msg->len, phone, port, gameID );
|
||||
(void)write_fake_sms( params, msg->data, msg->len,
|
||||
phone, port );
|
||||
}
|
||||
|
||||
LinSMSData* storage = getStorage( params );
|
||||
|
@ -420,6 +346,7 @@ sendOrRetry( LaunchParams* params, SMSMsgArray* arr, XP_U16 waitSecs,
|
|||
XP_STRCAT( closure->phone, phone );
|
||||
closure->port = port;
|
||||
closure->gameID = gameID;
|
||||
closure->cmd = cmd;
|
||||
g_timeout_add_seconds( 5, retrySend, closure );
|
||||
}
|
||||
}
|
||||
|
@ -430,9 +357,11 @@ retrySend( gpointer data )
|
|||
RetryClosure* closure = (RetryClosure*)data;
|
||||
LinSMSData* storage = getStorage( closure->params );
|
||||
XP_U16 waitSecs;
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, NULL, 0,
|
||||
closure->phone, XP_TRUE, &waitSecs );
|
||||
sendOrRetry( closure->params, arr, waitSecs, closure->phone,
|
||||
SMSMsgArray* arr = smsproto_prepOutbound( storage->protoState, closure->cmd,
|
||||
closure->gameID, NULL, 0,
|
||||
closure->phone, closure->port,
|
||||
XP_TRUE, &waitSecs );
|
||||
sendOrRetry( closure->params, arr, closure->cmd, waitSecs, closure->phone,
|
||||
closure->port, closure->gameID );
|
||||
XP_FREEP( closure->params->mpool, &closure );
|
||||
return FALSE;
|
||||
|
@ -538,11 +467,4 @@ getStorage( LaunchParams* params )
|
|||
return storage;
|
||||
}
|
||||
|
||||
static void
|
||||
writeHeader( XWStreamCtxt* stream, SMS_CMD cmd )
|
||||
{
|
||||
stream_putU8( stream, SMS_PROTO_VERSION );
|
||||
stream_putU8( stream, cmd );
|
||||
}
|
||||
|
||||
#endif /* XWFEATURE_SMS */
|
||||
|
|
|
@ -23,12 +23,10 @@
|
|||
#ifdef XWFEATURE_SMS
|
||||
|
||||
#include "main.h"
|
||||
#include "nli.h"
|
||||
|
||||
typedef struct _SMSProcs {
|
||||
void (*inviteReceived)( void* closure, const XP_UCHAR* gameName,
|
||||
XP_U32 gameID, XP_U16 dictLang,
|
||||
const XP_UCHAR* dictName, XP_U16 nPlayers,
|
||||
XP_U16 nHere, XP_U16 forceChannel,
|
||||
void (*inviteReceived)( void* closure, const NetLaunchInfo* nli,
|
||||
const CommsAddrRec* returnAddr );
|
||||
void (*msgReceived)( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
||||
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_U16 buflen, const XP_UCHAR* phone, XP_U16 port,
|
||||
XP_U32 gameID );
|
||||
void linux_sms_invite( LaunchParams* params, const CurGameInfo* info,
|
||||
const CommsAddrRec* addr, const gchar* gameName,
|
||||
XP_U16 nMissing, int forceChannel,
|
||||
void linux_sms_invite( LaunchParams* params, const NetLaunchInfo* nli,
|
||||
const gchar* phone, int port );
|
||||
void linux_sms_cleanup( LaunchParams* params );
|
||||
|
||||
|
|
Loading…
Reference in a new issue