mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +01:00
Merge branch 'gtk_multigame' into android_branch
This commit is contained in:
commit
5462a05692
71 changed files with 5811 additions and 2995 deletions
|
@ -995,8 +995,21 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1start
|
||||||
( JNIEnv* env, jclass C, jint gamePtr )
|
( JNIEnv* env, jclass C, jint gamePtr )
|
||||||
{
|
{
|
||||||
XWJNI_START();
|
XWJNI_START();
|
||||||
if ( !!state->game.comms ) {
|
CommsCtxt* comms = state->game.comms;
|
||||||
comms_start( state->game.comms );
|
if ( !!comms ) {
|
||||||
|
comms_start( comms );
|
||||||
|
}
|
||||||
|
XWJNI_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1stop
|
||||||
|
( JNIEnv* env, jclass C, jint gamePtr )
|
||||||
|
{
|
||||||
|
XWJNI_START();
|
||||||
|
CommsCtxt* comms = state->game.comms;
|
||||||
|
if ( !!comms ) {
|
||||||
|
comms_stop( comms );
|
||||||
}
|
}
|
||||||
XWJNI_END();
|
XWJNI_END();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@
|
||||||
<string name="key_sms_port">key_sms_port</string>
|
<string name="key_sms_port">key_sms_port</string>
|
||||||
<string name="key_dict_host">key_dict_host3</string>
|
<string name="key_dict_host">key_dict_host3</string>
|
||||||
<string name="key_logging_on">key_logging_on</string>
|
<string name="key_logging_on">key_logging_on</string>
|
||||||
|
<string name="key_udp_relay">key_udp_relay</string>
|
||||||
|
<string name="key_drop_gcm">key_drop_gcm</string>
|
||||||
<string name="key_show_sms">key_show_sms</string>
|
<string name="key_show_sms">key_show_sms</string>
|
||||||
<string name="key_init_hintsallowed">key_init_hintsallowed</string>
|
<string name="key_init_hintsallowed">key_init_hintsallowed</string>
|
||||||
<string name="key_init_nethintsallowed">key_init_nethintsallowed</string>
|
<string name="key_init_nethintsallowed">key_init_nethintsallowed</string>
|
||||||
|
@ -127,6 +129,9 @@
|
||||||
<string name="name_dict_fmt">%1$s/%2$s</string>
|
<string name="name_dict_fmt">%1$s/%2$s</string>
|
||||||
<string name="gamel_menu_storedb">Write DB to SD card</string>
|
<string name="gamel_menu_storedb">Write DB to SD card</string>
|
||||||
<string name="gamel_menu_loaddb">Load DB from SD card</string>
|
<string name="gamel_menu_loaddb">Load DB from SD card</string>
|
||||||
|
<string name="udp_relay">New/Experimental relay connection</string>
|
||||||
|
<string name="drop_gcm_title">Ignore GCM notices</string>
|
||||||
|
<string name="drop_gcm_summary">(for testing relay proxy)</string>
|
||||||
|
|
||||||
<!--string name="dict_url">http://10.0.2.2/~eehouse/and_dicts</string-->
|
<!--string name="dict_url">http://10.0.2.2/~eehouse/and_dicts</string-->
|
||||||
|
|
||||||
|
|
|
@ -295,6 +295,15 @@
|
||||||
android:summary="@string/git_rev"
|
android:summary="@string/git_rev"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
/>
|
/>
|
||||||
|
<CheckBoxPreference android:key="@string/key_udp_relay"
|
||||||
|
android:title="@string/udp_relay"
|
||||||
|
android:defaultValue="false"
|
||||||
|
/>
|
||||||
|
<CheckBoxPreference android:key="@string/key_drop_gcm"
|
||||||
|
android:title="@string/drop_gcm_title"
|
||||||
|
android:summary="@string/drop_gcm_summary"
|
||||||
|
android:defaultValue="false"
|
||||||
|
/>
|
||||||
<CheckBoxPreference android:key="@string/key_logging_on"
|
<CheckBoxPreference android:key="@string/key_logging_on"
|
||||||
android:title="@string/logging_on"
|
android:title="@string/logging_on"
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
|
|
|
@ -29,7 +29,6 @@ import android.bluetooth.BluetoothSocket;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -49,7 +48,7 @@ import junit.framework.Assert;
|
||||||
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
|
|
||||||
public class BTService extends Service {
|
public class BTService extends XWService {
|
||||||
|
|
||||||
private static final long RESEND_TIMEOUT = 5; // seconds
|
private static final long RESEND_TIMEOUT = 5; // seconds
|
||||||
private static final int MAX_SEND_FAIL = 3;
|
private static final int MAX_SEND_FAIL = 3;
|
||||||
|
@ -77,8 +76,6 @@ public class BTService extends Service {
|
||||||
private static final String NTO_STR = "TOT";
|
private static final String NTO_STR = "TOT";
|
||||||
private static final String NHE_STR = "HER";
|
private static final String NHE_STR = "HER";
|
||||||
|
|
||||||
private static MultiService s_srcMgr = null;
|
|
||||||
|
|
||||||
private enum BTCmd {
|
private enum BTCmd {
|
||||||
PING,
|
PING,
|
||||||
PONG,
|
PONG,
|
||||||
|
@ -147,16 +144,6 @@ public class BTService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setListener( MultiService.MultiEventListener li )
|
|
||||||
{
|
|
||||||
if ( XWApp.BTSUPPORTED ) {
|
|
||||||
if ( null == s_srcMgr ) {
|
|
||||||
s_srcMgr = new MultiService();
|
|
||||||
}
|
|
||||||
s_srcMgr.setListener( li );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void radioChanged( Context context, boolean cameOn )
|
public static void radioChanged( Context context, boolean cameOn )
|
||||||
{
|
{
|
||||||
Intent intent = getIntentTo( context, RADIO );
|
Intent intent = getIntentTo( context, RADIO );
|
||||||
|
@ -316,12 +303,6 @@ public class BTService extends Service {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind( Intent intent )
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BTListenerThread extends Thread {
|
private class BTListenerThread extends Thread {
|
||||||
private BluetoothServerSocket m_serverSocket;
|
private BluetoothServerSocket m_serverSocket;
|
||||||
|
|
||||||
|
@ -852,11 +833,6 @@ public class BTService extends Service {
|
||||||
sendResult( MultiEvent.SCAN_DONE, (Object)(names()) );
|
sendResult( MultiEvent.SCAN_DONE, (Object)(names()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendResult( MultiEvent event, Object ... args )
|
|
||||||
{
|
|
||||||
s_srcMgr.sendResult( event, args );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void listLocalBTGames( boolean force )
|
private void listLocalBTGames( boolean force )
|
||||||
{
|
{
|
||||||
if ( null == s_devGames ) {
|
if ( null == s_devGames ) {
|
||||||
|
|
|
@ -190,6 +190,23 @@ public class BoardActivity extends XWActivity
|
||||||
return delivered;
|
return delivered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean feedMessage( long rowid, byte[] msg )
|
||||||
|
{
|
||||||
|
boolean delivered = false;
|
||||||
|
synchronized( s_thisLocker ) {
|
||||||
|
if ( null != s_this ) {
|
||||||
|
Assert.assertNotNull( s_this.m_gi );
|
||||||
|
Assert.assertNotNull( s_this.m_gameLock );
|
||||||
|
Assert.assertNotNull( s_this.m_jniThread );
|
||||||
|
if ( rowid == s_this.m_rowid ) {
|
||||||
|
s_this.m_jniThread.handle( JNICmd.CMD_RECEIVE, msg, null );
|
||||||
|
delivered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delivered;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean feedMessages( long rowid, byte[][] msgs )
|
public static boolean feedMessages( long rowid, byte[][] msgs )
|
||||||
{
|
{
|
||||||
boolean delivered = false;
|
boolean delivered = false;
|
||||||
|
@ -1693,7 +1710,7 @@ public class BoardActivity extends XWActivity
|
||||||
|
|
||||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||||
m_xport = new CommsTransport( m_jniGamePtr, this, this,
|
m_xport = new CommsTransport( m_jniGamePtr, this, this,
|
||||||
m_gi.serverRole );
|
m_rowid, m_gi.serverRole );
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonPrefs cp = CommonPrefs.get( this );
|
CommonPrefs cp = CommonPrefs.get( this );
|
||||||
|
|
|
@ -57,6 +57,7 @@ public class CommsTransport implements TransportProcs,
|
||||||
private ByteBuffer m_bytesIn;
|
private ByteBuffer m_bytesIn;
|
||||||
|
|
||||||
private Context m_context;
|
private Context m_context;
|
||||||
|
private long m_rowid;
|
||||||
|
|
||||||
// assembling inbound packet
|
// assembling inbound packet
|
||||||
private byte[] m_packetIn;
|
private byte[] m_packetIn;
|
||||||
|
@ -64,11 +65,12 @@ public class CommsTransport implements TransportProcs,
|
||||||
|
|
||||||
public CommsTransport( int jniGamePtr, Context context,
|
public CommsTransport( int jniGamePtr, Context context,
|
||||||
TransportProcs.TPMsgHandler handler,
|
TransportProcs.TPMsgHandler handler,
|
||||||
DeviceRole role )
|
long rowid, DeviceRole role )
|
||||||
{
|
{
|
||||||
m_jniGamePtr = jniGamePtr;
|
m_jniGamePtr = jniGamePtr;
|
||||||
m_context = context;
|
m_context = context;
|
||||||
m_tpHandler = handler;
|
m_tpHandler = handler;
|
||||||
|
m_rowid = rowid;
|
||||||
m_buffersOut = new Vector<ByteBuffer>();
|
m_buffersOut = new Vector<ByteBuffer>();
|
||||||
m_bytesIn = ByteBuffer.allocate( 2048 );
|
m_bytesIn = ByteBuffer.allocate( 2048 );
|
||||||
|
|
||||||
|
@ -377,13 +379,17 @@ public class CommsTransport implements TransportProcs,
|
||||||
|
|
||||||
switch ( addr.conType ) {
|
switch ( addr.conType ) {
|
||||||
case COMMS_CONN_RELAY:
|
case COMMS_CONN_RELAY:
|
||||||
if ( NetStateCache.netAvail( m_context ) ) {
|
if ( XWPrefs.getUDPEnabled( m_context ) ) {
|
||||||
putOut( buf ); // add to queue
|
nSent = RelayService.sendPacket( m_context, m_rowid, buf );
|
||||||
if ( null == m_thread ) {
|
} else {
|
||||||
m_thread = new CommsThread();
|
if ( NetStateCache.netAvail( m_context ) ) {
|
||||||
m_thread.start();
|
putOut( buf ); // add to queue
|
||||||
|
if ( null == m_thread ) {
|
||||||
|
m_thread = new CommsThread();
|
||||||
|
m_thread.start();
|
||||||
|
}
|
||||||
|
nSent = buf.length;
|
||||||
}
|
}
|
||||||
nSent = buf.length;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_SMS:
|
case COMMS_CONN_SMS:
|
||||||
|
|
|
@ -265,6 +265,11 @@ public class DlgDelegate {
|
||||||
(String)args[0] );
|
(String)args[0] );
|
||||||
asToast = false;
|
asToast = false;
|
||||||
break;
|
break;
|
||||||
|
case RELAY_ALERT:
|
||||||
|
msg = (String)args[0];
|
||||||
|
asToast = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DbgUtils.logf( "eventOccurred: unhandled event %s", event.toString() );
|
DbgUtils.logf( "eventOccurred: unhandled event %s", event.toString() );
|
||||||
}
|
}
|
||||||
|
@ -452,9 +457,17 @@ public class DlgDelegate {
|
||||||
|
|
||||||
private void addState( DlgState state )
|
private void addState( DlgState state )
|
||||||
{
|
{
|
||||||
|
// I'm getting serialization failures on devices pointing at
|
||||||
|
// DlgState but the code below says the object's fine (as it
|
||||||
|
// should be.) Just to have a record....
|
||||||
|
//
|
||||||
|
// Bundle bundle = new Bundle();
|
||||||
|
// DbgUtils.logf( "addState: testing serializable" );
|
||||||
|
// bundle.putSerializable( "foo", state );
|
||||||
|
// state = (DlgState)bundle.getSerializable( "foo" );
|
||||||
|
// DbgUtils.logf( "addState: serializable is ok" );
|
||||||
|
|
||||||
m_dlgStates.put( state.m_id, state );
|
m_dlgStates.put( state.m_id, state );
|
||||||
// DbgUtils.logf( "addState: there are now %d active dialogs",
|
|
||||||
// m_dlgStates.size() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,40 +58,44 @@ public class GCMIntentService extends GCMBaseIntentService {
|
||||||
protected void onMessage( Context context, Intent intent )
|
protected void onMessage( Context context, Intent intent )
|
||||||
{
|
{
|
||||||
String value;
|
String value;
|
||||||
|
boolean ignoreIt = XWPrefs.getGCMIgnored( this );
|
||||||
|
if ( ignoreIt ) {
|
||||||
|
DbgUtils.logf( "received GCM but ignoring it" );
|
||||||
|
} else {
|
||||||
|
value = intent.getStringExtra( "checkUpdates" );
|
||||||
|
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||||
|
UpdateCheckReceiver.checkVersions( context, true );
|
||||||
|
}
|
||||||
|
|
||||||
value = intent.getStringExtra( "getMoves" );
|
value = intent.getStringExtra( "getMoves" );
|
||||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||||
RelayReceiver.RestartTimer( context, true );
|
RelayReceiver.RestartTimer( context, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
value = intent.getStringExtra( "msgs64" );
|
value = intent.getStringExtra( "msgs64" );
|
||||||
if ( null != value ) {
|
if ( null != value ) {
|
||||||
String connname = intent.getStringExtra( "connname" );
|
String connname = intent.getStringExtra( "connname" );
|
||||||
if ( null != connname ) {
|
if ( null != connname ) {
|
||||||
try {
|
try {
|
||||||
JSONArray msgs64 = new JSONArray( value );
|
JSONArray msgs64 = new JSONArray( value );
|
||||||
String[] strs64 = new String[msgs64.length()];
|
String[] strs64 = new String[msgs64.length()];
|
||||||
for ( int ii = 0; ii < strs64.length; ++ii ) {
|
for ( int ii = 0; ii < strs64.length; ++ii ) {
|
||||||
strs64[ii] = msgs64.optString(ii);
|
strs64[ii] = msgs64.optString(ii);
|
||||||
|
}
|
||||||
|
RelayService.processMsgs( context, connname, strs64 );
|
||||||
|
} catch (org.json.JSONException jse ) {
|
||||||
|
DbgUtils.loge( jse );
|
||||||
}
|
}
|
||||||
RelayService.processMsgs( context, connname, strs64 );
|
|
||||||
} catch (org.json.JSONException jse ) {
|
|
||||||
DbgUtils.loge( jse );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
value = intent.getStringExtra( "checkUpdates" );
|
value = intent.getStringExtra( "msg" );
|
||||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
if ( null != value ) {
|
||||||
UpdateCheckReceiver.checkVersions( context, true );
|
String title = intent.getStringExtra( "title" );
|
||||||
}
|
if ( null != title ) {
|
||||||
|
int code = value.hashCode() ^ title.hashCode();
|
||||||
value = intent.getStringExtra( "msg" );
|
Utils.postNotification( context, null, title, value, code );
|
||||||
if ( null != value ) {
|
}
|
||||||
String title = intent.getStringExtra( "title" );
|
|
||||||
if ( null != title ) {
|
|
||||||
int code = value.hashCode() ^ title.hashCode();
|
|
||||||
Utils.postNotification( context, null, title, value, code );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,9 @@ public class GamesList extends XWExpandableListActivity
|
||||||
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
||||||
|
|
||||||
private static final String RELAYIDS_EXTRA = "relayids";
|
private static final String RELAYIDS_EXTRA = "relayids";
|
||||||
|
private static final String ROWID_EXTRA = "rowid";
|
||||||
private static final String GAMEID_EXTRA = "gameid";
|
private static final String GAMEID_EXTRA = "gameid";
|
||||||
private static final String REMATCH_ROWID_EXTRA = "rowid";
|
private static final String REMATCH_ROWID_EXTRA = "rowid_rm";
|
||||||
|
|
||||||
private static final int NEW_NET_GAME_ACTION = 1;
|
private static final int NEW_NET_GAME_ACTION = 1;
|
||||||
private static final int RESET_GAME_ACTION = 2;
|
private static final int RESET_GAME_ACTION = 2;
|
||||||
|
@ -388,6 +389,7 @@ public class GamesList extends XWExpandableListActivity
|
||||||
m_gameLaunched = false;
|
m_gameLaunched = false;
|
||||||
Assert.assertNotNull( intent );
|
Assert.assertNotNull( intent );
|
||||||
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
|
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
|
||||||
|
invalRowID( intent.getLongExtra( ROWID_EXTRA, -1 ) );
|
||||||
startFirstHasDict( intent );
|
startFirstHasDict( intent );
|
||||||
startNewNetGame( intent );
|
startNewNetGame( intent );
|
||||||
startHasGameID( intent );
|
startHasGameID( intent );
|
||||||
|
@ -919,10 +921,18 @@ public class GamesList extends XWExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void invalRowID( long rowid )
|
||||||
|
{
|
||||||
|
if ( -1 != rowid ) {
|
||||||
|
m_adapter.inval( rowid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Launch the first of these for which there's a dictionary
|
// Launch the first of these for which there's a dictionary
|
||||||
// present.
|
// present.
|
||||||
private void startFirstHasDict( String[] relayIDs )
|
private boolean startFirstHasDict( String[] relayIDs )
|
||||||
{
|
{
|
||||||
|
boolean launched = false;
|
||||||
if ( null != relayIDs ) {
|
if ( null != relayIDs ) {
|
||||||
outer:
|
outer:
|
||||||
for ( String relayID : relayIDs ) {
|
for ( String relayID : relayIDs ) {
|
||||||
|
@ -931,19 +941,33 @@ public class GamesList extends XWExpandableListActivity
|
||||||
for ( long rowid : rowids ) {
|
for ( long rowid : rowids ) {
|
||||||
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
||||||
launchGame( rowid );
|
launchGame( rowid );
|
||||||
|
launched = true;
|
||||||
break outer;
|
break outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return launched;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startFirstHasDict( long rowid )
|
||||||
|
{
|
||||||
|
if ( -1 != rowid ) {
|
||||||
|
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
||||||
|
launchGame( rowid );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startFirstHasDict( Intent intent )
|
private void startFirstHasDict( Intent intent )
|
||||||
{
|
{
|
||||||
if ( null != intent ) {
|
if ( null != intent ) {
|
||||||
String[] relayIDs = intent.getStringArrayExtra( RELAYIDS_EXTRA );
|
String[] relayIDs = intent.getStringArrayExtra( RELAYIDS_EXTRA );
|
||||||
startFirstHasDict( relayIDs );
|
if ( !startFirstHasDict( relayIDs ) ) {
|
||||||
|
long rowid = intent.getLongExtra( ROWID_EXTRA, -1 );
|
||||||
|
startFirstHasDict( rowid );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,11 +1123,10 @@ public class GamesList extends XWExpandableListActivity
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent makeRelayIdsIntent( Context context,
|
public static Intent makeRowidIntent( Context context, long rowid )
|
||||||
String[] relayIDs )
|
|
||||||
{
|
{
|
||||||
Intent intent = makeSelfIntent( context );
|
Intent intent = makeSelfIntent( context );
|
||||||
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
|
intent.putExtra( ROWID_EXTRA, rowid );
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class MultiMsgSink implements TransportProcs {
|
||||||
|
|
||||||
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
|
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
|
||||||
{
|
{
|
||||||
Assert.fail();
|
Assert.fail(); // implement if this is getting called!!!
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ public class MultiMsgSink implements TransportProcs {
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean relayNoConnProc( byte[] buf, String relayID )
|
public boolean relayNoConnProc( byte[] buf, String relayID )
|
||||||
{
|
{
|
||||||
Assert.fail();
|
Assert.fail(); // implement if this is getting called!!!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ public class MultiService {
|
||||||
, SMS_SEND_OK
|
, SMS_SEND_OK
|
||||||
, SMS_SEND_FAILED
|
, SMS_SEND_FAILED
|
||||||
, SMS_SEND_FAILED_NORADIO
|
, SMS_SEND_FAILED_NORADIO
|
||||||
|
|
||||||
|
, RELAY_ALERT
|
||||||
};
|
};
|
||||||
|
|
||||||
public interface MultiEventListener {
|
public interface MultiEventListener {
|
||||||
|
|
|
@ -41,6 +41,7 @@ public class PrefsActivity extends PreferenceActivity
|
||||||
private String m_keyLogging;
|
private String m_keyLogging;
|
||||||
private String m_smsToasting;
|
private String m_smsToasting;
|
||||||
private String m_smsEnable;
|
private String m_smsEnable;
|
||||||
|
private String m_udpEnabled;
|
||||||
private String m_downloadPath;
|
private String m_downloadPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -122,6 +123,7 @@ public class PrefsActivity extends PreferenceActivity
|
||||||
m_keyLogging = getString( R.string.key_logging_on );
|
m_keyLogging = getString( R.string.key_logging_on );
|
||||||
m_smsToasting = getString( R.string.key_show_sms );
|
m_smsToasting = getString( R.string.key_show_sms );
|
||||||
m_smsEnable = getString( R.string.key_enable_sms );
|
m_smsEnable = getString( R.string.key_enable_sms );
|
||||||
|
m_udpEnabled = getString( R.string.key_udp_relay );
|
||||||
m_downloadPath = getString( R.string.key_download_path );
|
m_downloadPath = getString( R.string.key_download_path );
|
||||||
|
|
||||||
Button button = (Button)findViewById( R.id.revert_colors );
|
Button button = (Button)findViewById( R.id.revert_colors );
|
||||||
|
@ -161,6 +163,8 @@ public class PrefsActivity extends PreferenceActivity
|
||||||
DbgUtils.logEnable( sp.getBoolean( key, false ) );
|
DbgUtils.logEnable( sp.getBoolean( key, false ) );
|
||||||
} else if ( key.equals( m_smsToasting ) ) {
|
} else if ( key.equals( m_smsToasting ) ) {
|
||||||
SMSService.smsToastEnable( sp.getBoolean( key, false ) );
|
SMSService.smsToastEnable( sp.getBoolean( key, false ) );
|
||||||
|
} else if ( key.equals( m_udpEnabled ) ) {
|
||||||
|
RelayService.udpChanged( this );
|
||||||
} else if ( key.equals( m_smsEnable ) ) {
|
} else if ( key.equals( m_smsEnable ) ) {
|
||||||
if ( sp.getBoolean( key, true ) ) {
|
if ( sp.getBoolean( key, true ) ) {
|
||||||
SMSService.checkForInvites( this );
|
SMSService.checkForInvites( this );
|
||||||
|
|
|
@ -25,24 +25,113 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||||
|
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
import org.eehouse.android.xw4.jni.GameSummary;
|
import org.eehouse.android.xw4.jni.GameSummary;
|
||||||
|
import org.eehouse.android.xw4.jni.UtilCtxt;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
|
||||||
public class RelayService extends Service {
|
public class RelayService extends XWService {
|
||||||
private static final int MAX_SEND = 1024;
|
private static final int MAX_SEND = 1024;
|
||||||
private static final int MAX_BUF = MAX_SEND - 2;
|
private static final int MAX_BUF = MAX_SEND - 2;
|
||||||
|
|
||||||
private static final String CMD_STR = "CMD";
|
private static final String CMD_STR = "CMD";
|
||||||
|
|
||||||
private static final int PROCESS_MSGS = 1;
|
private static final int PROCESS_MSGS = 1;
|
||||||
|
private static final int UDP_CHANGED = 2;
|
||||||
|
private static final int SEND = 3;
|
||||||
|
private static final int RECEIVE = 4;
|
||||||
|
|
||||||
private static final String MSGS = "MSGS";
|
private static final String MSGS = "MSGS";
|
||||||
private static final String RELAY_ID = "RELAY_ID";
|
private static final String RELAY_ID = "RELAY_ID";
|
||||||
|
private static final String ROWID = "ROWID";
|
||||||
|
private static final String BINBUFFER = "BINBUFFER";
|
||||||
|
|
||||||
|
private static HashSet<Integer> s_packetsSent = new HashSet<Integer>();
|
||||||
|
private static int s_nextPacketID = 1;
|
||||||
|
|
||||||
|
private Thread m_fetchThread = null;
|
||||||
|
private Thread m_UDPReadThread = null;
|
||||||
|
private Thread m_UDPWriteThread = null;
|
||||||
|
private DatagramSocket m_UDPSocket;
|
||||||
|
private LinkedBlockingQueue<DatagramPacket> m_queue = null;
|
||||||
|
|
||||||
|
// These must match the enum XWRelayReg in xwrelay.h
|
||||||
|
private static final int XWPDEV_PROTO_VERSION = 0;
|
||||||
|
// private static final int XWPDEV_NONE = 0;
|
||||||
|
|
||||||
|
private enum XWRelayReg {
|
||||||
|
XWPDEV_NONE
|
||||||
|
,XWPDEV_ALERT
|
||||||
|
,XWPDEV_REG
|
||||||
|
,XWPDEV_REGRSP
|
||||||
|
,XWPDEV_PING
|
||||||
|
,XWPDEV_HAVEMSGS
|
||||||
|
,XWPDEV_RQSTMSGS
|
||||||
|
,XWPDEV_MSG
|
||||||
|
,XWPDEV_MSGNOCONN
|
||||||
|
,XWPDEV_MSGRSP
|
||||||
|
,XWPDEV_BADREG
|
||||||
|
,XWPDEV_ACK
|
||||||
|
};
|
||||||
|
|
||||||
|
// private static final int XWPDEV_ALERT = 1;
|
||||||
|
// private static final int XWPDEV_REG = 2;
|
||||||
|
// private static final int XWPDEV_REGRSP = 3;
|
||||||
|
// private static final int XWPDEV_PING = 4;
|
||||||
|
// private static final int XWPDEV_HAVEMSGS = 5;
|
||||||
|
// private static final int XWPDEV_RQSTMSGS = 6;
|
||||||
|
// private static final int XWPDEV_MSG = 7;
|
||||||
|
// private static final int XWPDEV_MSGNOCONN = 8;
|
||||||
|
// private static final int XWPDEV_MSGRSP = 9;
|
||||||
|
// private static final int XWPDEV_BADREG = 10;
|
||||||
|
|
||||||
|
public static void startService( Context context )
|
||||||
|
{
|
||||||
|
Intent intent = getIntentTo( context, UDP_CHANGED );
|
||||||
|
context.startService( intent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int sendPacket( Context context, long rowid, byte[] buf )
|
||||||
|
{
|
||||||
|
Intent intent = getIntentTo( context, SEND )
|
||||||
|
.putExtra( ROWID, rowid )
|
||||||
|
.putExtra( BINBUFFER, buf );
|
||||||
|
context.startService( intent );
|
||||||
|
return buf.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists to get incoming data onto the main thread
|
||||||
|
private static void postData( Context context, long rowid, byte[] msg )
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "RelayService::postData: packet of length %d for token %d",
|
||||||
|
msg.length, rowid );
|
||||||
|
Intent intent = getIntentTo( context, RECEIVE )
|
||||||
|
.putExtra( ROWID, rowid )
|
||||||
|
.putExtra( BINBUFFER, msg );
|
||||||
|
context.startService( intent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void udpChanged( Context context )
|
||||||
|
{
|
||||||
|
startService( context );
|
||||||
|
}
|
||||||
|
|
||||||
public static void processMsgs( Context context, String relayId,
|
public static void processMsgs( Context context, String relayId,
|
||||||
String[] msgs64 )
|
String[] msgs64 )
|
||||||
|
@ -64,45 +153,65 @@ public class RelayService extends Service {
|
||||||
public void onCreate()
|
public void onCreate()
|
||||||
{
|
{
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
startFetchThreadIf();
|
||||||
Thread thread = new Thread( null, new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
fetchAndProcess();
|
|
||||||
RelayService.this.stopSelf();
|
|
||||||
}
|
|
||||||
}, getClass().getName() );
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind( Intent intent )
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand( Intent intent, int flags, int startId )
|
public int onStartCommand( Intent intent, int flags, int startId )
|
||||||
{
|
{
|
||||||
int cmd = intent.getIntExtra( CMD_STR, -1 );
|
DbgUtils.logf( "RelayService::onStartCommand" );
|
||||||
switch( cmd ) {
|
int result;
|
||||||
case PROCESS_MSGS:
|
if ( null != intent ) {
|
||||||
String[] relayIDs = new String[1];
|
int cmd = intent.getIntExtra( CMD_STR, -1 );
|
||||||
relayIDs[0] = intent.getStringExtra( RELAY_ID );
|
switch( cmd ) {
|
||||||
long[] rowIDs = DBUtils.getRowIDsFor( this, relayIDs[0] );
|
case -1:
|
||||||
if ( 0 < rowIDs.length ) {
|
break;
|
||||||
String[] msgs64 = intent.getStringArrayExtra( MSGS );
|
case PROCESS_MSGS:
|
||||||
int count = msgs64.length;
|
String[] relayIDs = new String[1];
|
||||||
|
relayIDs[0] = intent.getStringExtra( RELAY_ID );
|
||||||
|
long[] rowIDs = DBUtils.getRowIDsFor( this, relayIDs[0] );
|
||||||
|
if ( 0 < rowIDs.length ) {
|
||||||
|
String[] msgs64 = intent.getStringArrayExtra( MSGS );
|
||||||
|
int count = msgs64.length;
|
||||||
|
|
||||||
byte[][][] msgs = new byte[1][count][];
|
byte[][][] msgs = new byte[1][count][];
|
||||||
for ( int ii = 0; ii < count; ++ii ) {
|
for ( int ii = 0; ii < count; ++ii ) {
|
||||||
msgs[0][ii] = XwJNI.base64Decode( msgs64[ii] );
|
msgs[0][ii] = XwJNI.base64Decode( msgs64[ii] );
|
||||||
|
}
|
||||||
|
process( msgs, rowIDs, relayIDs );
|
||||||
}
|
}
|
||||||
process( msgs, rowIDs, relayIDs );
|
break;
|
||||||
|
case UDP_CHANGED:
|
||||||
|
DbgUtils.logf( "RelayService::onStartCommand::UDP_CHANGED" );
|
||||||
|
if ( XWPrefs.getUDPEnabled( this ) ) {
|
||||||
|
stopFetchThreadIf();
|
||||||
|
startUDPThreadsIfNot();
|
||||||
|
registerWithRelay();
|
||||||
|
} else {
|
||||||
|
stopUDPThreadsIf();
|
||||||
|
startFetchThreadIf();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SEND:
|
||||||
|
case RECEIVE:
|
||||||
|
startUDPThreadsIfNot();
|
||||||
|
long rowid = intent.getLongExtra( ROWID, -1 );
|
||||||
|
byte[] msg = intent.getByteArrayExtra( BINBUFFER );
|
||||||
|
if ( SEND == cmd ) {
|
||||||
|
sendMessage( rowid, msg );
|
||||||
|
} else {
|
||||||
|
feedMessage( rowid, msg );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assert.fail();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
result = Service.START_STICKY;
|
||||||
|
} else {
|
||||||
|
result = Service.START_STICKY_COMPATIBILITY;
|
||||||
}
|
}
|
||||||
stopSelf( startId );
|
return result;
|
||||||
return Service.START_NOT_STICKY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupNotification( String[] relayIDs )
|
private void setupNotification( String[] relayIDs )
|
||||||
|
@ -111,18 +220,380 @@ public class RelayService extends Service {
|
||||||
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
|
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
|
||||||
if ( null != rowids ) {
|
if ( null != rowids ) {
|
||||||
for ( long rowid : rowids ) {
|
for ( long rowid : rowids ) {
|
||||||
Intent intent =
|
setupNotification( rowid );
|
||||||
GamesList.makeRelayIdsIntent( this,
|
|
||||||
new String[] {relayID} );
|
|
||||||
String msg = Utils.format( this, R.string.notify_bodyf,
|
|
||||||
GameUtils.getName( this, rowid ) );
|
|
||||||
Utils.postNotification( this, intent, R.string.notify_title,
|
|
||||||
msg, (int)rowid );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupNotification( long rowid )
|
||||||
|
{
|
||||||
|
Intent intent = GamesList.makeRowidIntent( this, rowid );
|
||||||
|
String msg = Utils.format( this, R.string.notify_bodyf,
|
||||||
|
GameUtils.getName( this, rowid ) );
|
||||||
|
Utils.postNotification( this, intent, R.string.notify_title,
|
||||||
|
msg, (int)rowid );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startFetchThreadIf()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "startFetchThreadIf()" );
|
||||||
|
if ( !XWPrefs.getUDPEnabled( this ) && null == m_fetchThread ) {
|
||||||
|
m_fetchThread = new Thread( null, new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
fetchAndProcess();
|
||||||
|
m_fetchThread = null;
|
||||||
|
RelayService.this.stopSelf();
|
||||||
|
}
|
||||||
|
}, getClass().getName() );
|
||||||
|
m_fetchThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopFetchThreadIf()
|
||||||
|
{
|
||||||
|
if ( null != m_fetchThread ) {
|
||||||
|
DbgUtils.logf( "2: m_fetchThread NOT NULL; WHAT TO DO???" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startUDPThreadsIfNot()
|
||||||
|
{
|
||||||
|
if ( XWPrefs.getUDPEnabled( this ) ) {
|
||||||
|
if ( null == m_UDPSocket ) {
|
||||||
|
int port = XWPrefs.getDefaultRelayPort( RelayService.this );
|
||||||
|
String host = XWPrefs.getDefaultRelayHost( RelayService.this );
|
||||||
|
try {
|
||||||
|
m_UDPSocket = new DatagramSocket();
|
||||||
|
InetAddress addr = InetAddress.getByName( host );
|
||||||
|
m_UDPSocket.connect( addr, port ); // remember this address
|
||||||
|
} catch( java.net.SocketException se ) {
|
||||||
|
DbgUtils.loge( se );
|
||||||
|
Assert.fail();
|
||||||
|
} catch( java.net.UnknownHostException uhe ) {
|
||||||
|
DbgUtils.loge( uhe );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue( m_UDPSocket.isConnected() );
|
||||||
|
DbgUtils.logf( "m_UDPSocket not null" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == m_UDPReadThread ) {
|
||||||
|
m_UDPReadThread = new Thread( null, new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
DbgUtils.logf( "read thread running" );
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
for ( ; ; ) {
|
||||||
|
DatagramPacket packet =
|
||||||
|
new DatagramPacket( buf, buf.length );
|
||||||
|
try {
|
||||||
|
DbgUtils.logf( "UPD read thread blocking on receive" );
|
||||||
|
m_UDPSocket.receive( packet );
|
||||||
|
DbgUtils.logf( "UPD read thread: receive returned" );
|
||||||
|
} catch( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
break; // ???
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "received %d bytes", packet.getLength() );
|
||||||
|
gotPacket( packet );
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "read thread exiting" );
|
||||||
|
}
|
||||||
|
}, getClass().getName() );
|
||||||
|
m_UDPReadThread.start();
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "m_UDPReadThread not null and assumed to be running" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null == m_UDPWriteThread ) {
|
||||||
|
m_queue = new LinkedBlockingQueue<DatagramPacket>();
|
||||||
|
m_UDPWriteThread = new Thread( null, new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
DbgUtils.logf( "write thread running" );
|
||||||
|
for ( ; ; ) {
|
||||||
|
DatagramPacket outPacket;
|
||||||
|
try {
|
||||||
|
outPacket = m_queue.take();
|
||||||
|
} catch ( InterruptedException ie ) {
|
||||||
|
DbgUtils.logf( "RelayService; write thread killed" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( null == outPacket || 0 == outPacket.getLength() ) {
|
||||||
|
DbgUtils.logf( "stopping write thread" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "Sending udp packet of length %d",
|
||||||
|
outPacket.getLength() );
|
||||||
|
try {
|
||||||
|
m_UDPSocket.send( outPacket );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "write thread exiting" );
|
||||||
|
}
|
||||||
|
}, getClass().getName() );
|
||||||
|
m_UDPWriteThread.start();
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "m_UDPWriteThread not null and assumed to be running" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopUDPThreadsIf()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "stopUDPThreadsIf" );
|
||||||
|
if ( null != m_queue && null != m_UDPWriteThread ) {
|
||||||
|
// can't add null
|
||||||
|
m_queue.add( new DatagramPacket( new byte[0], 0 ) );
|
||||||
|
try {
|
||||||
|
DbgUtils.logf( "joining m_UDPWriteThread" );
|
||||||
|
m_UDPWriteThread.join();
|
||||||
|
DbgUtils.logf( "SUCCESSFULLY joined m_UDPWriteThread" );
|
||||||
|
} catch( java.lang.InterruptedException ie ) {
|
||||||
|
DbgUtils.loge( ie );
|
||||||
|
}
|
||||||
|
m_UDPWriteThread = null;
|
||||||
|
m_queue = null;
|
||||||
|
}
|
||||||
|
if ( null != m_UDPSocket && null != m_UDPReadThread ) {
|
||||||
|
m_UDPSocket.close();
|
||||||
|
DbgUtils.logf( "waiting for read thread to exit" );
|
||||||
|
try {
|
||||||
|
m_UDPReadThread.join();
|
||||||
|
} catch( java.lang.InterruptedException ie ) {
|
||||||
|
DbgUtils.loge( ie );
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "read thread exited" );
|
||||||
|
m_UDPReadThread = null;
|
||||||
|
m_UDPSocket = null;
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "stopUDPThreadsIf DONE" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Running on reader thread
|
||||||
|
private void gotPacket( DatagramPacket packet )
|
||||||
|
{
|
||||||
|
int packetLen = packet.getLength();
|
||||||
|
byte[] data = new byte[packetLen];
|
||||||
|
System.arraycopy( packet.getData(), 0, data, 0, packetLen );
|
||||||
|
DbgUtils.logf( "RelayService::gotPacket: %d bytes of data", packetLen );
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream( data );
|
||||||
|
DataInputStream dis = new DataInputStream( bis );
|
||||||
|
try {
|
||||||
|
PacketHeader header = readHeader( dis );
|
||||||
|
if ( null != header ) {
|
||||||
|
sendAckIf( header );
|
||||||
|
switch ( header.m_cmd ) {
|
||||||
|
case XWPDEV_ALERT:
|
||||||
|
String str = getStringWithLength( dis );
|
||||||
|
sendResult( MultiEvent.RELAY_ALERT, str );
|
||||||
|
break;
|
||||||
|
case XWPDEV_BADREG:
|
||||||
|
str = getStringWithLength( dis );
|
||||||
|
DbgUtils.logf( "bad relayID \"%s\" reported", str );
|
||||||
|
XWPrefs.clearRelayDevID( this );
|
||||||
|
registerWithRelay();
|
||||||
|
break;
|
||||||
|
case XWPDEV_REGRSP:
|
||||||
|
DbgUtils.logf( "got XWPDEV_REGRSP" );
|
||||||
|
str = getStringWithLength( dis );
|
||||||
|
DbgUtils.logf( "got relayid %s", str );
|
||||||
|
XWPrefs.setRelayDevID( this, str );
|
||||||
|
break;
|
||||||
|
case XWPDEV_HAVEMSGS:
|
||||||
|
requestMessages();
|
||||||
|
break;
|
||||||
|
case XWPDEV_MSG:
|
||||||
|
DbgUtils.logf( "got XWPDEV_MSG" );
|
||||||
|
int token = dis.readInt();
|
||||||
|
byte[] msg = new byte[dis.available()];
|
||||||
|
Assert.assertTrue( packet.getLength() >= msg.length );
|
||||||
|
Assert.assertTrue( packetLen >= msg.length );
|
||||||
|
dis.read( msg );
|
||||||
|
postData( RelayService.this, token, msg );
|
||||||
|
break;
|
||||||
|
case XWPDEV_ACK:
|
||||||
|
noteAck( dis.readInt() );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DbgUtils.logf( "RelayService: Unhandled cmd: %d",
|
||||||
|
header.m_cmd );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
} // gotPacket
|
||||||
|
|
||||||
|
private void registerWithRelay()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "registerWithRelay" );
|
||||||
|
byte[] typ = new byte[1];
|
||||||
|
String devid = getDevID(typ);
|
||||||
|
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
DataOutputStream out = addProtoAndCmd( bas, XWRelayReg.XWPDEV_REG );
|
||||||
|
out.writeByte( typ[0] );
|
||||||
|
out.writeShort( devid.length() );
|
||||||
|
out.writeBytes( devid );
|
||||||
|
postPacket( bas );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestMessages()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "requestMessages" );
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
DataOutputStream out =
|
||||||
|
addProtoAndCmd( bas, XWRelayReg.XWPDEV_RQSTMSGS );
|
||||||
|
String devid = getDevID( null );
|
||||||
|
out.writeShort( devid.length() );
|
||||||
|
out.writeBytes( devid );
|
||||||
|
postPacket( bas );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessage( long rowid, byte[] msg )
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
DataOutputStream out = addProtoAndCmd( bas, XWRelayReg.XWPDEV_MSG );
|
||||||
|
Assert.assertTrue( rowid < Integer.MAX_VALUE );
|
||||||
|
out.writeInt( (int)rowid );
|
||||||
|
out.write( msg, 0, msg.length );
|
||||||
|
postPacket( bas );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendNoConnMessage( long rowid, String relayID, byte[] msg )
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
DataOutputStream out =
|
||||||
|
addProtoAndCmd( bas, XWRelayReg.XWPDEV_MSGNOCONN );
|
||||||
|
Assert.assertTrue( rowid < Integer.MAX_VALUE );
|
||||||
|
out.writeInt( (int)rowid );
|
||||||
|
out.writeBytes( relayID );
|
||||||
|
out.write( '\n' );
|
||||||
|
out.write( msg, 0, msg.length );
|
||||||
|
postPacket( bas );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAckIf( PacketHeader header )
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "sendAckIf" );
|
||||||
|
if ( XWRelayReg.XWPDEV_ACK != header.m_cmd ) {
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
DataOutputStream out =
|
||||||
|
addProtoAndCmd( bas, XWRelayReg.XWPDEV_ACK );
|
||||||
|
out.writeInt( header.m_packetID );
|
||||||
|
postPacket( bas );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
DbgUtils.loge( ioe );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PacketHeader readHeader( DataInputStream dis )
|
||||||
|
throws java.io.IOException
|
||||||
|
{
|
||||||
|
PacketHeader result = null;
|
||||||
|
byte proto = dis.readByte();
|
||||||
|
if ( XWPDEV_PROTO_VERSION == proto ) {
|
||||||
|
int packetID = dis.readInt();
|
||||||
|
DbgUtils.logf( "readHeader: got packetID %d", packetID );
|
||||||
|
byte ordinal = dis.readByte();
|
||||||
|
XWRelayReg cmd = XWRelayReg.values()[ordinal];
|
||||||
|
result = new PacketHeader( cmd, packetID );
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "bad proto: %d", proto );
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "readHeader => %H", result );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStringWithLength( DataInputStream dis )
|
||||||
|
throws java.io.IOException
|
||||||
|
{
|
||||||
|
short len = dis.readShort();
|
||||||
|
byte[] tmp = new byte[len];
|
||||||
|
dis.read( tmp );
|
||||||
|
return new String( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataOutputStream addProtoAndCmd( ByteArrayOutputStream bas,
|
||||||
|
XWRelayReg cmd )
|
||||||
|
throws java.io.IOException
|
||||||
|
{
|
||||||
|
DataOutputStream out = new DataOutputStream( bas );
|
||||||
|
out.writeByte( XWPDEV_PROTO_VERSION );
|
||||||
|
out.writeInt( nextPacketID( cmd ) ); // packetID
|
||||||
|
out.writeByte( cmd.ordinal() );
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postPacket( ByteArrayOutputStream bas )
|
||||||
|
{
|
||||||
|
byte[] data = bas.toByteArray();
|
||||||
|
m_queue.add( new DatagramPacket( data, data.length ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDevID( byte[] typp )
|
||||||
|
{
|
||||||
|
byte typ;
|
||||||
|
String devid = XWPrefs.getRelayDevID( this );
|
||||||
|
if ( null != devid && 0 < devid.length() ) {
|
||||||
|
typ = UtilCtxt.ID_TYPE_RELAY;
|
||||||
|
} else {
|
||||||
|
devid = XWPrefs.getGCMDevID( this );
|
||||||
|
if ( null != devid && 0 < devid.length() ) {
|
||||||
|
typ = UtilCtxt.ID_TYPE_ANDROID_GCM;
|
||||||
|
} else {
|
||||||
|
devid = "";
|
||||||
|
typ = UtilCtxt.ID_TYPE_ANON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( null != typp ) {
|
||||||
|
typp[0] = typ;
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue( typ == UtilCtxt.ID_TYPE_RELAY );
|
||||||
|
}
|
||||||
|
return devid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void feedMessage( long rowid, byte[] msg )
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "RelayService::feedMessage: %d bytes for rowid %d",
|
||||||
|
msg.length, rowid );
|
||||||
|
if ( BoardActivity.feedMessage( rowid, msg ) ) {
|
||||||
|
DbgUtils.logf( "feedMessage: board ate it" );
|
||||||
|
// do nothing
|
||||||
|
} else {
|
||||||
|
RelayMsgSink sink = new RelayMsgSink();
|
||||||
|
sink.setRowID( rowid );
|
||||||
|
if ( GameUtils.feedMessage( this, rowid, msg, null,
|
||||||
|
sink ) ) {
|
||||||
|
setupNotification( rowid );
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "feedMessage: background dropped it" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void fetchAndProcess()
|
private void fetchAndProcess()
|
||||||
{
|
{
|
||||||
long[][] rowIDss = new long[1][];
|
long[][] rowIDss = new long[1][];
|
||||||
|
@ -256,29 +727,79 @@ public class RelayService extends Service {
|
||||||
private class RelayMsgSink extends MultiMsgSink {
|
private class RelayMsgSink extends MultiMsgSink {
|
||||||
|
|
||||||
private HashMap<String,ArrayList<byte[]>> m_msgLists = null;
|
private HashMap<String,ArrayList<byte[]>> m_msgLists = null;
|
||||||
|
private long m_rowid = -1;
|
||||||
|
|
||||||
|
public void setRowID( long rowid ) { m_rowid = rowid; }
|
||||||
|
|
||||||
public void send( Context context )
|
public void send( Context context )
|
||||||
{
|
{
|
||||||
sendToRelay( context, m_msgLists );
|
if ( -1 == m_rowid ) {
|
||||||
|
sendToRelay( context, m_msgLists );
|
||||||
|
} else {
|
||||||
|
Assert.assertNull( m_msgLists );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** TransportProcs interface *****/
|
/***** TransportProcs interface *****/
|
||||||
|
|
||||||
|
public int transportSend( byte[] buf, final CommsAddrRec addr,
|
||||||
|
int gameID )
|
||||||
|
{
|
||||||
|
Assert.assertTrue( -1 != m_rowid );
|
||||||
|
sendPacket( RelayService.this, m_rowid, buf );
|
||||||
|
return buf.length;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean relayNoConnProc( byte[] buf, String relayID )
|
public boolean relayNoConnProc( byte[] buf, String relayID )
|
||||||
{
|
{
|
||||||
if ( null == m_msgLists ) {
|
if ( -1 != m_rowid ) {
|
||||||
m_msgLists = new HashMap<String,ArrayList<byte[]>>();
|
sendNoConnMessage( m_rowid, relayID, buf );
|
||||||
}
|
} else {
|
||||||
|
if ( null == m_msgLists ) {
|
||||||
|
m_msgLists = new HashMap<String,ArrayList<byte[]>>();
|
||||||
|
}
|
||||||
|
|
||||||
ArrayList<byte[]> list = m_msgLists.get( relayID );
|
ArrayList<byte[]> list = m_msgLists.get( relayID );
|
||||||
if ( list == null ) {
|
if ( list == null ) {
|
||||||
list = new ArrayList<byte[]>();
|
list = new ArrayList<byte[]>();
|
||||||
m_msgLists.put( relayID, list );
|
m_msgLists.put( relayID, list );
|
||||||
|
}
|
||||||
|
list.add( buf );
|
||||||
}
|
}
|
||||||
list.add( buf );
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int nextPacketID( XWRelayReg cmd )
|
||||||
|
{
|
||||||
|
int nextPacketID = 0;
|
||||||
|
synchronized( s_packetsSent ) {
|
||||||
|
if ( XWRelayReg.XWPDEV_ACK != cmd ) {
|
||||||
|
nextPacketID = s_nextPacketID++;
|
||||||
|
s_packetsSent.add( nextPacketID );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DbgUtils.logf( "nextPacketID(%s)=>%d", cmd.toString(), nextPacketID );
|
||||||
|
return nextPacketID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void noteAck( int packetID )
|
||||||
|
{
|
||||||
|
synchronized( s_packetsSent ) {
|
||||||
|
s_packetsSent.remove( packetID );
|
||||||
|
DbgUtils.logf( "Got ack for %d; there are %d unacked packets",
|
||||||
|
packetID, s_packetsSent.size() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PacketHeader {
|
||||||
|
public int m_packetID;
|
||||||
|
public XWRelayReg m_cmd;
|
||||||
|
public PacketHeader( XWRelayReg cmd, int packetID ) {
|
||||||
|
DbgUtils.logf( "in PacketHeader contructor" );
|
||||||
|
m_packetID = packetID;
|
||||||
|
m_cmd = cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.telephony.SmsManager;
|
import android.telephony.SmsManager;
|
||||||
import android.telephony.SmsMessage;
|
import android.telephony.SmsMessage;
|
||||||
|
@ -52,7 +51,7 @@ import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
|
||||||
public class SMSService extends Service {
|
public class SMSService extends XWService {
|
||||||
|
|
||||||
private static final String INSTALL_URL = "http://eehouse.org/_/a.py/a ";
|
private static final String INSTALL_URL = "http://eehouse.org/_/a.py/a ";
|
||||||
private static final int MAX_SMS_LEN = 140; // ??? differs by network
|
private static final int MAX_SMS_LEN = 140; // ??? differs by network
|
||||||
|
@ -66,7 +65,7 @@ public class SMSService extends Service {
|
||||||
private static final int INVITE = 2;
|
private static final int INVITE = 2;
|
||||||
private static final int SEND = 3;
|
private static final int SEND = 3;
|
||||||
private static final int REMOVE = 4;
|
private static final int REMOVE = 4;
|
||||||
private static final int MESG_GAMEGONE = 5;
|
// private static final int MESG_GAMEGONE = 5;
|
||||||
private static final int CHECK_MSGDB = 6;
|
private static final int CHECK_MSGDB = 6;
|
||||||
private static final int ADDED_MISSING = 7;
|
private static final int ADDED_MISSING = 7;
|
||||||
private static final int STOP_SELF = 8;
|
private static final int STOP_SELF = 8;
|
||||||
|
@ -77,7 +76,6 @@ public class SMSService extends Service {
|
||||||
private static final String PHONE = "PHONE";
|
private static final String PHONE = "PHONE";
|
||||||
|
|
||||||
private static Boolean s_showToasts = null;
|
private static Boolean s_showToasts = null;
|
||||||
private static MultiService s_srcMgr = null;
|
|
||||||
|
|
||||||
// All messages are base64-encoded byte arrays. The first byte is
|
// All messages are base64-encoded byte arrays. The first byte is
|
||||||
// always one of these. What follows depends.
|
// always one of these. What follows depends.
|
||||||
|
@ -196,16 +194,6 @@ public class SMSService extends Service {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setListener( MultiService.MultiEventListener li )
|
|
||||||
{
|
|
||||||
if ( XWApp.SMSSUPPORTED ) {
|
|
||||||
if ( null == s_srcMgr ) {
|
|
||||||
s_srcMgr = new MultiService();
|
|
||||||
}
|
|
||||||
s_srcMgr.setListener( li );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Intent getIntentTo( Context context, int cmd )
|
private static Intent getIntentTo( Context context, int cmd )
|
||||||
{
|
{
|
||||||
if ( null == s_showToasts ) {
|
if ( null == s_showToasts ) {
|
||||||
|
@ -303,12 +291,6 @@ public class SMSService extends Service {
|
||||||
return result;
|
return result;
|
||||||
} // onStartCommand
|
} // onStartCommand
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind( Intent intent )
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inviteRemote( String phone, int gameID, String gameName,
|
private void inviteRemote( String phone, int gameID, String gameName,
|
||||||
int lang, String dict,
|
int lang, String dict,
|
||||||
int nPlayersT, int nPlayersH )
|
int nPlayersT, int nPlayersH )
|
||||||
|
@ -662,13 +644,6 @@ public class SMSService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendResult( MultiEvent event, Object ... args )
|
|
||||||
{
|
|
||||||
if ( null != s_srcMgr ) {
|
|
||||||
s_srcMgr.sendResult( event, args );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerReceivers()
|
private void registerReceivers()
|
||||||
{
|
{
|
||||||
registerReceiver( new BroadcastReceiver() {
|
registerReceiver( new BroadcastReceiver() {
|
||||||
|
|
|
@ -54,8 +54,7 @@ public class XWActivity extends Activity
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
||||||
BTService.setListener( this );
|
XWService.setListener( this );
|
||||||
SMSService.setListener( this );
|
|
||||||
super.onResume();
|
super.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +62,7 @@ public class XWActivity extends Activity
|
||||||
protected void onPause()
|
protected void onPause()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
||||||
BTService.setListener( null );
|
XWService.setListener( null );
|
||||||
SMSService.setListener( null );
|
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,10 @@ public class XWApp extends Application {
|
||||||
|
|
||||||
RelayReceiver.RestartTimer( this );
|
RelayReceiver.RestartTimer( this );
|
||||||
UpdateCheckReceiver.restartTimer( this );
|
UpdateCheckReceiver.restartTimer( this );
|
||||||
|
|
||||||
BTService.startService( this );
|
BTService.startService( this );
|
||||||
|
|
||||||
SMSService.checkForInvites( this );
|
SMSService.checkForInvites( this );
|
||||||
|
RelayService.startService( this );
|
||||||
GCMIntentService.init( this );
|
GCMIntentService.init( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,22 @@ public class XWExpandableListActivity extends ExpandableListActivity
|
||||||
m_delegate = new DlgDelegate( this, this, savedInstanceState );
|
m_delegate = new DlgDelegate( this, this, savedInstanceState );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
||||||
|
XWService.setListener( this );
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause()
|
||||||
|
{
|
||||||
|
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
||||||
|
XWService.setListener( null );
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState( Bundle outState )
|
protected void onSaveInstanceState( Bundle outState )
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,8 +51,7 @@ public class XWListActivity extends ListActivity
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
||||||
BTService.setListener( this );
|
XWService.setListener( this );
|
||||||
SMSService.setListener( this );
|
|
||||||
super.onResume();
|
super.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +59,7 @@ public class XWListActivity extends ListActivity
|
||||||
protected void onPause()
|
protected void onPause()
|
||||||
{
|
{
|
||||||
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
||||||
BTService.setListener( null );
|
XWService.setListener( null );
|
||||||
SMSService.setListener( null );
|
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,16 @@ public class XWPrefs {
|
||||||
return getPrefsBoolean( context, R.string.key_enable_sms, false );
|
return getPrefsBoolean( context, R.string.key_enable_sms, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean getUDPEnabled( Context context )
|
||||||
|
{
|
||||||
|
return getPrefsBoolean( context, R.string.key_udp_relay, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getGCMIgnored( Context context )
|
||||||
|
{
|
||||||
|
return getPrefsBoolean( context, R.string.key_drop_gcm, false );
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean getDebugEnabled( Context context )
|
public static boolean getDebugEnabled( Context context )
|
||||||
{
|
{
|
||||||
return getPrefsBoolean( context, R.string.key_enable_debug, false );
|
return getPrefsBoolean( context, R.string.key_enable_debug, false );
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2010 - 2012 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
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||||
|
|
||||||
|
|
||||||
|
public class XWService extends Service {
|
||||||
|
|
||||||
|
protected static MultiService s_srcMgr = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind( Intent intent )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static void setListener( MultiService.MultiEventListener li )
|
||||||
|
{
|
||||||
|
if ( null == s_srcMgr ) {
|
||||||
|
DbgUtils.logf( "setListener: registering %s", li.getClass().getName() );
|
||||||
|
s_srcMgr = new MultiService();
|
||||||
|
}
|
||||||
|
s_srcMgr.setListener( li );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendResult( MultiEvent event, Object ... args )
|
||||||
|
{
|
||||||
|
if ( null != s_srcMgr ) {
|
||||||
|
s_srcMgr.sendResult( event, args );
|
||||||
|
} else {
|
||||||
|
DbgUtils.logf( "sendResult: dropping event" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -286,6 +286,9 @@ public class JNIThread extends Thread {
|
||||||
// state. In some cases it'll otherwise drop the move.
|
// state. In some cases it'll otherwise drop the move.
|
||||||
XwJNI.server_do( m_jniGamePtr );
|
XwJNI.server_do( m_jniGamePtr );
|
||||||
|
|
||||||
|
// And let it tell the relay (if any) it's leaving
|
||||||
|
XwJNI.comms_stop( m_jniGamePtr );
|
||||||
|
|
||||||
XwJNI.game_getGi( m_jniGamePtr, m_gi );
|
XwJNI.game_getGi( m_jniGamePtr, m_gi );
|
||||||
if ( null != m_newDict ) {
|
if ( null != m_newDict ) {
|
||||||
m_gi.dictName = m_newDict;
|
m_gi.dictName = m_newDict;
|
||||||
|
|
|
@ -60,6 +60,8 @@ public interface UtilCtxt {
|
||||||
public static final int ID_TYPE_NONE = 0;
|
public static final int ID_TYPE_NONE = 0;
|
||||||
public static final int ID_TYPE_RELAY = 1;
|
public static final int ID_TYPE_RELAY = 1;
|
||||||
public static final int ID_TYPE_ANDROID_GCM = 3;
|
public static final int ID_TYPE_ANDROID_GCM = 3;
|
||||||
|
public static final int ID_TYPE_ANDROID_OTHER = 4;
|
||||||
|
public static final int ID_TYPE_ANON = 5;
|
||||||
|
|
||||||
String getDevID( /*out*/ byte[] typ );
|
String getDevID( /*out*/ byte[] typ );
|
||||||
void deviceRegistered( int devIDType, String idRelay );
|
void deviceRegistered( int devIDType, String idRelay );
|
||||||
|
|
|
@ -234,6 +234,7 @@ public class XwJNI {
|
||||||
|
|
||||||
// Comms
|
// Comms
|
||||||
public static native void comms_start( int gamePtr );
|
public static native void comms_start( int gamePtr );
|
||||||
|
public static native void comms_stop( int gamePtr );
|
||||||
public static native void comms_resetSame( int gamePtr );
|
public static native void comms_resetSame( int gamePtr );
|
||||||
public static native void comms_getAddr( int gamePtr, CommsAddrRec addr );
|
public static native void comms_getAddr( int gamePtr, CommsAddrRec addr );
|
||||||
public static native CommsAddrRec[] comms_getAddrs( int gamePtr );
|
public static native CommsAddrRec[] comms_getAddrs( int gamePtr );
|
||||||
|
|
|
@ -467,8 +467,11 @@ comms_transportFailed( CommsCtxt* comms )
|
||||||
void
|
void
|
||||||
comms_destroy( CommsCtxt* comms )
|
comms_destroy( CommsCtxt* comms )
|
||||||
{
|
{
|
||||||
CommsAddrRec aNew;
|
/* did I call comms_stop()? */
|
||||||
aNew.conType = COMMS_CONN_NONE;
|
XP_ASSERT( COMMS_CONN_RELAY != comms->addr.conType
|
||||||
|
|| COMMS_RELAYSTATE_UNCONNECTED == comms->r.relayState );
|
||||||
|
|
||||||
|
CommsAddrRec aNew = { .conType = COMMS_CONN_NONE };
|
||||||
util_addrChange( comms->util, &comms->addr, &aNew );
|
util_addrChange( comms->util, &comms->addr, &aNew );
|
||||||
|
|
||||||
cleanupInternal( comms );
|
cleanupInternal( comms );
|
||||||
|
@ -665,6 +668,14 @@ comms_start( CommsCtxt* comms )
|
||||||
sendConnect( comms, XP_FALSE );
|
sendConnect( comms, XP_FALSE );
|
||||||
} /* comms_start */
|
} /* comms_start */
|
||||||
|
|
||||||
|
void
|
||||||
|
comms_stop( CommsCtxt* comms )
|
||||||
|
{
|
||||||
|
if ( COMMS_CONN_RELAY == comms->addr.conType ) {
|
||||||
|
relayDisconnect( comms );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendConnect( CommsCtxt* comms, XP_Bool breakExisting )
|
sendConnect( CommsCtxt* comms, XP_Bool breakExisting )
|
||||||
{
|
{
|
||||||
|
@ -1185,6 +1196,14 @@ gameID( const CommsCtxt* comms )
|
||||||
gameID = comms->util->gameInfo->gameID;
|
gameID = comms->util->gameInfo->gameID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XP_ASSERT( 0 != gameID );
|
||||||
|
if ( 0 == gameID ) {
|
||||||
|
XP_LOGF( "%s: gameID STILL 0", __func__ );
|
||||||
|
} else if ( 0 == comms->util->gameInfo->gameID ) {
|
||||||
|
XP_LOGF( "%s: setting gi's gameID to 0X%lX", __func__, gameID );
|
||||||
|
comms->util->gameInfo->gameID = gameID;
|
||||||
|
}
|
||||||
|
|
||||||
/* Most of the time these will be the same, but early in a game they won't
|
/* Most of the time these will be the same, but early in a game they won't
|
||||||
be. Would be nice not to have to use gameID. */
|
be. Would be nice not to have to use gameID. */
|
||||||
if ( 0 == gameID ) {
|
if ( 0 == gameID ) {
|
||||||
|
|
|
@ -198,6 +198,7 @@ CommsCtxt* comms_makeFromStream( MPFORMAL XWStreamCtxt* stream,
|
||||||
XW_UtilCtxt* util,
|
XW_UtilCtxt* util,
|
||||||
const TransportProcs* procs );
|
const TransportProcs* procs );
|
||||||
void comms_start( CommsCtxt* comms );
|
void comms_start( CommsCtxt* comms );
|
||||||
|
void comms_stop( CommsCtxt* comms );
|
||||||
void comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
void comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
XP_U16 saveToken );
|
XP_U16 saveToken );
|
||||||
void comms_saveSucceeded( CommsCtxt* comms, XP_U16 saveToken );
|
void comms_saveSucceeded( CommsCtxt* comms, XP_U16 saveToken );
|
||||||
|
|
|
@ -249,7 +249,7 @@ typedef struct _PlayerDicts {
|
||||||
# define RELAY_ROOM_DEFAULT "Room 1"
|
# define RELAY_ROOM_DEFAULT "Room 1"
|
||||||
#endif
|
#endif
|
||||||
#ifndef RELAY_PORT_DEFAULT
|
#ifndef RELAY_PORT_DEFAULT
|
||||||
# define RELAY_PORT_DEFAULT 10999
|
# define RELAY_PORT_DEFAULT 10997
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
|
|
|
@ -133,62 +133,67 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
board_prefsChanged( game->board, cp );
|
board_prefsChanged( game->board, cp );
|
||||||
} /* game_makeNewGame */
|
} /* game_makeNewGame */
|
||||||
|
|
||||||
void
|
XP_Bool
|
||||||
game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
|
game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
XW_UtilCtxt* XP_UNUSED_STANDALONE(util),
|
XW_UtilCtxt* XP_UNUSED_STANDALONE(util),
|
||||||
CommonPrefs* cp, const TransportProcs* procs )
|
CommonPrefs* cp, const TransportProcs* procs )
|
||||||
{
|
{
|
||||||
|
XP_Bool result = XP_FALSE;
|
||||||
XP_U16 ii;
|
XP_U16 ii;
|
||||||
|
|
||||||
XP_ASSERT( !!game->model );
|
if ( !!game->model ) {
|
||||||
XP_ASSERT( !!gi );
|
XP_ASSERT( !!game->model );
|
||||||
|
XP_ASSERT( !!gi );
|
||||||
|
|
||||||
gi->gameID = makeGameID( util );
|
gi->gameID = makeGameID( util );
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
XP_U16 nPlayersHere = 0;
|
XP_U16 nPlayersHere = 0;
|
||||||
XP_U16 nPlayersTotal = 0;
|
XP_U16 nPlayersTotal = 0;
|
||||||
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
|
||||||
|
|
||||||
if ( !!game->comms ) {
|
if ( !!game->comms ) {
|
||||||
if ( gi->serverRole == SERVER_STANDALONE ) {
|
if ( gi->serverRole == SERVER_STANDALONE ) {
|
||||||
comms_destroy( game->comms );
|
comms_destroy( game->comms );
|
||||||
game->comms = NULL;
|
game->comms = NULL;
|
||||||
} else {
|
} else {
|
||||||
comms_reset( game->comms, gi->serverRole != SERVER_ISCLIENT,
|
comms_reset( game->comms, gi->serverRole != SERVER_ISCLIENT,
|
||||||
nPlayersHere, nPlayersTotal );
|
nPlayersHere, nPlayersTotal );
|
||||||
}
|
}
|
||||||
} else if ( gi->serverRole != SERVER_STANDALONE ) {
|
} else if ( gi->serverRole != SERVER_STANDALONE ) {
|
||||||
game->comms = comms_make( MPPARM(mpool) util,
|
game->comms = comms_make( MPPARM(mpool) util,
|
||||||
gi->serverRole != SERVER_ISCLIENT,
|
gi->serverRole != SERVER_ISCLIENT,
|
||||||
nPlayersHere, nPlayersTotal, procs
|
nPlayersHere, nPlayersTotal, procs
|
||||||
#ifdef SET_GAMESEED
|
#ifdef SET_GAMESEED
|
||||||
, 0
|
, 0
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# ifdef DEBUG
|
# ifdef DEBUG
|
||||||
mpool = mpool; /* quash unused formal warning */
|
mpool = mpool; /* quash unused formal warning */
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
model_setSize( game->model, gi->boardSize );
|
model_setSize( game->model, gi->boardSize );
|
||||||
server_reset( game->server,
|
server_reset( game->server,
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
game->comms
|
game->comms
|
||||||
#else
|
#else
|
||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
board_reset( game->board );
|
board_reset( game->board );
|
||||||
|
|
||||||
for ( ii = 0; ii < gi->nPlayers; ++ii ) {
|
for ( ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||||
gi->players[ii].secondsUsed = 0;
|
gi->players[ii].secondsUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_prefsChanged( game->server, cp );
|
||||||
|
board_prefsChanged( game->board, cp );
|
||||||
|
result = XP_TRUE;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
server_prefsChanged( game->server, cp );
|
|
||||||
board_prefsChanged( game->board, cp );
|
|
||||||
} /* game_reset */
|
} /* game_reset */
|
||||||
|
|
||||||
#ifdef XWFEATURE_CHANGEDICT
|
#ifdef XWFEATURE_CHANGEDICT
|
||||||
|
@ -335,6 +340,7 @@ game_dispose( XWGame* game )
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
if ( !!game->comms ) {
|
if ( !!game->comms ) {
|
||||||
|
comms_stop( game->comms );
|
||||||
comms_destroy( game->comms );
|
comms_destroy( game->comms );
|
||||||
game->comms = NULL;
|
game->comms = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,8 @@ void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
,XP_U16 gameSeed
|
,XP_U16 gameSeed
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
void game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
|
XP_Bool game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
|
||||||
CommonPrefs* cp, const TransportProcs* procs );
|
CommonPrefs* cp, const TransportProcs* procs );
|
||||||
void game_changeDict( MPFORMAL XWGame* game, CurGameInfo* gi,
|
void game_changeDict( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||||
DictionaryCtxt* dict );
|
DictionaryCtxt* dict );
|
||||||
|
|
||||||
|
|
|
@ -78,19 +78,21 @@ checkIsText( MemPoolEntry* entry )
|
||||||
{
|
{
|
||||||
unsigned char* txt = (unsigned char*)entry->ptr;
|
unsigned char* txt = (unsigned char*)entry->ptr;
|
||||||
XP_U32 len = entry->size;
|
XP_U32 len = entry->size;
|
||||||
|
char* result = NULL;
|
||||||
|
|
||||||
while ( len-- ) {
|
if ( 0 < len ) {
|
||||||
unsigned char c = *txt++;
|
while ( len-- ) {
|
||||||
if ( c < 32 || c > 127 ) {
|
unsigned char c = *txt++;
|
||||||
if ( len == 0 && c == '\0' ) {
|
if ( c < 32 || c > 127 ) {
|
||||||
return (char*)entry->ptr;
|
if ( len == 0 && c == '\0' ) {
|
||||||
} else {
|
result = (char*)entry->ptr;
|
||||||
return (char*)NULL;
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (char*)NULL;
|
return result;
|
||||||
} /* checkIsText */
|
} /* checkIsText */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -226,6 +228,7 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
|
||||||
if ( !entry ) {
|
if ( !entry ) {
|
||||||
XP_LOGF( "findEntryFor failed; called from %s, line %ld in %s",
|
XP_LOGF( "findEntryFor failed; called from %s, line %ld in %s",
|
||||||
func, lineNo, file );
|
func, lineNo, file );
|
||||||
|
XP_ASSERT( 0 );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
#ifdef MPOOL_DEBUG
|
#ifdef MPOOL_DEBUG
|
||||||
|
@ -249,11 +252,7 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
|
||||||
|
|
||||||
++mpool->nFree;
|
++mpool->nFree;
|
||||||
--mpool->nUsed;
|
--mpool->nUsed;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_ASSERT( 0 );
|
|
||||||
} /* mpool_free */
|
} /* mpool_free */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
1
xwords4/linux/.gitignore
vendored
1
xwords4/linux/.gitignore
vendored
|
@ -6,3 +6,4 @@ obj_linux_rel
|
||||||
log_*_*.txt
|
log_*_*.txt
|
||||||
discon_ok2.sh_logs
|
discon_ok2.sh_logs
|
||||||
test_backsend.sh_*
|
test_backsend.sh_*
|
||||||
|
games.db
|
||||||
|
|
|
@ -101,6 +101,7 @@ DEFINES += -DXWFEATURE_WALKDICT
|
||||||
DEFINES += -DXWFEATURE_WALKDICT_FILTER
|
DEFINES += -DXWFEATURE_WALKDICT_FILTER
|
||||||
DEFINES += -DXWFEATURE_DICTSANITY
|
DEFINES += -DXWFEATURE_DICTSANITY
|
||||||
DEFINES += -DHASH_STREAM
|
DEFINES += -DHASH_STREAM
|
||||||
|
DEFINES += -DRELAY_NAME_DEFAULT="\"localhost\""
|
||||||
#DEFINES += -DXWFEATURE_SCOREONEPASS
|
#DEFINES += -DXWFEATURE_SCOREONEPASS
|
||||||
### Enable zero or one of these two ###
|
### Enable zero or one of these two ###
|
||||||
#DEFINES += -DXWFEATURE_TRAYUNDO_ALL
|
#DEFINES += -DXWFEATURE_TRAYUNDO_ALL
|
||||||
|
@ -112,6 +113,7 @@ DEFINES += -DXWFEATURE_HILITECELL
|
||||||
DEFINES += -DXWFEATURE_CHANGEDICT
|
DEFINES += -DXWFEATURE_CHANGEDICT
|
||||||
DEFINES += -DXWFEATURE_DEVID
|
DEFINES += -DXWFEATURE_DEVID
|
||||||
DEFINES += -DXWFEATURE_COMMSACK
|
DEFINES += -DXWFEATURE_COMMSACK
|
||||||
|
DEFINES += -DCOMMS_XPORT_FLAGSPROC
|
||||||
|
|
||||||
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
||||||
DEFINES += -DMAX_ROWS=32
|
DEFINES += -DMAX_ROWS=32
|
||||||
|
@ -169,6 +171,7 @@ INCLUDES += ${EXTRAINCS}
|
||||||
ifdef DO_GTK
|
ifdef DO_GTK
|
||||||
GTK_OBJS = \
|
GTK_OBJS = \
|
||||||
$(BUILD_PLAT_DIR)/gtkmain.o \
|
$(BUILD_PLAT_DIR)/gtkmain.o \
|
||||||
|
$(BUILD_PLAT_DIR)/gtkboard.o \
|
||||||
$(BUILD_PLAT_DIR)/gtkdraw.o \
|
$(BUILD_PLAT_DIR)/gtkdraw.o \
|
||||||
$(BUILD_PLAT_DIR)/gtkask.o \
|
$(BUILD_PLAT_DIR)/gtkask.o \
|
||||||
$(BUILD_PLAT_DIR)/gtkletterask.o \
|
$(BUILD_PLAT_DIR)/gtkletterask.o \
|
||||||
|
@ -201,6 +204,8 @@ OBJ = \
|
||||||
$(BUILD_PLAT_DIR)/linuxsms.o \
|
$(BUILD_PLAT_DIR)/linuxsms.o \
|
||||||
$(BUILD_PLAT_DIR)/linuxdict.o \
|
$(BUILD_PLAT_DIR)/linuxdict.o \
|
||||||
$(BUILD_PLAT_DIR)/linuxutl.o \
|
$(BUILD_PLAT_DIR)/linuxutl.o \
|
||||||
|
$(BUILD_PLAT_DIR)/gamesdb.o \
|
||||||
|
$(BUILD_PLAT_DIR)/relaycon.o \
|
||||||
$(CURSES_OBJS) $(GTK_OBJS) $(MAIN_OBJS)
|
$(CURSES_OBJS) $(GTK_OBJS) $(MAIN_OBJS)
|
||||||
|
|
||||||
LIBS = -lm -luuid $(GPROFFLAG)
|
LIBS = -lm -luuid $(GPROFFLAG)
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
/* Figure out how many lines there are and how wide the widest is.
|
/* Figure out how many lines there are and how wide the widest is.
|
||||||
*/
|
*/
|
||||||
short
|
short
|
||||||
cursesask( CursesAppGlobals* globals, char* question, short numButtons,
|
cursesask( CursesAppGlobals* globals, const char* question, short numButtons,
|
||||||
char* button1, ... )
|
const char* button1, ... )
|
||||||
{
|
{
|
||||||
WINDOW* confWin;
|
WINDOW* confWin;
|
||||||
int x, y, rows, row, nLines;
|
int x, y, rows, row, nLines;
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
#include "cursesmain.h"
|
#include "cursesmain.h"
|
||||||
|
|
||||||
short cursesask( CursesAppGlobals* globals, char* question,
|
short cursesask( CursesAppGlobals* globals, const char* question,
|
||||||
short numButtons, char* button1, ... );
|
short numButtons, const char* button1, ... );
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,7 +70,7 @@ measureAskText( const XP_UCHAR* question, int width, FormatInfo* fip )
|
||||||
|
|
||||||
void
|
void
|
||||||
drawButtons( WINDOW* win, XP_U16 line, short spacePerButton,
|
drawButtons( WINDOW* win, XP_U16 line, short spacePerButton,
|
||||||
short numButtons, short curSelButton, char** button1 )
|
short numButtons, short curSelButton, const char** button1 )
|
||||||
{
|
{
|
||||||
short i;
|
short i;
|
||||||
for ( i = 0; i < numButtons; ++i ) {
|
for ( i = 0; i < numButtons; ++i ) {
|
||||||
|
|
|
@ -44,6 +44,6 @@ typedef struct FormatInfo {
|
||||||
void measureAskText( const XP_UCHAR* question, int maxWidth, FormatInfo* fip );
|
void measureAskText( const XP_UCHAR* question, int maxWidth, FormatInfo* fip );
|
||||||
|
|
||||||
void drawButtons( WINDOW* confWin, XP_U16 line, short spacePerButton,
|
void drawButtons( WINDOW* confWin, XP_U16 line, short spacePerButton,
|
||||||
short numButtons, short curSelButton, char** button1 );
|
short numButtons, short curSelButton, const char** button1 );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -57,7 +57,7 @@ curses_askLetter( CursesAppGlobals* globals, XP_UCHAR* query,
|
||||||
short curSelButton = 1; /* force draw by being different */
|
short curSelButton = 1; /* force draw by being different */
|
||||||
short maxWidth;
|
short maxWidth;
|
||||||
short numCtlButtons;
|
short numCtlButtons;
|
||||||
char* ctlButtons[] = { "Ok", "Cancel" };
|
const char* ctlButtons[] = { "Ok", "Cancel" };
|
||||||
XP_Bool dismissed = XP_FALSE;
|
XP_Bool dismissed = XP_FALSE;
|
||||||
FormatInfo fi;
|
FormatInfo fi;
|
||||||
int len;
|
int len;
|
||||||
|
@ -138,7 +138,7 @@ curses_askLetter( CursesAppGlobals* globals, XP_UCHAR* query,
|
||||||
MAX_TILE_BUTTON_WIDTH-1,
|
MAX_TILE_BUTTON_WIDTH-1,
|
||||||
nInRow,
|
nInRow,
|
||||||
newSelButton - textsOffsets[i],
|
newSelButton - textsOffsets[i],
|
||||||
(char**)&textPtrs[textsOffsets[i]] );
|
(const char**)&textPtrs[textsOffsets[i]] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include "linuxmain.h"
|
#include "linuxmain.h"
|
||||||
#include "linuxutl.h"
|
#include "linuxutl.h"
|
||||||
|
#include "linuxdict.h"
|
||||||
#include "cursesmain.h"
|
#include "cursesmain.h"
|
||||||
#include "cursesask.h"
|
#include "cursesask.h"
|
||||||
#include "cursesletterask.h"
|
#include "cursesletterask.h"
|
||||||
|
@ -61,6 +62,8 @@
|
||||||
#include "dbgutil.h"
|
#include "dbgutil.h"
|
||||||
#include "linuxsms.h"
|
#include "linuxsms.h"
|
||||||
#include "linuxudp.h"
|
#include "linuxudp.h"
|
||||||
|
#include "gamesdb.h"
|
||||||
|
#include "relaycon.h"
|
||||||
|
|
||||||
#ifdef CURSES_SMALL_SCREEN
|
#ifdef CURSES_SMALL_SCREEN
|
||||||
# define MENU_WINDOW_HEIGHT 1
|
# define MENU_WINDOW_HEIGHT 1
|
||||||
|
@ -208,7 +211,7 @@ static CursesMenuHandler getHandlerForKey( const MenuList* list, char ch );
|
||||||
|
|
||||||
|
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
# define MEMPOOL params->util->mpool,
|
# define MEMPOOL cGlobals->util->mpool,
|
||||||
#else
|
#else
|
||||||
# define MEMPOOL
|
# define MEMPOOL
|
||||||
#endif
|
#endif
|
||||||
|
@ -237,7 +240,7 @@ curses_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
char query[128];
|
char query[128];
|
||||||
XP_S16 index;
|
XP_S16 index;
|
||||||
char* playerName = globals->cGlobals.params->gi.players[playerNum].name;
|
char* playerName = globals->cGlobals.gi->players[playerNum].name;
|
||||||
|
|
||||||
snprintf( query, sizeof(query),
|
snprintf( query, sizeof(query),
|
||||||
"Pick tile for %s! (Tab or type letter to select "
|
"Pick tile for %s! (Tab or type letter to select "
|
||||||
|
@ -255,7 +258,7 @@ curses_util_userPickTileTray( XW_UtilCtxt* uc, const PickInfo* XP_UNUSED(pi),
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
char query[128];
|
char query[128];
|
||||||
XP_S16 index;
|
XP_S16 index;
|
||||||
char* playerName = globals->cGlobals.params->gi.players[playerNum].name;
|
char* playerName = globals->cGlobals.gi->players[playerNum].name;
|
||||||
|
|
||||||
snprintf( query, sizeof(query),
|
snprintf( query, sizeof(query),
|
||||||
"Pick tile for %s! (Tab or type letter to select "
|
"Pick tile for %s! (Tab or type letter to select "
|
||||||
|
@ -343,7 +346,7 @@ cursesShowFinalScores( CursesAppGlobals* globals )
|
||||||
XWStreamCtxt* stream;
|
XWStreamCtxt* stream;
|
||||||
XP_UCHAR* text;
|
XP_UCHAR* text;
|
||||||
|
|
||||||
stream = mem_stream_make( MPPARM(globals->cGlobals.params->util->mpool)
|
stream = mem_stream_make( MPPARM(globals->cGlobals.util->mpool)
|
||||||
globals->cGlobals.params->vtMgr,
|
globals->cGlobals.params->vtMgr,
|
||||||
globals, CHANNEL_NONE, NULL );
|
globals, CHANNEL_NONE, NULL );
|
||||||
server_writeFinalScores( globals->cGlobals.game.server, stream );
|
server_writeFinalScores( globals->cGlobals.game.server, stream );
|
||||||
|
@ -408,6 +411,14 @@ curses_util_informNetDict( XW_UtilCtxt* uc, XP_LangCode XP_UNUSED(lang),
|
||||||
XP_LOGF( "%s: %s => %s (cksum: %s)", __func__, oldName, newName, newSum );
|
XP_LOGF( "%s: %s => %s (cksum: %s)", __func__, oldName, newName, newSum );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
curses_util_setIsServer( XW_UtilCtxt* uc, XP_Bool isServer )
|
||||||
|
{
|
||||||
|
LOG_FUNC();
|
||||||
|
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||||
|
linuxSetIsServer( cGlobals, isServer );
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef XWFEATURE_HILITECELL
|
#ifdef XWFEATURE_HILITECELL
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
curses_util_hiliteCell( XW_UtilCtxt* uc,
|
curses_util_hiliteCell( XW_UtilCtxt* uc,
|
||||||
|
@ -1039,7 +1050,7 @@ data_socket_proc( GIOChannel* source, GIOCondition condition, gpointer data )
|
||||||
if ( 0 != (G_IO_IN & condition) ) {
|
if ( 0 != (G_IO_IN & condition) ) {
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
||||||
int fd = g_io_channel_unix_get_fd( source );
|
int fd = g_io_channel_unix_get_fd( source );
|
||||||
unsigned char buf[256];
|
unsigned char buf[1024];
|
||||||
int nBytes;
|
int nBytes;
|
||||||
CommsAddrRec addrRec;
|
CommsAddrRec addrRec;
|
||||||
CommsAddrRec* addrp = NULL;
|
CommsAddrRec* addrp = NULL;
|
||||||
|
@ -1087,7 +1098,7 @@ data_socket_proc( GIOChannel* source, GIOCondition condition, gpointer data )
|
||||||
that on the screen before giving the server another
|
that on the screen before giving the server another
|
||||||
shot. So just call the idle proc. */
|
shot. So just call the idle proc. */
|
||||||
if ( redraw ) {
|
if ( redraw ) {
|
||||||
curses_util_requestTime( globals->cGlobals.params->util );
|
curses_util_requestTime( globals->cGlobals.util );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,6 +1127,15 @@ curses_socket_changed( void* closure, int oldSock, int newSock,
|
||||||
#endif
|
#endif
|
||||||
} /* curses_socket_changed */
|
} /* curses_socket_changed */
|
||||||
|
|
||||||
|
static void
|
||||||
|
curses_onGameSaved( void* closure, sqlite3_int64 rowid,
|
||||||
|
XP_Bool XP_UNUSED(firstTime) )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
/* May not be recorded */
|
||||||
|
globals->cGlobals.selRow = rowid;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_GLIBLOOP
|
#ifdef USE_GLIBLOOP
|
||||||
static gboolean
|
static gboolean
|
||||||
handle_quitwrite( GIOChannel* XP_UNUSED(source), GIOCondition XP_UNUSED(condition), gpointer data )
|
handle_quitwrite( GIOChannel* XP_UNUSED(source), GIOCondition XP_UNUSED(condition), gpointer data )
|
||||||
|
@ -1284,7 +1304,7 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch )
|
||||||
globals );
|
globals );
|
||||||
} else {
|
} else {
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
unsigned char buf[256];
|
unsigned char buf[1024];
|
||||||
int nBytes;
|
int nBytes;
|
||||||
CommsAddrRec addrRec;
|
CommsAddrRec addrRec;
|
||||||
CommsAddrRec* addrp = NULL;
|
CommsAddrRec* addrp = NULL;
|
||||||
|
@ -1489,7 +1509,7 @@ curses_util_remSelected( XW_UtilCtxt* uc )
|
||||||
XWStreamCtxt* stream;
|
XWStreamCtxt* stream;
|
||||||
XP_UCHAR* text;
|
XP_UCHAR* text;
|
||||||
|
|
||||||
stream = mem_stream_make( MPPARM(globals->cGlobals.params->util->mpool)
|
stream = mem_stream_make( MPPARM(globals->cGlobals.util->mpool)
|
||||||
globals->cGlobals.params->vtMgr,
|
globals->cGlobals.params->vtMgr,
|
||||||
globals, CHANNEL_NONE, NULL );
|
globals, CHANNEL_NONE, NULL );
|
||||||
board_formatRemainingTiles( globals->cGlobals.game.board, stream );
|
board_formatRemainingTiles( globals->cGlobals.game.board, stream );
|
||||||
|
@ -1553,6 +1573,8 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
|
||||||
util->vtable->m_util_informUndo = curses_util_informUndo;
|
util->vtable->m_util_informUndo = curses_util_informUndo;
|
||||||
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
|
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
|
||||||
util->vtable->m_util_informNetDict = curses_util_informNetDict;
|
util->vtable->m_util_informNetDict = curses_util_informNetDict;
|
||||||
|
util->vtable->m_util_setIsServer = curses_util_setIsServer;
|
||||||
|
|
||||||
#ifdef XWFEATURE_HILITECELL
|
#ifdef XWFEATURE_HILITECELL
|
||||||
util->vtable->m_util_hiliteCell = curses_util_hiliteCell;
|
util->vtable->m_util_hiliteCell = curses_util_hiliteCell;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1609,7 +1631,7 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height )
|
||||||
XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth;
|
XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth;
|
||||||
BoardCtxt* board = globals->cGlobals.game.board;
|
BoardCtxt* board = globals->cGlobals.game.board;
|
||||||
int remWidth = width;
|
int remWidth = width;
|
||||||
int nRows = globals->cGlobals.params->gi.boardSize;
|
int nRows = globals->cGlobals.gi->boardSize;
|
||||||
|
|
||||||
cellWidth = CURSES_CELL_WIDTH;
|
cellWidth = CURSES_CELL_WIDTH;
|
||||||
cellHt = CURSES_CELL_HT;
|
cellHt = CURSES_CELL_HT;
|
||||||
|
@ -1719,6 +1741,119 @@ handle_stdin( GIOChannel* XP_UNUSED_DBG(source), GIOCondition condition,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef COMMS_XPORT_FLAGSPROC
|
||||||
|
static XP_U32
|
||||||
|
curses_getFlags( void* XP_UNUSED(closure) )
|
||||||
|
{
|
||||||
|
return COMMS_XPORT_FLAGS_HASNOCONN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursesGotBuf( void* closure, const XP_U8* buf, XP_U16 len )
|
||||||
|
{
|
||||||
|
LOG_FUNC();
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
XP_U32 gameToken;
|
||||||
|
XP_ASSERT( sizeof(gameToken) < len );
|
||||||
|
gameToken = ntohl(*(XP_U32*)&buf[0]);
|
||||||
|
buf += sizeof(gameToken);
|
||||||
|
len -= sizeof(gameToken);
|
||||||
|
|
||||||
|
gameGotBuf( &globals->cGlobals, XP_TRUE, buf, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
curses_requestMsgs( gpointer data )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
||||||
|
XP_UCHAR devIDBuf[64] = {0};
|
||||||
|
db_fetch( globals->cGlobals.pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) );
|
||||||
|
if ( '\0' != devIDBuf[0] ) {
|
||||||
|
relaycon_requestMsgs( globals->cGlobals.params, devIDBuf );
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "%s: not requesting messages as don't have relay id", __func__ );
|
||||||
|
}
|
||||||
|
return 0; /* don't run again */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursesNoticeRcvd( void* closure )
|
||||||
|
{
|
||||||
|
LOG_FUNC();
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
(void)g_idle_add( curses_requestMsgs, globals );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursesDevIDChanged( void* closure, const XP_UCHAR* devID )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
CommonGlobals* cGlobals = &globals->cGlobals;
|
||||||
|
sqlite3* pDb = cGlobals->pDb;
|
||||||
|
if ( !!devID ) {
|
||||||
|
XP_LOGF( "%s(devID=%s)", __func__, devID );
|
||||||
|
db_store( pDb, KEY_RDEVID, devID );
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "%s: bad relayid", __func__ );
|
||||||
|
db_remove( pDb, KEY_RDEVID );
|
||||||
|
|
||||||
|
DevIDType typ;
|
||||||
|
const XP_UCHAR* devID = linux_getDevID( cGlobals->params, &typ );
|
||||||
|
relaycon_reg( cGlobals->params, devID, typ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursesErrorMsgRcvd( void* closure, const XP_UCHAR* msg )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
if ( !!globals->lastErr && 0 == strcmp( globals->lastErr, msg ) ) {
|
||||||
|
XP_LOGF( "skipping error message from relay" );
|
||||||
|
} else {
|
||||||
|
g_free( globals->lastErr );
|
||||||
|
globals->lastErr = g_strdup( msg );
|
||||||
|
(void)cursesask( globals, msg, 1, "Ok" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
curses_app_socket_proc( GIOChannel* source, GIOCondition condition,
|
||||||
|
gpointer data )
|
||||||
|
{
|
||||||
|
if ( 0 != (G_IO_IN & condition) ) {
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
||||||
|
int socket = g_io_channel_unix_get_fd( source );
|
||||||
|
GList* iter;
|
||||||
|
for ( iter = globals->sources; !!iter; iter = iter->next ) {
|
||||||
|
SourceData* sd = (SourceData*)iter->data;
|
||||||
|
if ( sd->channel == source ) {
|
||||||
|
(*sd->proc)( sd->procClosure, socket );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XP_ASSERT( !!iter ); /* didn't fail to find it */
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursesUDPSocketChanged( void* closure, int newSock, int XP_UNUSED(oldSock),
|
||||||
|
SockReceiver proc, void* procClosure )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
||||||
|
|
||||||
|
SourceData* sd = g_malloc( sizeof(*sd) );
|
||||||
|
sd->channel = g_io_channel_unix_new( newSock );
|
||||||
|
sd->watch = g_io_add_watch( sd->channel, G_IO_IN | G_IO_ERR,
|
||||||
|
curses_app_socket_proc, globals );
|
||||||
|
sd->proc = proc;
|
||||||
|
sd->procClosure = procClosure;
|
||||||
|
globals->sources = g_list_append( globals->sources, sd );
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
chatsTimerFired( gpointer data )
|
chatsTimerFired( gpointer data )
|
||||||
{
|
{
|
||||||
|
@ -1748,6 +1883,7 @@ void
|
||||||
cursesmain( XP_Bool isServer, LaunchParams* params )
|
cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
|
CommonGlobals* cGlobals = &g_globals.cGlobals;
|
||||||
|
|
||||||
memset( &g_globals, 0, sizeof(g_globals) );
|
memset( &g_globals, 0, sizeof(g_globals) );
|
||||||
|
|
||||||
|
@ -1763,6 +1899,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
|
|
||||||
g_globals.cGlobals.socketChanged = curses_socket_changed;
|
g_globals.cGlobals.socketChanged = curses_socket_changed;
|
||||||
g_globals.cGlobals.socketChangedClosure = &g_globals;
|
g_globals.cGlobals.socketChangedClosure = &g_globals;
|
||||||
|
g_globals.cGlobals.onSave = curses_onGameSaved;
|
||||||
|
g_globals.cGlobals.onSaveClosure = &g_globals;
|
||||||
|
|
||||||
g_globals.cGlobals.addAcceptor = curses_socket_acceptor;
|
g_globals.cGlobals.addAcceptor = curses_socket_acceptor;
|
||||||
|
|
||||||
g_globals.cGlobals.cp.showBoardArrow = XP_TRUE;
|
g_globals.cGlobals.cp.showBoardArrow = XP_TRUE;
|
||||||
|
@ -1778,7 +1917,11 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
g_globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
g_globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setupCursesUtilCallbacks( &g_globals, params->util );
|
g_globals.cGlobals.gi = ¶ms->pgi;
|
||||||
|
setupUtil( &g_globals.cGlobals );
|
||||||
|
setupCursesUtilCallbacks( &g_globals, g_globals.cGlobals.util );
|
||||||
|
|
||||||
|
initFromParams( &g_globals.cGlobals, params );
|
||||||
|
|
||||||
#ifdef XWFEATURE_RELAY
|
#ifdef XWFEATURE_RELAY
|
||||||
if ( params->conType == COMMS_CONN_RELAY ) {
|
if ( params->conType == COMMS_CONN_RELAY ) {
|
||||||
|
@ -1792,12 +1935,14 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
cursesListenOnSocket( &g_globals, 0, handle_stdin );
|
cursesListenOnSocket( &g_globals, 0, handle_stdin );
|
||||||
}
|
}
|
||||||
setOneSecondTimer( &g_globals.cGlobals );
|
setOneSecondTimer( &g_globals.cGlobals );
|
||||||
|
|
||||||
# ifdef DEBUG
|
# ifdef DEBUG
|
||||||
int piperesult =
|
int piperesult =
|
||||||
# endif
|
# endif
|
||||||
pipe( g_globals.quitpipe );
|
pipe( g_globals.quitpipe );
|
||||||
XP_ASSERT( piperesult == 0 );
|
XP_ASSERT( piperesult == 0 );
|
||||||
cursesListenOnSocket( &g_globals, g_globals.quitpipe[0], handle_quitwrite );
|
cursesListenOnSocket( &g_globals, g_globals.quitpipe[0], handle_quitwrite );
|
||||||
|
|
||||||
#else
|
#else
|
||||||
cursesListenOnSocket( &g_globals, 0 ); /* stdin */
|
cursesListenOnSocket( &g_globals, 0 ); /* stdin */
|
||||||
|
|
||||||
|
@ -1824,7 +1969,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
.rconnd = relay_connd_curses,
|
.rconnd = relay_connd_curses,
|
||||||
.rerror = relay_error_curses,
|
.rerror = relay_error_curses,
|
||||||
.sendNoConn = relay_sendNoConn_curses,
|
.sendNoConn = relay_sendNoConn_curses,
|
||||||
.flags = COMMS_XPORT_FLAGS_HASNOCONN,
|
# ifdef COMMS_XPORT_FLAGSPROC
|
||||||
|
.getFlags = curses_getFlags,
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1846,7 +1993,40 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
cursesDrawCtxtMake( g_globals.boardWin );
|
cursesDrawCtxtMake( g_globals.boardWin );
|
||||||
|
|
||||||
XWStreamCtxt* stream = NULL;
|
XWStreamCtxt* stream = NULL;
|
||||||
if ( !!params->fileName && file_exists( params->fileName ) ) {
|
if ( !!params->dbName ) {
|
||||||
|
g_globals.cGlobals.pDb = openGamesDB( params->dbName );
|
||||||
|
|
||||||
|
RelayConnProcs procs = {
|
||||||
|
.msgReceived = cursesGotBuf,
|
||||||
|
.msgNoticeReceived = cursesNoticeRcvd,
|
||||||
|
.devIDChanged = cursesDevIDChanged,
|
||||||
|
.msgErrorMsg = cursesErrorMsgRcvd,
|
||||||
|
.socketChanged = cursesUDPSocketChanged,
|
||||||
|
};
|
||||||
|
|
||||||
|
relaycon_init( params, &procs, &g_globals,
|
||||||
|
params->connInfo.relay.relayName,
|
||||||
|
params->connInfo.relay.defaultSendPort );
|
||||||
|
DevIDType typ;
|
||||||
|
const XP_UCHAR* devID = linux_getDevID( params, &typ );
|
||||||
|
relaycon_reg( params, devID, typ );
|
||||||
|
|
||||||
|
GSList* games = listGames( g_globals.cGlobals.pDb );
|
||||||
|
if ( !!games ) {
|
||||||
|
stream = mem_stream_make( MEMPOOL params->vtMgr,
|
||||||
|
&g_globals.cGlobals, CHANNEL_NONE,
|
||||||
|
NULL );
|
||||||
|
sqlite3_int64 selRow = *(sqlite3_int64*)games->data;
|
||||||
|
if ( loadGame( stream, g_globals.cGlobals.pDb, selRow ) ) {
|
||||||
|
g_globals.cGlobals.selRow = selRow;
|
||||||
|
} else {
|
||||||
|
stream_destroy( stream );
|
||||||
|
stream = NULL;
|
||||||
|
}
|
||||||
|
g_slist_free( games );
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ( !!params->fileName && file_exists( params->fileName ) ) {
|
||||||
stream = streamFromFile( &g_globals.cGlobals, params->fileName,
|
stream = streamFromFile( &g_globals.cGlobals, params->fileName,
|
||||||
&g_globals );
|
&g_globals );
|
||||||
#ifdef USE_SQLITE
|
#ifdef USE_SQLITE
|
||||||
|
@ -1855,27 +2035,40 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( NULL == cGlobals->dict ) {
|
||||||
|
if ( !!stream ) {
|
||||||
|
cGlobals->dict = makeDictForStream( cGlobals, stream );
|
||||||
|
} else {
|
||||||
|
cGlobals->dict =
|
||||||
|
linux_dictionary_make( MEMPOOL params,
|
||||||
|
cGlobals->gi->dictName, XP_TRUE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cGlobals->gi->dictLang = dict_getLangCode( cGlobals->dict );
|
||||||
|
|
||||||
if ( !!stream ) {
|
if ( !!stream ) {
|
||||||
(void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game,
|
(void)game_makeFromStream( MEMPOOL stream, &cGlobals->game,
|
||||||
¶ms->gi, params->dict, ¶ms->dicts,
|
cGlobals->gi, cGlobals->dict,
|
||||||
params->util,
|
&cGlobals->dicts, cGlobals->util,
|
||||||
(DrawCtx*)g_globals.draw,
|
(DrawCtx*)g_globals.draw,
|
||||||
&g_globals.cGlobals.cp, &procs );
|
&g_globals.cGlobals.cp, &procs );
|
||||||
|
|
||||||
stream_destroy( stream );
|
stream_destroy( stream );
|
||||||
if ( !isServer && params->gi.serverRole == SERVER_ISSERVER ) {
|
if ( !isServer && cGlobals->gi->serverRole == SERVER_ISSERVER ) {
|
||||||
isServer = XP_TRUE;
|
isServer = XP_TRUE;
|
||||||
}
|
}
|
||||||
opened = XP_TRUE;
|
opened = XP_TRUE;
|
||||||
}
|
}
|
||||||
if ( !opened ) {
|
if ( !opened ) {
|
||||||
game_makeNewGame( MEMPOOL &g_globals.cGlobals.game, ¶ms->gi,
|
game_makeNewGame( MEMPOOL &cGlobals->game, cGlobals->gi,
|
||||||
params->util, (DrawCtx*)g_globals.draw,
|
cGlobals->util, (DrawCtx*)g_globals.draw,
|
||||||
&g_globals.cGlobals.cp, &procs, params->gameSeed );
|
&g_globals.cGlobals.cp, &procs, params->gameSeed );
|
||||||
|
g_globals.cGlobals.selRow = -1;
|
||||||
|
saveGame( &g_globals.cGlobals );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
if ( g_globals.cGlobals.game.comms ) {
|
if ( cGlobals->game.comms ) {
|
||||||
CommsAddrRec addr = {0};
|
CommsAddrRec addr = {0};
|
||||||
|
|
||||||
if ( 0 ) {
|
if ( 0 ) {
|
||||||
|
@ -1907,22 +2100,22 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
sizeof(params->connInfo.bt.hostAddr) );
|
sizeof(params->connInfo.bt.hostAddr) );
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
comms_setAddr( g_globals.cGlobals.game.comms, &addr );
|
comms_setAddr( cGlobals->game.comms, &addr );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
model_setDictionary( g_globals.cGlobals.game.model, params->dict );
|
model_setDictionary( cGlobals->game.model, cGlobals->dict );
|
||||||
setSquareBonuses( &g_globals.cGlobals );
|
setSquareBonuses( cGlobals );
|
||||||
positionSizeStuff( &g_globals, width, height );
|
positionSizeStuff( &g_globals, width, height );
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
/* send any events that need to get off before the event loop begins */
|
/* send any events that need to get off before the event loop begins */
|
||||||
if ( !isServer ) {
|
if ( !isServer ) {
|
||||||
if ( 1 /* stream_open( params->info.clientInfo.stream ) */) {
|
if ( 1 /* stream_open( params->info.clientInfo.stream ) */) {
|
||||||
server_initClientConnection( g_globals.cGlobals.game.server,
|
server_initClientConnection( cGlobals->game.server,
|
||||||
mem_stream_make( MEMPOOL
|
mem_stream_make( MEMPOOL
|
||||||
params->vtMgr,
|
params->vtMgr,
|
||||||
&g_globals.cGlobals,
|
cGlobals,
|
||||||
(XP_PlayerAddr)0,
|
(XP_PlayerAddr)0,
|
||||||
sendOnClose ) );
|
sendOnClose ) );
|
||||||
} else {
|
} else {
|
||||||
|
@ -1961,10 +2154,13 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if ( !!g_globals.cGlobals.game.comms ) {
|
||||||
|
comms_stop( g_globals.cGlobals.game.comms );
|
||||||
|
}
|
||||||
saveGame( &g_globals.cGlobals );
|
saveGame( &g_globals.cGlobals );
|
||||||
|
|
||||||
game_dispose( &g_globals.cGlobals.game ); /* takes care of the dict */
|
game_dispose( &g_globals.cGlobals.game ); /* takes care of the dict */
|
||||||
gi_disposePlayerInfo( MEMPOOL &g_globals.cGlobals.params->gi );
|
gi_disposePlayerInfo( MEMPOOL cGlobals->gi );
|
||||||
|
|
||||||
#ifdef XWFEATURE_BLUETOOTH
|
#ifdef XWFEATURE_BLUETOOTH
|
||||||
linux_bt_close( &g_globals.cGlobals );
|
linux_bt_close( &g_globals.cGlobals );
|
||||||
|
@ -1977,5 +2173,12 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
endwin();
|
endwin();
|
||||||
|
|
||||||
|
if ( !!params->dbName ) {
|
||||||
|
closeGamesDB( g_globals.cGlobals.pDb );
|
||||||
|
}
|
||||||
|
relaycon_cleanup( params );
|
||||||
|
|
||||||
|
linux_util_vt_destroy( g_globals.cGlobals.util );
|
||||||
} /* cursesmain */
|
} /* cursesmain */
|
||||||
#endif /* PLATFORM_NCURSES */
|
#endif /* PLATFORM_NCURSES */
|
||||||
|
|
|
@ -68,6 +68,7 @@ struct CursesAppGlobals {
|
||||||
XP_Bool doDraw;
|
XP_Bool doDraw;
|
||||||
const struct MenuList* menuList;
|
const struct MenuList* menuList;
|
||||||
XP_U16 nLinesMenu;
|
XP_U16 nLinesMenu;
|
||||||
|
gchar* lastErr;
|
||||||
|
|
||||||
XP_U16 nChatsSent;
|
XP_U16 nChatsSent;
|
||||||
|
|
||||||
|
@ -98,13 +99,6 @@ struct CursesAppGlobals {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_GLIBLOOP
|
|
||||||
typedef struct _SourceData {
|
|
||||||
GIOChannel* channel;
|
|
||||||
gint watch;
|
|
||||||
} SourceData;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DrawCtx* cursesDrawCtxtMake( WINDOW* boardWin );
|
DrawCtx* cursesDrawCtxtMake( WINDOW* boardWin );
|
||||||
|
|
||||||
/* Ports: Client and server pick a port at startup on which they'll listen.
|
/* Ports: Client and server pick a port at startup on which they'll listen.
|
||||||
|
|
292
xwords4/linux/gamesdb.c
Normal file
292
xwords4/linux/gamesdb.c
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2000-2013 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gamesdb.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
static void getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf,
|
||||||
|
int len );
|
||||||
|
|
||||||
|
|
||||||
|
sqlite3*
|
||||||
|
openGamesDB( const char* dbName )
|
||||||
|
{
|
||||||
|
sqlite3* pDb = NULL;
|
||||||
|
int result = sqlite3_open( dbName, &pDb );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
|
||||||
|
const char* createGamesStr =
|
||||||
|
"CREATE TABLE games ( "
|
||||||
|
"rowid INTEGER PRIMARY KEY AUTOINCREMENT"
|
||||||
|
",game BLOB"
|
||||||
|
",room VARCHAR(32)"
|
||||||
|
",ended INT(1)"
|
||||||
|
",turn INT(2)"
|
||||||
|
",nmoves INT"
|
||||||
|
",nmissing INT(2)"
|
||||||
|
")";
|
||||||
|
result = sqlite3_exec( pDb, createGamesStr, NULL, NULL, NULL );
|
||||||
|
|
||||||
|
const char* createValuesStr =
|
||||||
|
"CREATE TABLE pairs ( key TEXT UNIQUE,value TEXT )";
|
||||||
|
result = sqlite3_exec( pDb, createValuesStr, NULL, NULL, NULL );
|
||||||
|
XP_LOGF( "sqlite3_exec=>%d", result );
|
||||||
|
|
||||||
|
return pDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closeGamesDB( sqlite3* pDb )
|
||||||
|
{
|
||||||
|
sqlite3_close( pDb );
|
||||||
|
XP_LOGF( "%s finished", __func__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeToDB( XWStreamCtxt* stream, void* closure )
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
CommonGlobals* cGlobals = (CommonGlobals*)closure;
|
||||||
|
sqlite3_int64 selRow = cGlobals->selRow;
|
||||||
|
sqlite3* pDb = cGlobals->pDb;
|
||||||
|
XP_U16 len = stream_getSize( stream );
|
||||||
|
char buf[256];
|
||||||
|
char* query;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
XP_Bool newGame = -1 == selRow;
|
||||||
|
if ( newGame ) { /* new row; need to insert blob first */
|
||||||
|
query = "INSERT INTO games (game) VALUES (?)";
|
||||||
|
} else {
|
||||||
|
const char* fmt = "UPDATE games SET game=? where rowid=%lld";
|
||||||
|
snprintf( buf, sizeof(buf), fmt, selRow );
|
||||||
|
query = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_prepare_v2( pDb, query, -1, &stmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_bind_zeroblob( stmt, 1 /*col 0 ??*/, len );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( stmt );
|
||||||
|
XP_ASSERT( SQLITE_DONE == result );
|
||||||
|
|
||||||
|
if ( newGame ) { /* new row; need to insert blob first */
|
||||||
|
selRow = sqlite3_last_insert_rowid( pDb );
|
||||||
|
XP_LOGF( "%s: new rowid: %lld", __func__, selRow );
|
||||||
|
cGlobals->selRow = selRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_blob* blob;
|
||||||
|
result = sqlite3_blob_open( pDb, "main", "games", "game",
|
||||||
|
selRow, 1 /*flags: writeable*/, &blob );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
const XP_U8* ptr = stream_getPtr( stream );
|
||||||
|
result = sqlite3_blob_write( blob, ptr, len, 0 );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_blob_close( blob );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
if ( !!stmt ) {
|
||||||
|
sqlite3_finalize( stmt );
|
||||||
|
}
|
||||||
|
|
||||||
|
(*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
summarize( CommonGlobals* cGlobals )
|
||||||
|
{
|
||||||
|
XP_S16 nMoves = model_getNMoves( cGlobals->game.model );
|
||||||
|
XP_Bool gameOver = server_getGameIsOver( cGlobals->game.server );
|
||||||
|
XP_S16 turn = server_getCurrentTurn( cGlobals->game.server );
|
||||||
|
XP_S16 nMissing = 0;
|
||||||
|
CommsAddrRec addr = {0};
|
||||||
|
gchar* room = "";
|
||||||
|
|
||||||
|
if ( !!cGlobals->game.comms ) {
|
||||||
|
nMissing = server_getMissingPlayers( cGlobals->game.server );
|
||||||
|
comms_getAddr( cGlobals->game.comms, &addr );
|
||||||
|
if ( COMMS_CONN_RELAY == addr.conType ) {
|
||||||
|
room = addr.u.ip_relay.invite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* fmt = "UPDATE games SET room='%s', ended=%d, turn=%d, nmissing=%d, nmoves=%d"
|
||||||
|
" where rowid=%lld";
|
||||||
|
XP_UCHAR buf[256];
|
||||||
|
snprintf( buf, sizeof(buf), fmt, room, gameOver?1:0, turn, nMissing, nMoves,
|
||||||
|
cGlobals->selRow );
|
||||||
|
XP_LOGF( "query: %s", buf );
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
int result = sqlite3_prepare_v2( cGlobals->pDb, buf, -1, &stmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( stmt );
|
||||||
|
XP_ASSERT( SQLITE_DONE == result );
|
||||||
|
sqlite3_finalize( stmt );
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList*
|
||||||
|
listGames( sqlite3* pDb )
|
||||||
|
{
|
||||||
|
GSList* list = NULL;
|
||||||
|
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb,
|
||||||
|
"SELECT rowid FROM games ORDER BY rowid",
|
||||||
|
-1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
while ( NULL != ppStmt ) {
|
||||||
|
switch( sqlite3_step( ppStmt ) ) {
|
||||||
|
case SQLITE_ROW: /* have data */
|
||||||
|
{
|
||||||
|
sqlite3_int64* data = g_malloc( sizeof( *data ) );
|
||||||
|
*data = sqlite3_column_int64( ppStmt, 0 );
|
||||||
|
XP_LOGF( "%s: got a row; id=%lld", __func__, *data );
|
||||||
|
list = g_slist_append( list, data );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SQLITE_DONE:
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
ppStmt = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
|
||||||
|
{
|
||||||
|
XP_Bool success = XP_FALSE;
|
||||||
|
const char* fmt = "SELECT room, ended, turn, nmoves, nmissing "
|
||||||
|
"FROM games WHERE rowid = %lld";
|
||||||
|
XP_UCHAR query[256];
|
||||||
|
snprintf( query, sizeof(query), fmt, rowid );
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
if ( SQLITE_ROW == result ) {
|
||||||
|
success = XP_TRUE;
|
||||||
|
getColumnText( ppStmt, 0, gib->room, sizeof(gib->room) );
|
||||||
|
gib->gameOver = 1 == sqlite3_column_int( ppStmt, 1 );
|
||||||
|
gib->turn = sqlite3_column_int( ppStmt, 2 );
|
||||||
|
gib->nMoves = sqlite3_column_int( ppStmt, 3 );
|
||||||
|
gib->nMissing = sqlite3_column_int( ppStmt, 4 );
|
||||||
|
snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid );
|
||||||
|
}
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
snprintf( buf, sizeof(buf), "SELECT game from games WHERE rowid = %lld", rowid );
|
||||||
|
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
XP_Bool success = SQLITE_ROW == result;
|
||||||
|
if ( success ) {
|
||||||
|
const void* ptr = sqlite3_column_blob( ppStmt, 0 );
|
||||||
|
int size = sqlite3_column_bytes( ppStmt, 0 );
|
||||||
|
stream_putBytes( stream, ptr, size );
|
||||||
|
}
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deleteGame( sqlite3* pDb, sqlite3_int64 rowid )
|
||||||
|
{
|
||||||
|
char query[256];
|
||||||
|
snprintf( query, sizeof(query), "DELETE FROM games WHERE rowid = %lld", rowid );
|
||||||
|
sqlite3_stmt* ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
XP_ASSERT( SQLITE_DONE == result );
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
db_store( sqlite3* pDb, const gchar* key, const gchar* value )
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
snprintf( buf, sizeof(buf),
|
||||||
|
"INSERT OR REPLACE INTO pairs (key, value) VALUES ('%s', '%s')",
|
||||||
|
key, value );
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
XP_ASSERT( SQLITE_DONE == result );
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
db_fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint buflen )
|
||||||
|
{
|
||||||
|
XP_Bool found;
|
||||||
|
char query[256];
|
||||||
|
snprintf( query, sizeof(query),
|
||||||
|
"SELECT value from pairs where key = '%s'", key );
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
found = SQLITE_ROW == result;
|
||||||
|
if ( found ) {
|
||||||
|
getColumnText( ppStmt, 0, buf, buflen );
|
||||||
|
} else {
|
||||||
|
buf[0] = '\0';
|
||||||
|
}
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
db_remove( sqlite3* pDb, const gchar* key )
|
||||||
|
{
|
||||||
|
char query[256];
|
||||||
|
snprintf( query, sizeof(query), "DELETE FROM pairs WHERE key = '%s'", key );
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
|
||||||
|
XP_ASSERT( SQLITE_OK == result );
|
||||||
|
result = sqlite3_step( ppStmt );
|
||||||
|
XP_ASSERT( SQLITE_DONE == result );
|
||||||
|
sqlite3_finalize( ppStmt );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf, int len )
|
||||||
|
{
|
||||||
|
const unsigned char* txt = sqlite3_column_text( ppStmt, iCol );
|
||||||
|
int needLen = sqlite3_column_bytes( ppStmt, iCol );
|
||||||
|
XP_ASSERT( needLen < len );
|
||||||
|
XP_MEMCPY( buf, txt, needLen );
|
||||||
|
buf[needLen] = '\0';
|
||||||
|
}
|
58
xwords4/linux/gamesdb.h
Normal file
58
xwords4/linux/gamesdb.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2000-2012 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GAMESDB_H_
|
||||||
|
#define _GAMESDB_H_
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "comtypes.h"
|
||||||
|
|
||||||
|
typedef struct _GameInfo {
|
||||||
|
XP_UCHAR name[128];
|
||||||
|
XP_UCHAR room[128];
|
||||||
|
XP_S16 nMoves;
|
||||||
|
XP_Bool gameOver;
|
||||||
|
XP_S16 turn;
|
||||||
|
XP_S16 nMissing;
|
||||||
|
} GameInfo;
|
||||||
|
|
||||||
|
|
||||||
|
sqlite3* openGamesDB( const char* dbName );
|
||||||
|
void closeGamesDB( sqlite3* dbp );
|
||||||
|
|
||||||
|
void writeToDB( XWStreamCtxt* stream, void* closure );
|
||||||
|
void summarize( CommonGlobals* cGlobals );
|
||||||
|
|
||||||
|
/* Return GSList whose data is (ptrs to) rowids */
|
||||||
|
GSList* listGames( sqlite3* dbp );
|
||||||
|
XP_Bool getGameInfo( sqlite3* dbp, sqlite3_int64 rowid, GameInfo* gib );
|
||||||
|
XP_Bool loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid );
|
||||||
|
void deleteGame( sqlite3* pDb, sqlite3_int64 rowid );
|
||||||
|
|
||||||
|
#define KEY_RDEVID "RDEVID"
|
||||||
|
|
||||||
|
void db_store( sqlite3* dbp, const gchar* key, const gchar* value );
|
||||||
|
XP_Bool db_fetch( sqlite3* dbp, const gchar* key, gchar* buf, gint buflen );
|
||||||
|
void db_remove( sqlite3* dbp, const gchar* key );
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _GTKASK_H_
|
#ifndef _GTKASK_H_
|
||||||
#define _GTKASK_H_
|
#define _GTKASK_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
/* Returns true for "yes" or "ok" answer, false otherwise.
|
/* Returns true for "yes" or "ok" answer, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -41,9 +41,9 @@ init_list( GtkWidget* list )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_to_list( GtkWidget *list, const gchar *str )
|
add_to_list( GtkWidget* list, const gchar* str )
|
||||||
{
|
{
|
||||||
GtkListStore *store =
|
GtkListStore* store =
|
||||||
GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
|
GTK_LIST_STORE( gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
gtk_list_store_append( store, &iter );
|
gtk_list_store_append( store, &iter );
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _GTKASKDICT_H_
|
#ifndef _GTKASKDICT_H_
|
||||||
#define _GTKASKDICT_H_
|
#define _GTKASKDICT_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
gchar* gtkaskdict( GSList* dicts, gchar* buf, gint buflen );
|
gchar* gtkaskdict( GSList* dicts, gchar* buf, gint buflen );
|
||||||
|
|
||||||
|
|
2649
xwords4/linux/gtkboard.c
Normal file
2649
xwords4/linux/gtkboard.c
Normal file
File diff suppressed because it is too large
Load diff
180
xwords4/linux/gtkboard.h
Normal file
180
xwords4/linux/gtkboard.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/* -*- mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||||
|
/* Copyright 1997 - 2005 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GTKBOARD_H_
|
||||||
|
#define _GTKBOARD_H_
|
||||||
|
|
||||||
|
#ifdef PLATFORM_GTK
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <pango/pango-font.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "draw.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "dictnry.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LAYOUT_BOARD
|
||||||
|
,LAYOUT_SMALL
|
||||||
|
,LAYOUT_LARGE
|
||||||
|
,LAYOUT_NLAYOUTS
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_SCORE_LEN 31
|
||||||
|
|
||||||
|
typedef struct GtkDrawCtx {
|
||||||
|
DrawCtxVTable* vtable;
|
||||||
|
|
||||||
|
/* GdkDrawable* pixmap; */
|
||||||
|
GtkWidget* drawing_area;
|
||||||
|
struct GtkGameGlobals* globals;
|
||||||
|
|
||||||
|
#ifdef USE_CAIRO
|
||||||
|
cairo_t* cr;
|
||||||
|
#else
|
||||||
|
GdkGC* drawGC;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GdkColor black;
|
||||||
|
GdkColor white;
|
||||||
|
GdkColor grey;
|
||||||
|
GdkColor red; /* for pending tiles */
|
||||||
|
GdkColor tileBack; /* for pending tiles */
|
||||||
|
GdkColor cursor;
|
||||||
|
GdkColor bonusColors[4];
|
||||||
|
GdkColor playerColors[MAX_NUM_PLAYERS];
|
||||||
|
|
||||||
|
/* new for gtk 2.0 */
|
||||||
|
PangoContext* pangoContext;
|
||||||
|
GList* fontsPerSize;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
XP_UCHAR str[MAX_SCORE_LEN+1];
|
||||||
|
XP_U16 fontHt;
|
||||||
|
} scoreCache[MAX_NUM_PLAYERS];
|
||||||
|
|
||||||
|
XP_U16 trayOwner;
|
||||||
|
XP_U16 cellWidth;
|
||||||
|
XP_U16 cellHeight;
|
||||||
|
|
||||||
|
XP_Bool scoreIsVertical;
|
||||||
|
} GtkDrawCtx;
|
||||||
|
|
||||||
|
typedef struct ClientStreamRec {
|
||||||
|
XWStreamCtxt* stream;
|
||||||
|
guint key;
|
||||||
|
int sock;
|
||||||
|
} ClientStreamRec;
|
||||||
|
|
||||||
|
typedef struct GtkGameGlobals {
|
||||||
|
CommonGlobals cGlobals;
|
||||||
|
CurGameInfo gi;
|
||||||
|
GtkWidget* window;
|
||||||
|
GtkDrawCtx* draw;
|
||||||
|
GtkAppGlobals* apg;
|
||||||
|
/* GdkPixmap* pixmap; */
|
||||||
|
GtkWidget* drawing_area;
|
||||||
|
|
||||||
|
GtkWidget* flip_button;
|
||||||
|
GtkWidget* zoomin_button;
|
||||||
|
GtkWidget* zoomout_button;
|
||||||
|
GtkWidget* toggle_undo_button;
|
||||||
|
GtkWidget* prevhint_button;
|
||||||
|
GtkWidget* nexthint_button;
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_CHAT
|
||||||
|
GtkWidget* chat_button;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EngineCtxt* engine;
|
||||||
|
|
||||||
|
guint idleID;
|
||||||
|
|
||||||
|
struct timeval scoreTv; /* for timer */
|
||||||
|
XP_U32 scoreTimerInterval;
|
||||||
|
|
||||||
|
GtkAdjustment* adjustment;
|
||||||
|
|
||||||
|
ClientStreamRec clientRecs[MAX_NUM_PLAYERS];
|
||||||
|
|
||||||
|
guint timerSources[NUM_TIMERS_PLUS_ONE - 1];
|
||||||
|
|
||||||
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
|
XP_U16 netStatLeft, netStatTop;
|
||||||
|
XP_UCHAR stateChar;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
XP_Bool gridOn;
|
||||||
|
XP_Bool dropIncommingMsgs;
|
||||||
|
XP_Bool mouseDown;
|
||||||
|
XP_Bool altKeyDown;
|
||||||
|
#ifdef KEYBOARD_NAV
|
||||||
|
XP_Bool keyDown;
|
||||||
|
#endif
|
||||||
|
} GtkGameGlobals;
|
||||||
|
|
||||||
|
/* DictionaryCtxt* gtk_dictionary_make(); */
|
||||||
|
#define GTK_MIN_SCALE 12 /* was 14 */
|
||||||
|
|
||||||
|
#define GTK_MIN_TRAY_SCALEH 24
|
||||||
|
#define GTK_MIN_TRAY_SCALEV GTK_MIN_TRAY_SCALEH
|
||||||
|
#define GTK_TRAYPAD_WIDTH 2
|
||||||
|
|
||||||
|
#define GTK_TOP_MARGIN 0 /* was 2 */
|
||||||
|
#define GTK_BOARD_LEFT_MARGIN 2
|
||||||
|
#define GTK_TRAY_LEFT_MARGIN 2
|
||||||
|
#define GTK_SCORE_BOARD_PADDING 0
|
||||||
|
|
||||||
|
#define GTK_HOR_SCORE_LEFT (GTK_BOARD_LEFT_MARGIN)
|
||||||
|
#define GTK_HOR_SCORE_HEIGHT 12
|
||||||
|
#define GTK_TIMER_HEIGHT GTK_HOR_SCORE_HEIGHT
|
||||||
|
#define GTK_HOR_SCORE_TOP (GTK_TOP_MARGIN)
|
||||||
|
#define GTK_TIMER_PAD 10
|
||||||
|
#define GTK_VERT_SCORE_TOP (GTK_TIMER_HEIGHT + GTK_TIMER_PAD)
|
||||||
|
#define GTK_VERT_SCORE_HEIGHT ((MIN_SCALE*MAX_COLS) - GTK_TIMER_HEIGHT - \
|
||||||
|
GTK_TIMER_PAD)
|
||||||
|
#define GTK_TIMER_WIDTH 40
|
||||||
|
#define GTK_NETSTAT_WIDTH 20
|
||||||
|
#define GTK_TIMER_TOP GTK_HOR_SCORE_TOP
|
||||||
|
#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*20)-GTK_TIMER_PAD)
|
||||||
|
#define GTK_VERT_SCORE_WIDTH 40
|
||||||
|
|
||||||
|
#define GTK_BOARD_TOP (GTK_SCORE_TOP + GTK_SCORE_HEIGHT \
|
||||||
|
+ GTK_SCORE_BOARD_PADDING )
|
||||||
|
#define GTK_BOARD_LEFT (GTK_BOARD_LEFT_MARGIN)
|
||||||
|
|
||||||
|
#define GTK_TRAY_LEFT GTK_TRAY_LEFT_MARGIN
|
||||||
|
|
||||||
|
#define GTK_DIVIDER_WIDTH 5
|
||||||
|
|
||||||
|
#define GTK_BOTTOM_MARGIN GTK_TOP_MARGIN
|
||||||
|
#define GTK_RIGHT_MARGIN GTK_BOARD_LEFT_MARGIN
|
||||||
|
|
||||||
|
void initGlobals( GtkGameGlobals* globals, LaunchParams* params );
|
||||||
|
void freeGlobals( GtkGameGlobals* globals );
|
||||||
|
XP_Bool makeNewGame( GtkGameGlobals* globals );
|
||||||
|
XP_Bool loadGameNoDraw( GtkGameGlobals* globals, LaunchParams* params,
|
||||||
|
sqlite3_int64 rowid );
|
||||||
|
void destroy_board_window( GtkWidget* widget, GtkGameGlobals* globals );
|
||||||
|
|
||||||
|
#endif /* PLATFORM_GTK */
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,7 +22,7 @@
|
||||||
#include "gtkchat.h"
|
#include "gtkchat.h"
|
||||||
|
|
||||||
gchar*
|
gchar*
|
||||||
gtkGetChatMessage( GtkAppGlobals* XP_UNUSED(globals) )
|
gtkGetChatMessage( GtkGameGlobals* XP_UNUSED(globals) )
|
||||||
{
|
{
|
||||||
gchar* result = NULL;
|
gchar* result = NULL;
|
||||||
GtkWidget* dialog = gtk_dialog_new_with_buttons( "message text", NULL, //GtkWindow *parent,
|
GtkWidget* dialog = gtk_dialog_new_with_buttons( "message text", NULL, //GtkWindow *parent,
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
#ifdef PLATFORM_GTK
|
#ifdef PLATFORM_GTK
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
gchar* gtkGetChatMessage( GtkAppGlobals* globals );
|
gchar* gtkGetChatMessage( GtkGameGlobals* globals );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif /* #ifndef _GTKCHAT_H_ */
|
#endif /* #ifndef _GTKCHAT_H_ */
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "gtkutils.h"
|
#include "gtkutils.h"
|
||||||
|
|
||||||
typedef struct _GtkConnsState {
|
typedef struct _GtkConnsState {
|
||||||
GtkAppGlobals* globals;
|
GtkGameGlobals* globals;
|
||||||
CommsAddrRec* addr;
|
CommsAddrRec* addr;
|
||||||
DeviceRole role;
|
DeviceRole role;
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ makeBTPage( GtkConnsState* state )
|
||||||
} /* makeBTPage */
|
} /* makeBTPage */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gtkConnsDlg( GtkAppGlobals* globals, CommsAddrRec* addr, DeviceRole role,
|
gtkConnsDlg( GtkGameGlobals* globals, CommsAddrRec* addr, DeviceRole role,
|
||||||
XP_Bool readOnly )
|
XP_Bool readOnly )
|
||||||
{
|
{
|
||||||
GtkConnsState state;
|
GtkConnsState state;
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
#ifndef _GTKCONNSDLG_H_
|
#ifndef _GTKCONNSDLG_H_
|
||||||
#define _GTKCONNSDLG_H_
|
#define _GTKCONNSDLG_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
gboolean gtkConnsDlg( GtkAppGlobals* globals, CommsAddrRec* addr,
|
gboolean gtkConnsDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
|
||||||
DeviceRole role, XP_Bool readOnly );
|
DeviceRole role, XP_Bool readOnly );
|
||||||
|
|
||||||
#endif /* _GTKCONNSDLG_H_ */
|
#endif /* _GTKCONNSDLG_H_ */
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include <gdk/gdkdrawable.h>
|
#include <gdk/gdkdrawable.h>
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "linuxmain.h"
|
#include "linuxmain.h"
|
||||||
|
@ -515,7 +515,8 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
|
||||||
{
|
{
|
||||||
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
|
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
|
||||||
XP_Rect rectInset = *rect;
|
XP_Rect rectInset = *rect;
|
||||||
XP_Bool showGrid = dctx->globals->gridOn;
|
GtkGameGlobals* globals = dctx->globals;
|
||||||
|
XP_Bool showGrid = globals->gridOn;
|
||||||
XP_Bool highlight = (flags & CELL_HIGHLIGHT) != 0;
|
XP_Bool highlight = (flags & CELL_HIGHLIGHT) != 0;
|
||||||
GdkColor* cursor =
|
GdkColor* cursor =
|
||||||
((flags & CELL_ISCURSOR) != 0) ? &dctx->cursor : NULL;
|
((flags & CELL_ISCURSOR) != 0) ? &dctx->cursor : NULL;
|
||||||
|
@ -1305,7 +1306,7 @@ allocAndSet( GdkColormap* map, GdkColor* color, unsigned short red,
|
||||||
} /* allocAndSet */
|
} /* allocAndSet */
|
||||||
|
|
||||||
DrawCtx*
|
DrawCtx*
|
||||||
gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
|
gtkDrawCtxtMake( GtkWidget* drawing_area, GtkGameGlobals* globals )
|
||||||
{
|
{
|
||||||
GtkDrawCtx* dctx = g_malloc0( sizeof(GtkDrawCtx) );
|
GtkDrawCtx* dctx = g_malloc0( sizeof(GtkDrawCtx) );
|
||||||
GdkColormap* map;
|
GdkColormap* map;
|
||||||
|
@ -1423,7 +1424,7 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
|
||||||
void
|
void
|
||||||
draw_gtk_status( GtkDrawCtx* dctx, char ch )
|
draw_gtk_status( GtkDrawCtx* dctx, char ch )
|
||||||
{
|
{
|
||||||
GtkAppGlobals* globals = dctx->globals;
|
GtkGameGlobals* globals = dctx->globals;
|
||||||
|
|
||||||
XP_Rect rect = {
|
XP_Rect rect = {
|
||||||
.left = globals->netStatLeft,
|
.left = globals->netStatLeft,
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
DrawCtx* gtkDrawCtxtMake( GtkWidget *widget, GtkAppGlobals* globals );
|
DrawCtx* gtkDrawCtxtMake( GtkWidget *widget, GtkGameGlobals* globals );
|
||||||
|
|
||||||
void draw_gtk_status( GtkDrawCtx* draw, char ch );
|
void draw_gtk_status( GtkDrawCtx* draw, char ch );
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef _GTKLETTERASK_H_
|
#ifndef _GTKLETTERASK_H_
|
||||||
#define _GTKLETTERASK_H_
|
#define _GTKLETTERASK_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
XP_S16 gtkletterask( const PickInfo* pi, XP_Bool forTray,
|
XP_S16 gtkletterask( const PickInfo* pi, XP_Bool forTray,
|
||||||
const XP_UCHAR* name,
|
const XP_UCHAR* name,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
/* -*- mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/* Copyright 1997 - 2005 by Eric House (xwords@eehouse.org) All rights
|
/* Copyright 1997 - 2013 by Eric House (xwords@eehouse.org) All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -20,155 +20,11 @@
|
||||||
#ifndef _GTKMAIN_H_
|
#ifndef _GTKMAIN_H_
|
||||||
#define _GTKMAIN_H_
|
#define _GTKMAIN_H_
|
||||||
|
|
||||||
#ifdef PLATFORM_GTK
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <pango/pango-font.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "draw.h"
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "game.h"
|
#include "gtkboard.h"
|
||||||
#include "dictnry.h"
|
|
||||||
|
|
||||||
enum {
|
int gtkmain( LaunchParams* params );
|
||||||
LAYOUT_BOARD
|
void windowDestroyed( GtkGameGlobals* globals );
|
||||||
,LAYOUT_SMALL
|
void onGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime );
|
||||||
,LAYOUT_LARGE
|
|
||||||
,LAYOUT_NLAYOUTS
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_SCORE_LEN 31
|
|
||||||
|
|
||||||
typedef struct GtkDrawCtx {
|
|
||||||
DrawCtxVTable* vtable;
|
|
||||||
|
|
||||||
/* GdkDrawable* pixmap; */
|
|
||||||
GtkWidget* drawing_area;
|
|
||||||
struct GtkAppGlobals* globals;
|
|
||||||
|
|
||||||
#ifdef USE_CAIRO
|
|
||||||
cairo_t* cr;
|
|
||||||
#else
|
|
||||||
GdkGC* drawGC;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GdkColor black;
|
|
||||||
GdkColor white;
|
|
||||||
GdkColor grey;
|
|
||||||
GdkColor red; /* for pending tiles */
|
|
||||||
GdkColor tileBack; /* for pending tiles */
|
|
||||||
GdkColor cursor;
|
|
||||||
GdkColor bonusColors[4];
|
|
||||||
GdkColor playerColors[MAX_NUM_PLAYERS];
|
|
||||||
|
|
||||||
/* new for gtk 2.0 */
|
|
||||||
PangoContext* pangoContext;
|
|
||||||
GList* fontsPerSize;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
XP_UCHAR str[MAX_SCORE_LEN+1];
|
|
||||||
XP_U16 fontHt;
|
|
||||||
} scoreCache[MAX_NUM_PLAYERS];
|
|
||||||
|
|
||||||
XP_U16 trayOwner;
|
|
||||||
XP_U16 cellWidth;
|
|
||||||
XP_U16 cellHeight;
|
|
||||||
|
|
||||||
XP_Bool scoreIsVertical;
|
|
||||||
} GtkDrawCtx;
|
|
||||||
|
|
||||||
typedef struct ClientStreamRec {
|
|
||||||
XWStreamCtxt* stream;
|
|
||||||
guint key;
|
|
||||||
int sock;
|
|
||||||
} ClientStreamRec;
|
|
||||||
|
|
||||||
typedef struct GtkAppGlobals {
|
|
||||||
CommonGlobals cGlobals;
|
|
||||||
GtkWidget* window;
|
|
||||||
GtkDrawCtx* draw;
|
|
||||||
|
|
||||||
/* GdkPixmap* pixmap; */
|
|
||||||
GtkWidget* drawing_area;
|
|
||||||
|
|
||||||
GtkWidget* flip_button;
|
|
||||||
GtkWidget* zoomin_button;
|
|
||||||
GtkWidget* zoomout_button;
|
|
||||||
GtkWidget* toggle_undo_button;
|
|
||||||
GtkWidget* prevhint_button;
|
|
||||||
GtkWidget* nexthint_button;
|
|
||||||
|
|
||||||
#ifdef XWFEATURE_CHAT
|
|
||||||
GtkWidget* chat_button;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EngineCtxt* engine;
|
|
||||||
|
|
||||||
guint idleID;
|
|
||||||
|
|
||||||
struct timeval scoreTv; /* for timer */
|
|
||||||
XP_U32 scoreTimerInterval;
|
|
||||||
|
|
||||||
GtkAdjustment* adjustment;
|
|
||||||
|
|
||||||
ClientStreamRec clientRecs[MAX_NUM_PLAYERS];
|
|
||||||
|
|
||||||
guint timerSources[NUM_TIMERS_PLUS_ONE - 1];
|
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
||||||
XP_U16 netStatLeft, netStatTop;
|
|
||||||
XP_UCHAR stateChar;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
XP_Bool gridOn;
|
|
||||||
XP_Bool dropIncommingMsgs;
|
|
||||||
XP_Bool mouseDown;
|
|
||||||
XP_Bool altKeyDown;
|
|
||||||
#ifdef KEYBOARD_NAV
|
|
||||||
XP_Bool keyDown;
|
|
||||||
#endif
|
|
||||||
} GtkAppGlobals;
|
|
||||||
|
|
||||||
/* DictionaryCtxt* gtk_dictionary_make(); */
|
|
||||||
int gtkmain( LaunchParams* params, int argc, char *argv[] );
|
|
||||||
|
|
||||||
#define GTK_MIN_SCALE 12 /* was 14 */
|
|
||||||
|
|
||||||
#define GTK_MIN_TRAY_SCALEH 24
|
|
||||||
#define GTK_MIN_TRAY_SCALEV GTK_MIN_TRAY_SCALEH
|
|
||||||
#define GTK_TRAYPAD_WIDTH 2
|
|
||||||
|
|
||||||
#define GTK_TOP_MARGIN 0 /* was 2 */
|
|
||||||
#define GTK_BOARD_LEFT_MARGIN 2
|
|
||||||
#define GTK_TRAY_LEFT_MARGIN 2
|
|
||||||
#define GTK_SCORE_BOARD_PADDING 0
|
|
||||||
|
|
||||||
#define GTK_HOR_SCORE_LEFT (GTK_BOARD_LEFT_MARGIN)
|
|
||||||
#define GTK_HOR_SCORE_HEIGHT 12
|
|
||||||
#define GTK_TIMER_HEIGHT GTK_HOR_SCORE_HEIGHT
|
|
||||||
#define GTK_HOR_SCORE_TOP (GTK_TOP_MARGIN)
|
|
||||||
#define GTK_TIMER_PAD 10
|
|
||||||
#define GTK_VERT_SCORE_TOP (GTK_TIMER_HEIGHT + GTK_TIMER_PAD)
|
|
||||||
#define GTK_VERT_SCORE_HEIGHT ((MIN_SCALE*MAX_COLS) - GTK_TIMER_HEIGHT - \
|
|
||||||
GTK_TIMER_PAD)
|
|
||||||
#define GTK_TIMER_WIDTH 40
|
|
||||||
#define GTK_NETSTAT_WIDTH 20
|
|
||||||
#define GTK_TIMER_TOP GTK_HOR_SCORE_TOP
|
|
||||||
#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*20)-GTK_TIMER_PAD)
|
|
||||||
#define GTK_VERT_SCORE_WIDTH 40
|
|
||||||
|
|
||||||
#define GTK_BOARD_TOP (GTK_SCORE_TOP + GTK_SCORE_HEIGHT \
|
|
||||||
+ GTK_SCORE_BOARD_PADDING )
|
|
||||||
#define GTK_BOARD_LEFT (GTK_BOARD_LEFT_MARGIN)
|
|
||||||
|
|
||||||
#define GTK_TRAY_LEFT GTK_TRAY_LEFT_MARGIN
|
|
||||||
|
|
||||||
#define GTK_DIVIDER_WIDTH 5
|
|
||||||
|
|
||||||
#define GTK_BOTTOM_MARGIN GTK_TOP_MARGIN
|
|
||||||
#define GTK_RIGHT_MARGIN GTK_BOARD_LEFT_MARGIN
|
|
||||||
|
|
||||||
#endif /* PLATFORM_GTK */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2001-2008 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2001-2013 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -22,16 +22,18 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "linuxutl.h"
|
#include "linuxutl.h"
|
||||||
|
#include "linuxmain.h"
|
||||||
#include "gtknewgame.h"
|
#include "gtknewgame.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
#include "nwgamest.h"
|
#include "nwgamest.h"
|
||||||
#include "gtkconnsdlg.h"
|
#include "gtkconnsdlg.h"
|
||||||
#include "gtkutils.h"
|
#include "gtkutils.h"
|
||||||
|
|
||||||
#define MAX_SIZE_CHOICES 10
|
#define MAX_SIZE_CHOICES 32
|
||||||
|
|
||||||
typedef struct GtkNewGameState {
|
typedef struct GtkNewGameState {
|
||||||
GtkAppGlobals* globals;
|
GtkGameGlobals* globals;
|
||||||
|
CurGameInfo* gi;
|
||||||
NewGameCtx* newGameCtxt;
|
NewGameCtx* newGameCtxt;
|
||||||
|
|
||||||
CommsAddrRec addr;
|
CommsAddrRec addr;
|
||||||
|
@ -43,6 +45,7 @@ typedef struct GtkNewGameState {
|
||||||
XP_Bool fireConnDlg;
|
XP_Bool fireConnDlg;
|
||||||
gboolean isNewGame;
|
gboolean isNewGame;
|
||||||
short nCols; /* for board size */
|
short nCols; /* for board size */
|
||||||
|
gchar* dict;
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
GtkWidget* remoteChecks[MAX_NUM_PLAYERS];
|
GtkWidget* remoteChecks[MAX_NUM_PLAYERS];
|
||||||
|
@ -153,6 +156,14 @@ size_combo_changed( GtkComboBox* combo, gpointer gp )
|
||||||
}
|
}
|
||||||
} /* size_combo_changed */
|
} /* size_combo_changed */
|
||||||
|
|
||||||
|
static void
|
||||||
|
dict_combo_changed( GtkComboBox* combo, gpointer gp )
|
||||||
|
{
|
||||||
|
GtkNewGameState* state = (GtkNewGameState*)gp;
|
||||||
|
state->dict = gtk_combo_box_get_active_text( GTK_COMBO_BOX(combo) );
|
||||||
|
XP_LOGF( "got dict: %s", state->dict );
|
||||||
|
} /* size_combo_changed */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
||||||
{
|
{
|
||||||
|
@ -199,6 +210,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
||||||
#endif
|
#endif
|
||||||
GtkWidget* nPlayersCombo;
|
GtkWidget* nPlayersCombo;
|
||||||
GtkWidget* boardSizeCombo;
|
GtkWidget* boardSizeCombo;
|
||||||
|
GtkWidget* dictCombo;
|
||||||
CurGameInfo* gi;
|
CurGameInfo* gi;
|
||||||
short ii;
|
short ii;
|
||||||
|
|
||||||
|
@ -237,7 +249,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
||||||
nPlayersCombo = gtk_combo_box_new_text();
|
nPlayersCombo = gtk_combo_box_new_text();
|
||||||
state->nPlayersCombo = nPlayersCombo;
|
state->nPlayersCombo = nPlayersCombo;
|
||||||
|
|
||||||
gi = &state->globals->cGlobals.params->gi;
|
gi = state->gi;
|
||||||
|
|
||||||
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||||
char buf[2] = { ii + '1', '\0' };
|
char buf[2] = { ii + '1', '\0' };
|
||||||
|
@ -334,12 +346,26 @@ makeNewGameDialog( GtkNewGameState* state )
|
||||||
|
|
||||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Dictionary: "),
|
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Dictionary: "),
|
||||||
FALSE, TRUE, 0 );
|
FALSE, TRUE, 0 );
|
||||||
|
dictCombo = gtk_combo_box_new_text();
|
||||||
|
g_signal_connect( GTK_OBJECT(dictCombo), "changed",
|
||||||
|
G_CALLBACK(dict_combo_changed), state );
|
||||||
|
gtk_widget_show( dictCombo );
|
||||||
|
gtk_box_pack_start( GTK_BOX(hbox), dictCombo, FALSE, TRUE, 0 );
|
||||||
|
|
||||||
if ( !!gi->dictName ) {
|
GSList* dicts = listDicts( state->globals->cGlobals.params );
|
||||||
gtk_box_pack_start( GTK_BOX(hbox),
|
GSList* iter;
|
||||||
gtk_label_new(gi->dictName),
|
for ( iter = dicts, ii = 0; !!iter; iter = iter->next, ++ii ) {
|
||||||
FALSE, TRUE, 0 );
|
const gchar* name = iter->data;
|
||||||
|
gtk_combo_box_append_text( GTK_COMBO_BOX(dictCombo), name );
|
||||||
|
if ( !!gi->dictName ) {
|
||||||
|
if ( !strcmp( name, gi->dictName ) ) {
|
||||||
|
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||||
|
}
|
||||||
|
} else if ( 0 == ii ) {
|
||||||
|
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_slist_free( dicts );
|
||||||
|
|
||||||
gtk_widget_show( hbox );
|
gtk_widget_show( hbox );
|
||||||
|
|
||||||
|
@ -516,17 +542,17 @@ gtk_newgame_attr_set( void* closure, NewGameAttr attr, NGValue value )
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr, XP_Bool isNewGame,
|
newGameDialog( GtkGameGlobals* globals, CurGameInfo* gi, CommsAddrRec* addr,
|
||||||
XP_Bool fireConnDlg )
|
XP_Bool isNewGame, XP_Bool fireConnDlg )
|
||||||
{
|
{
|
||||||
GtkNewGameState state;
|
GtkNewGameState state;
|
||||||
XP_MEMSET( &state, 0, sizeof(state) );
|
XP_MEMSET( &state, 0, sizeof(state) );
|
||||||
|
|
||||||
state.globals = globals;
|
state.globals = globals;
|
||||||
state.newGameCtxt = newg_make( MPPARM(globals->cGlobals.params
|
state.gi = gi;
|
||||||
->util->mpool)
|
state.newGameCtxt = newg_make( MPPARM(globals->cGlobals.util->mpool)
|
||||||
isNewGame,
|
isNewGame,
|
||||||
globals->cGlobals.params->util,
|
globals->cGlobals.util,
|
||||||
gtk_newgame_col_enable,
|
gtk_newgame_col_enable,
|
||||||
gtk_newgame_attr_enable,
|
gtk_newgame_attr_enable,
|
||||||
gtk_newgame_col_get,
|
gtk_newgame_col_get,
|
||||||
|
@ -542,22 +568,25 @@ newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr, XP_Bool isNewGame,
|
||||||
|
|
||||||
state.revert = FALSE;
|
state.revert = FALSE;
|
||||||
state.loaded = XP_FALSE;
|
state.loaded = XP_FALSE;
|
||||||
state.nCols = globals->cGlobals.params->gi.boardSize;
|
state.nCols = gi->boardSize;
|
||||||
state.role = globals->cGlobals.params->gi.serverRole;
|
if ( 0 == state.nCols ) {
|
||||||
|
state.nCols = globals->cGlobals.params->pgi.boardSize;
|
||||||
|
}
|
||||||
|
state.role = gi->serverRole;
|
||||||
|
|
||||||
XP_MEMCPY( &state.addr, addr, sizeof(state.addr) );
|
XP_MEMCPY( &state.addr, addr, sizeof(state.addr) );
|
||||||
|
|
||||||
dialog = makeNewGameDialog( &state );
|
dialog = makeNewGameDialog( &state );
|
||||||
|
|
||||||
newg_load( state.newGameCtxt,
|
newg_load( state.newGameCtxt, gi );
|
||||||
&globals->cGlobals.params->gi );
|
|
||||||
state.loaded = XP_TRUE;
|
state.loaded = XP_TRUE;
|
||||||
|
|
||||||
gtk_main();
|
gtk_main();
|
||||||
if ( !state.cancelled && !state.revert ) {
|
if ( !state.cancelled && !state.revert ) {
|
||||||
if ( newg_store( state.newGameCtxt, &globals->cGlobals.params->gi,
|
if ( newg_store( state.newGameCtxt, gi, XP_TRUE ) ) {
|
||||||
XP_TRUE ) ) {
|
gi->boardSize = state.nCols;
|
||||||
globals->cGlobals.params->gi.boardSize = state.nCols;
|
replaceStringIfDifferent( globals->cGlobals.util->mpool,
|
||||||
|
&gi->dictName, state.dict );
|
||||||
} else {
|
} else {
|
||||||
/* Do it again if we warned user of inconsistency. */
|
/* Do it again if we warned user of inconsistency. */
|
||||||
state.revert = XP_TRUE;
|
state.revert = XP_TRUE;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- compile-command: "make MEMDEBUG=TRUE"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2000-2013 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -24,10 +24,11 @@
|
||||||
#ifndef _GTKNEWGAME_H_
|
#ifndef _GTKNEWGAME_H_
|
||||||
#define _GTKNEWGAME_H_
|
#define _GTKNEWGAME_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
gboolean newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr,
|
gboolean newGameDialog( GtkGameGlobals* globals, CurGameInfo* gi,
|
||||||
XP_Bool isNewGame, XP_Bool fireConnDlg );
|
CommsAddrRec* addr, XP_Bool isNewGame,
|
||||||
|
XP_Bool fireConnDlg );
|
||||||
|
|
||||||
#endif /* _GTKNEWGAME_H_ */
|
#endif /* _GTKNEWGAME_H_ */
|
||||||
#endif /* PLATFORM_GTK */
|
#endif /* PLATFORM_GTK */
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _GTKNTILESASK_H_
|
#ifndef _GTKNTILESASK_H_
|
||||||
#define _GTKNTILESASK_H_
|
#define _GTKNTILESASK_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
XP_U16 askNTiles( XP_U16 nTilesMax, XP_U16 deflt );
|
XP_U16 askNTiles( XP_U16 nTilesMax, XP_U16 deflt );
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef _GTKUTILS_H_
|
#ifndef _GTKUTILS_H_
|
||||||
#define _GTKUTILS_H_
|
#define _GTKUTILS_H_
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkboard.h"
|
||||||
|
|
||||||
GtkWidget* makeButton( char* text, GCallback func, gpointer data );
|
GtkWidget* makeButton( char* text, GCallback func, gpointer data );
|
||||||
GtkWidget* makeLabeledField( const char* labelText, GtkWidget** field );
|
GtkWidget* makeLabeledField( const char* labelText, GtkWidget** field );
|
||||||
|
|
|
@ -360,7 +360,7 @@ linux_bt_open( CommonGlobals* globals, XP_Bool amMaster )
|
||||||
LinBtStuff* btStuff = globals->btStuff;
|
LinBtStuff* btStuff = globals->btStuff;
|
||||||
if ( !btStuff ) {
|
if ( !btStuff ) {
|
||||||
btStuff = globals->btStuff
|
btStuff = globals->btStuff
|
||||||
= lbt_make( MPPARM(globals->params->util->mpool) amMaster );
|
= lbt_make( MPPARM(globals->util->mpool) amMaster );
|
||||||
btStuff->globals = globals;
|
btStuff->globals = globals;
|
||||||
btStuff->socket = -1;
|
btStuff->socket = -1;
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ linux_bt_close( CommonGlobals* globals )
|
||||||
(void)close( btStuff->socket );
|
(void)close( btStuff->socket );
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_FREE( globals->params->util->mpool, btStuff );
|
XP_FREE( globals->util->mpool, btStuff );
|
||||||
globals->btStuff = NULL;
|
globals->btStuff = NULL;
|
||||||
}
|
}
|
||||||
} /* linux_bt_close */
|
} /* linux_bt_close */
|
||||||
|
|
29
xwords4/linux/linuxdict.h
Normal file
29
xwords4/linux/linuxdict.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2000 - 2013 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _LINUXDICT_H_
|
||||||
|
#define _LINUXDICT_H_
|
||||||
|
|
||||||
|
DictionaryCtxt* linux_dictionary_make( MPFORMAL
|
||||||
|
const LaunchParams* mainParams,
|
||||||
|
const char* dictFileName,
|
||||||
|
XP_Bool useMMap );
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -55,7 +55,7 @@ XP_Bool linuxFireTimer( CommonGlobals* cGlobals, XWTimerReason why );
|
||||||
|
|
||||||
|
|
||||||
XWStreamCtxt* stream_from_msgbuf( CommonGlobals* cGlobals,
|
XWStreamCtxt* stream_from_msgbuf( CommonGlobals* cGlobals,
|
||||||
unsigned char* bufPtr, XP_U16 nBytes );
|
const unsigned char* bufPtr, XP_U16 nBytes );
|
||||||
XP_UCHAR* strFromStream( XWStreamCtxt* stream );
|
XP_UCHAR* strFromStream( XWStreamCtxt* stream );
|
||||||
|
|
||||||
void catGameHistory( CommonGlobals* cGlobals );
|
void catGameHistory( CommonGlobals* cGlobals );
|
||||||
|
@ -73,8 +73,6 @@ XP_Bool getDictPath( const LaunchParams *params, const char* name,
|
||||||
GSList* listDicts( const LaunchParams *params );
|
GSList* listDicts( const LaunchParams *params );
|
||||||
void saveGame( CommonGlobals* cGlobals );
|
void saveGame( CommonGlobals* cGlobals );
|
||||||
|
|
||||||
int blocking_read( int fd, unsigned char* buf, int len );
|
|
||||||
|
|
||||||
void linux_close_socket( CommonGlobals* cGlobals );
|
void linux_close_socket( CommonGlobals* cGlobals );
|
||||||
|
|
||||||
#ifdef KEYBOARD_NAV
|
#ifdef KEYBOARD_NAV
|
||||||
|
@ -94,4 +92,23 @@ void setOneSecondTimer( CommonGlobals* cGlobals );
|
||||||
# define setOneSecondTimer( cGlobals )
|
# define setOneSecondTimer( cGlobals )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void setupLinuxUtilCallbacks( XW_UtilCtxt* util );
|
||||||
|
void initFromParams( CommonGlobals* cGlobals, LaunchParams* params );
|
||||||
|
void setupUtil( CommonGlobals* cGlobals );
|
||||||
|
|
||||||
|
DictionaryCtxt* makeDictForStream( CommonGlobals* cGlobals,
|
||||||
|
XWStreamCtxt* stream );
|
||||||
|
void linuxSetIsServer( CommonGlobals* cGlobals, XP_Bool isServer );
|
||||||
|
void linuxChangeRoles( CommonGlobals* cGlobals );
|
||||||
|
|
||||||
|
void sendRelayReg( LaunchParams* params, sqlite3* pDb );
|
||||||
|
void gameGotBuf( CommonGlobals* globals, XP_Bool haveDraw,
|
||||||
|
const XP_U8* buf, XP_U16 len );
|
||||||
|
gboolean app_socket_proc( GIOChannel* source, GIOCondition condition,
|
||||||
|
gpointer data );
|
||||||
|
const XP_UCHAR* linux_getDevID( LaunchParams* params, DevIDType* typ );
|
||||||
|
|
||||||
|
/* void initParams( LaunchParams* params ); */
|
||||||
|
/* void freeParams( LaunchParams* params ); */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*-mode: C; compile-command: "make -j MEMDEBUG=TRUE";-*- */
|
/* -*- compile-command: "make -j MEMDEBUG=TRUE";-*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2006-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2006-2009 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
|
@ -93,7 +93,7 @@ linux_sms_init( CommonGlobals* globals, const CommsAddrRec* addr )
|
||||||
{
|
{
|
||||||
LinSMSData* data = globals->smsData;
|
LinSMSData* data = globals->smsData;
|
||||||
if ( !data ) {
|
if ( !data ) {
|
||||||
data = XP_MALLOC( globals->params->util->mpool, sizeof(*data) );
|
data = XP_MALLOC( globals->util->mpool, sizeof(*data) );
|
||||||
XP_ASSERT( !!data );
|
XP_ASSERT( !!data );
|
||||||
XP_MEMSET( data, 0, sizeof(*data) );
|
XP_MEMSET( data, 0, sizeof(*data) );
|
||||||
globals->smsData = data;
|
globals->smsData = data;
|
||||||
|
@ -125,7 +125,7 @@ linux_sms_close( CommonGlobals* globals )
|
||||||
{
|
{
|
||||||
LinSMSData* data = globals->smsData;
|
LinSMSData* data = globals->smsData;
|
||||||
if ( !!data ) {
|
if ( !!data ) {
|
||||||
XP_FREE( globals->params->util->mpool, data );
|
XP_FREE( globals->util->mpool, data );
|
||||||
globals->smsData = NULL;
|
globals->smsData = NULL;
|
||||||
}
|
}
|
||||||
} /* linux_sms_close */
|
} /* linux_sms_close */
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#include "linuxutl.h"
|
#include "linuxutl.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "linuxdict.h"
|
||||||
|
#include "linuxmain.h"
|
||||||
#include "LocalizedStrIncludes.h"
|
#include "LocalizedStrIncludes.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -148,7 +150,7 @@ setSquareBonuses( const CommonGlobals* cGlobals )
|
||||||
{
|
{
|
||||||
XP_U16 nBonuses;
|
XP_U16 nBonuses;
|
||||||
XWBonusType* bonuses =
|
XWBonusType* bonuses =
|
||||||
bonusesFor( cGlobals->params->gi.boardSize, &nBonuses );
|
bonusesFor( cGlobals->gi->boardSize, &nBonuses );
|
||||||
if ( !!bonuses ) {
|
if ( !!bonuses ) {
|
||||||
model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses );
|
model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses );
|
||||||
}
|
}
|
||||||
|
@ -348,19 +350,8 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code )
|
||||||
static const XP_UCHAR*
|
static const XP_UCHAR*
|
||||||
linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ )
|
linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ )
|
||||||
{
|
{
|
||||||
XP_UCHAR* result;
|
|
||||||
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||||
if ( !!cGlobals->params->rDevID ) {
|
return linux_getDevID( cGlobals->params, typ );
|
||||||
*typ = ID_TYPE_RELAY;
|
|
||||||
result = cGlobals->params->rDevID;
|
|
||||||
} else if ( !!cGlobals->params->devID ) {
|
|
||||||
*typ = ID_TYPE_LINUX;
|
|
||||||
result = cGlobals->params->devID;
|
|
||||||
} else {
|
|
||||||
*typ = ID_TYPE_NONE;
|
|
||||||
result = NULL;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -390,6 +381,9 @@ linux_util_deviceRegistered( XW_UtilCtxt* uc, DevIDType typ,
|
||||||
void
|
void
|
||||||
linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
|
linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
|
||||||
{
|
{
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
util->mpool = mpool;
|
||||||
|
#endif
|
||||||
util->vtable = XP_MALLOC( mpool, sizeof(UtilVtable) );
|
util->vtable = XP_MALLOC( mpool, sizeof(UtilVtable) );
|
||||||
|
|
||||||
util->vtable->m_util_makeEmptyDict = linux_util_makeEmptyDict;
|
util->vtable->m_util_makeEmptyDict = linux_util_makeEmptyDict;
|
||||||
|
@ -611,7 +605,7 @@ writeNoConnMsgs( CommonGlobals* cGlobals, int fd )
|
||||||
XP_ASSERT( 0 < nMsgs );
|
XP_ASSERT( 0 < nMsgs );
|
||||||
|
|
||||||
XWStreamCtxt* stream =
|
XWStreamCtxt* stream =
|
||||||
mem_stream_make( MPPARM(cGlobals->params->util->mpool)
|
mem_stream_make( MPPARM(cGlobals->util->mpool)
|
||||||
cGlobals->params->vtMgr,
|
cGlobals->params->vtMgr,
|
||||||
cGlobals, CHANNEL_NONE, NULL );
|
cGlobals, CHANNEL_NONE, NULL );
|
||||||
stream_putU16( stream, 1 ); /* number of relayIDs */
|
stream_putU16( stream, 1 ); /* number of relayIDs */
|
||||||
|
|
|
@ -32,9 +32,6 @@ void linux_debugf(const char*, ...)
|
||||||
__attribute__ ((format (printf, 1, 2)));
|
__attribute__ ((format (printf, 1, 2)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DictionaryCtxt* linux_dictionary_make( MPFORMAL const LaunchParams* mainParams,
|
|
||||||
const char* dictFileName, XP_Bool useMMap );
|
|
||||||
|
|
||||||
|
|
||||||
void linux_util_vt_init( MPFORMAL XW_UtilCtxt* util );
|
void linux_util_vt_init( MPFORMAL XW_UtilCtxt* util );
|
||||||
void linux_util_vt_destroy( XW_UtilCtxt* util );
|
void linux_util_vt_destroy( XW_UtilCtxt* util );
|
||||||
|
@ -49,6 +46,7 @@ XP_Bool storeNoConnMsg( CommonGlobals* cGlobals, const XP_U8* msg, XP_U16 len,
|
||||||
const XP_UCHAR* relayID );
|
const XP_UCHAR* relayID );
|
||||||
void writeNoConnMsgs( CommonGlobals* cGlobals, int fd );
|
void writeNoConnMsgs( CommonGlobals* cGlobals, int fd );
|
||||||
|
|
||||||
|
|
||||||
#ifdef STREAM_VERS_BIGBOARD
|
#ifdef STREAM_VERS_BIGBOARD
|
||||||
void setSquareBonuses( const CommonGlobals* cGlobals );
|
void setSquareBonuses( const CommonGlobals* cGlobals );
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2001-2007 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2001-2013 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -25,6 +25,8 @@
|
||||||
# include <bluetooth/bluetooth.h> /* for bdaddr_t, which should move */
|
# include <bluetooth/bluetooth.h> /* for bdaddr_t, which should move */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
#include "comtypes.h"
|
#include "comtypes.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
@ -42,26 +44,33 @@ typedef struct LinuxUtilCtxt {
|
||||||
UtilVtable* vtable;
|
UtilVtable* vtable;
|
||||||
} LinuxUtilCtxt;
|
} LinuxUtilCtxt;
|
||||||
|
|
||||||
|
typedef void (*SockReceiver)( void* closure, int socket );
|
||||||
|
typedef void (*NewSocketProc)( void* closure, int newSock, int oldSock,
|
||||||
|
SockReceiver proc, void* procClosure );
|
||||||
|
|
||||||
typedef struct LaunchParams {
|
typedef struct LaunchParams {
|
||||||
/* CommPipeCtxt* pipe; */
|
/* CommPipeCtxt* pipe; */
|
||||||
XW_UtilCtxt* util;
|
CurGameInfo pgi;
|
||||||
DictionaryCtxt* dict;
|
|
||||||
CurGameInfo gi;
|
|
||||||
PlayerDicts dicts;
|
|
||||||
GSList* dictDirs;
|
GSList* dictDirs;
|
||||||
char* fileName;
|
char* fileName;
|
||||||
|
char* dbName;
|
||||||
|
sqlite3* pDb; /* null unless opened */
|
||||||
XP_U16 saveFailPct;
|
XP_U16 saveFailPct;
|
||||||
const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS];
|
const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS];
|
||||||
#ifdef USE_SQLITE
|
#ifdef USE_SQLITE
|
||||||
char* dbFileName;
|
char* dbFileName;
|
||||||
XP_U32 dbFileID;
|
XP_U32 dbFileID;
|
||||||
#endif
|
#endif
|
||||||
|
void* relayConStorage; /* opaque outside of relaycon.c */
|
||||||
char* pipe;
|
char* pipe;
|
||||||
char* nbs;
|
char* nbs;
|
||||||
char* bonusFile;
|
char* bonusFile;
|
||||||
#ifdef XWFEATURE_DEVID
|
#ifdef XWFEATURE_DEVID
|
||||||
char* devID;
|
char* devID;
|
||||||
char* rDevID;
|
char* rDevID;
|
||||||
|
XP_Bool noAnonDevid;
|
||||||
|
XP_UCHAR devIDStore[16];
|
||||||
#endif
|
#endif
|
||||||
VTableMgr* vtMgr;
|
VTableMgr* vtMgr;
|
||||||
XP_U16 nLocalPlayers;
|
XP_U16 nLocalPlayers;
|
||||||
|
@ -140,7 +149,7 @@ typedef struct LaunchParams {
|
||||||
ServerInfo serverInfo;
|
ServerInfo serverInfo;
|
||||||
ClientInfo clientInfo;
|
ClientInfo clientInfo;
|
||||||
} info;
|
} info;
|
||||||
|
MPSLOT
|
||||||
} LaunchParams;
|
} LaunchParams;
|
||||||
|
|
||||||
typedef struct CommonGlobals CommonGlobals;
|
typedef struct CommonGlobals CommonGlobals;
|
||||||
|
@ -165,17 +174,29 @@ typedef struct _TimerInfo {
|
||||||
#endif
|
#endif
|
||||||
} TimerInfo;
|
} TimerInfo;
|
||||||
|
|
||||||
|
typedef void (*OnSaveFunc)( void* closure, sqlite3_int64 rowid,
|
||||||
|
XP_Bool firstTime );
|
||||||
|
|
||||||
struct CommonGlobals {
|
struct CommonGlobals {
|
||||||
LaunchParams* params;
|
LaunchParams* params;
|
||||||
CommonPrefs cp;
|
CommonPrefs cp;
|
||||||
|
XW_UtilCtxt* util;
|
||||||
|
|
||||||
XWGame game;
|
XWGame game;
|
||||||
|
CurGameInfo* gi;
|
||||||
|
CommsAddrRec addr;
|
||||||
|
DictionaryCtxt* dict;
|
||||||
|
PlayerDicts dicts;
|
||||||
XP_U16 lastNTilesToUse;
|
XP_U16 lastNTilesToUse;
|
||||||
XP_U16 lastStreamSize;
|
XP_U16 lastStreamSize;
|
||||||
XP_Bool manualFinal; /* use asked for final scores */
|
XP_Bool manualFinal; /* use asked for final scores */
|
||||||
|
sqlite3* pDb;
|
||||||
|
sqlite3_int64 selRow;
|
||||||
|
|
||||||
SocketChangedFunc socketChanged;
|
SocketChangedFunc socketChanged;
|
||||||
void* socketChangedClosure;
|
void* socketChangedClosure;
|
||||||
|
OnSaveFunc onSave;
|
||||||
|
void* onSaveClosure;
|
||||||
GSList* packetQueue;
|
GSList* packetQueue;
|
||||||
XP_U32 nextPacketID; /* for debugging */
|
XP_U32 nextPacketID; /* for debugging */
|
||||||
|
|
||||||
|
@ -210,4 +231,24 @@ struct CommonGlobals {
|
||||||
XP_U16 curSaveToken;
|
XP_U16 curSaveToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _SourceData {
|
||||||
|
GIOChannel* channel;
|
||||||
|
gint watch;
|
||||||
|
SockReceiver proc;
|
||||||
|
void* procClosure;
|
||||||
|
} SourceData;
|
||||||
|
|
||||||
|
typedef struct _GtkAppGlobals {
|
||||||
|
GArray* selRows;
|
||||||
|
LaunchParams* params;
|
||||||
|
GSList* globalsList;
|
||||||
|
GList* sources;
|
||||||
|
GtkWidget* window;
|
||||||
|
GtkWidget* listWidget;
|
||||||
|
GtkWidget* openButton;
|
||||||
|
GtkWidget* deleteButton;
|
||||||
|
} GtkAppGlobals;
|
||||||
|
|
||||||
|
sqlite3_int64 getSelRow( const GtkAppGlobals* apg );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
364
xwords4/linux/relaycon.c
Normal file
364
xwords4/linux/relaycon.c
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2013 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "relaycon.h"
|
||||||
|
#include "comtypes.h"
|
||||||
|
|
||||||
|
typedef struct _RelayConStorage {
|
||||||
|
int socket;
|
||||||
|
RelayConnProcs procs;
|
||||||
|
void* procsClosure;
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
} RelayConStorage;
|
||||||
|
|
||||||
|
typedef struct _MsgHeader {
|
||||||
|
XWRelayReg cmd;
|
||||||
|
uint32_t packetID;
|
||||||
|
} MsgHeader;
|
||||||
|
|
||||||
|
static RelayConStorage* getStorage( LaunchParams* params );
|
||||||
|
static XP_U32 hostNameToIP( const XP_UCHAR* name );
|
||||||
|
static void relaycon_receive( void* closure, int socket );
|
||||||
|
static ssize_t sendIt( RelayConStorage* storage, const XP_U8* msgbuf, XP_U16 len );
|
||||||
|
static size_t addStrWithLength( XP_U8* buf, XP_U8* end, const XP_UCHAR* str );
|
||||||
|
static void getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf );
|
||||||
|
static XP_U16 getNetShort( const XP_U8** ptr );
|
||||||
|
static XP_U32 getNetLong( const XP_U8** ptr );
|
||||||
|
static int writeHeader( XP_U8* dest, XWRelayReg cmd );
|
||||||
|
static bool readHeader( const XP_U8** buf, MsgHeader* header );
|
||||||
|
static size_t writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str );
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
|
||||||
|
void* procsClosure, const char* host, int port )
|
||||||
|
{
|
||||||
|
XP_ASSERT( !params->relayConStorage );
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
XP_MEMCPY( &storage->procs, procs, sizeof(storage->procs) );
|
||||||
|
storage->procsClosure = procsClosure;
|
||||||
|
|
||||||
|
storage->socket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||||
|
(*procs->socketChanged)( procsClosure, storage->socket, -1,
|
||||||
|
relaycon_receive, params );
|
||||||
|
|
||||||
|
XP_MEMSET( &storage->saddr, 0, sizeof(storage->saddr) );
|
||||||
|
storage->saddr.sin_family = PF_INET;
|
||||||
|
storage->saddr.sin_addr.s_addr = htonl( hostNameToIP(host) );
|
||||||
|
storage->saddr.sin_port = htons(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relaycon_reg( LaunchParams* params, const XP_UCHAR* devID, DevIDType typ )
|
||||||
|
{
|
||||||
|
LOG_FUNC();
|
||||||
|
XP_U8 tmpbuf[32];
|
||||||
|
int indx = 0;
|
||||||
|
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
XP_ASSERT( !!devID || typ == ID_TYPE_ANON );
|
||||||
|
indx += writeHeader( tmpbuf, XWPDEV_REG );
|
||||||
|
tmpbuf[indx++] = typ;
|
||||||
|
indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID );
|
||||||
|
|
||||||
|
sendIt( storage, tmpbuf, indx );
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_S16
|
||||||
|
relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
|
||||||
|
XP_U32 gameToken, const CommsAddrRec* XP_UNUSED(addrRec) )
|
||||||
|
{
|
||||||
|
XP_ASSERT( 0 != gameToken );
|
||||||
|
ssize_t nSent = -1;
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
|
||||||
|
XP_U8 tmpbuf[1 + 4 + 1 + sizeof(gameToken) + buflen];
|
||||||
|
int indx = 0;
|
||||||
|
indx += writeHeader( tmpbuf, XWPDEV_MSG );
|
||||||
|
XP_U32 inNBO = htonl(gameToken);
|
||||||
|
XP_MEMCPY( &tmpbuf[indx], &inNBO, sizeof(inNBO) );
|
||||||
|
indx += sizeof(inNBO);
|
||||||
|
XP_MEMCPY( &tmpbuf[indx], buf, buflen );
|
||||||
|
indx += buflen;
|
||||||
|
nSent = sendIt( storage, tmpbuf, indx );
|
||||||
|
if ( nSent > buflen ) {
|
||||||
|
nSent = buflen;
|
||||||
|
}
|
||||||
|
LOG_RETURNF( "%d", nSent );
|
||||||
|
return nSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_S16
|
||||||
|
relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
|
||||||
|
const XP_UCHAR* relayID, XP_U32 gameToken )
|
||||||
|
{
|
||||||
|
XP_LOGF( "%s(relayID=%s)", __func__, relayID );
|
||||||
|
XP_ASSERT( 0 != gameToken );
|
||||||
|
XP_U16 indx = 0;
|
||||||
|
ssize_t nSent = -1;
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
|
||||||
|
XP_U16 idLen = XP_STRLEN( relayID );
|
||||||
|
XP_U8 tmpbuf[1 + 4 + 1 +
|
||||||
|
1 + idLen +
|
||||||
|
sizeof(gameToken) + buflen];
|
||||||
|
indx += writeHeader( tmpbuf, XWPDEV_MSGNOCONN );
|
||||||
|
gameToken = htonl( gameToken );
|
||||||
|
XP_MEMCPY( &tmpbuf[indx], &gameToken, sizeof(gameToken) );
|
||||||
|
indx += sizeof(gameToken);
|
||||||
|
XP_MEMCPY( &tmpbuf[indx], relayID, idLen );
|
||||||
|
indx += idLen;
|
||||||
|
tmpbuf[indx++] = '\n';
|
||||||
|
XP_MEMCPY( &tmpbuf[indx], buf, buflen );
|
||||||
|
nSent = sendIt( storage, tmpbuf, sizeof(tmpbuf) );
|
||||||
|
if ( nSent > buflen ) {
|
||||||
|
nSent = buflen;
|
||||||
|
}
|
||||||
|
LOG_RETURNF( "%d", nSent );
|
||||||
|
return nSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relaycon_requestMsgs( LaunchParams* params, const XP_UCHAR* devID )
|
||||||
|
{
|
||||||
|
XP_LOGF( "%s(devID=%s)", __func__, devID );
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
|
||||||
|
XP_U8 tmpbuf[128];
|
||||||
|
int indx = 0;
|
||||||
|
indx += writeHeader( tmpbuf, XWPDEV_RQSTMSGS );
|
||||||
|
indx += addStrWithLength( &tmpbuf[indx], tmpbuf + sizeof(tmpbuf), devID );
|
||||||
|
|
||||||
|
sendIt( storage, tmpbuf, indx );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relaycon_deleted( LaunchParams* params, const XP_UCHAR* devID,
|
||||||
|
XP_U32 gameToken )
|
||||||
|
{
|
||||||
|
LOG_FUNC();
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
XP_U8 tmpbuf[128];
|
||||||
|
int indx = 0;
|
||||||
|
indx += writeHeader( tmpbuf, XWPDEV_DELGAME );
|
||||||
|
indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID );
|
||||||
|
gameToken = htonl( gameToken );
|
||||||
|
memcpy( &tmpbuf[indx], &gameToken, sizeof(gameToken) );
|
||||||
|
indx += sizeof( gameToken );
|
||||||
|
|
||||||
|
sendIt( storage, tmpbuf, indx );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sendAckIf( RelayConStorage* storage, const MsgHeader* header )
|
||||||
|
{
|
||||||
|
if ( header->cmd != XWPDEV_ACK ) {
|
||||||
|
XP_U8 tmpbuf[16];
|
||||||
|
int indx = writeHeader( tmpbuf, XWPDEV_ACK );
|
||||||
|
uint32_t msgID = htonl( header->packetID );
|
||||||
|
memcpy( &tmpbuf[indx], &msgID, sizeof(msgID) );
|
||||||
|
indx += sizeof(msgID);
|
||||||
|
sendIt( storage, tmpbuf, indx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
relaycon_receive( void* closure, int socket )
|
||||||
|
{
|
||||||
|
LaunchParams* params = (LaunchParams*)closure;
|
||||||
|
XP_ASSERT( !!params->relayConStorage );
|
||||||
|
RelayConStorage* storage = getStorage( params );
|
||||||
|
XP_U8 buf[512];
|
||||||
|
struct sockaddr_in from;
|
||||||
|
socklen_t fromlen = sizeof(from);
|
||||||
|
|
||||||
|
XP_LOGF( "%s: calling recvfrom on socket %d", __func__, socket );
|
||||||
|
|
||||||
|
ssize_t nRead = recvfrom( socket, buf, sizeof(buf), 0, /* flags */
|
||||||
|
(struct sockaddr*)&from, &fromlen );
|
||||||
|
XP_LOGF( "%s: read %d bytes", __func__, nRead );
|
||||||
|
if ( 0 <= nRead ) {
|
||||||
|
const XP_U8* ptr = buf;
|
||||||
|
const XP_U8* end = buf + nRead;
|
||||||
|
MsgHeader header;
|
||||||
|
if ( readHeader( &ptr, &header ) ) {
|
||||||
|
sendAckIf( storage, &header );
|
||||||
|
switch( header.cmd ) {
|
||||||
|
case XWPDEV_REGRSP: {
|
||||||
|
XP_U16 len = getNetShort( &ptr );
|
||||||
|
XP_UCHAR devID[len+1];
|
||||||
|
getNetString( &ptr, len, devID );
|
||||||
|
(*storage->procs.devIDChanged)( storage->procsClosure, devID );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XWPDEV_MSG:
|
||||||
|
(*storage->procs.msgReceived)( storage->procsClosure,
|
||||||
|
ptr, end - ptr );
|
||||||
|
break;
|
||||||
|
case XWPDEV_BADREG:
|
||||||
|
(*storage->procs.devIDChanged)( storage->procsClosure, NULL );
|
||||||
|
break;
|
||||||
|
case XWPDEV_HAVEMSGS: {
|
||||||
|
(*storage->procs.msgNoticeReceived)( storage->procsClosure );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XWPDEV_ALERT: {
|
||||||
|
XP_U16 len = getNetShort( &ptr );
|
||||||
|
XP_UCHAR buf[len+1];
|
||||||
|
getNetString( &ptr, len, buf );
|
||||||
|
(*storage->procs.msgErrorMsg)( storage->procsClosure, buf );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case XWPDEV_ACK: {
|
||||||
|
XP_U32 packetID = getNetLong( &ptr );
|
||||||
|
XP_LOGF( "got ack for packetID %ld", packetID );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
XP_LOGF( "%s: Unexpected cmd %d", __func__, header.cmd );
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "%s: error reading udp socket: %d (%s)", __func__,
|
||||||
|
errno, strerror(errno) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relaycon_cleanup( LaunchParams* params )
|
||||||
|
{
|
||||||
|
XP_FREEP( params->mpool, ¶ms->relayConStorage );
|
||||||
|
}
|
||||||
|
|
||||||
|
static RelayConStorage*
|
||||||
|
getStorage( LaunchParams* params )
|
||||||
|
{
|
||||||
|
RelayConStorage* storage = (RelayConStorage*)params->relayConStorage;
|
||||||
|
if ( NULL == storage ) {
|
||||||
|
storage = XP_CALLOC( params->mpool, sizeof(*storage) );
|
||||||
|
storage->socket = -1;
|
||||||
|
params->relayConStorage = storage;
|
||||||
|
}
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_U32
|
||||||
|
hostNameToIP( const XP_UCHAR* name )
|
||||||
|
{
|
||||||
|
XP_U32 ip;
|
||||||
|
struct hostent* host;
|
||||||
|
XP_LOGF( "%s: looking up %s", __func__, name );
|
||||||
|
host = gethostbyname( name );
|
||||||
|
if ( NULL == host ) {
|
||||||
|
XP_WARNF( "gethostbyname returned NULL\n" );
|
||||||
|
} else {
|
||||||
|
XP_MEMCPY( &ip, host->h_addr_list[0], sizeof(ip) );
|
||||||
|
ip = ntohl(ip);
|
||||||
|
}
|
||||||
|
XP_LOGF( "%s found %lx for %s", __func__, ip, name );
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
sendIt( RelayConStorage* storage, const XP_U8* msgbuf, XP_U16 len )
|
||||||
|
{
|
||||||
|
ssize_t nSent = sendto( storage->socket, msgbuf, len, 0, /* flags */
|
||||||
|
(struct sockaddr*)&storage->saddr,
|
||||||
|
sizeof(storage->saddr) );
|
||||||
|
XP_LOGF( "%s()=>%d", __func__, nSent );
|
||||||
|
return nSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
addStrWithLength( XP_U8* buf, XP_U8* end, const XP_UCHAR* str )
|
||||||
|
{
|
||||||
|
XP_U16 len = !!str? XP_STRLEN( str ) : 0;
|
||||||
|
if ( buf + len + sizeof(len) <= end ) {
|
||||||
|
XP_U16 lenNBO = htons( len );
|
||||||
|
XP_MEMCPY( buf, &lenNBO, sizeof(lenNBO) );
|
||||||
|
buf += sizeof(lenNBO);
|
||||||
|
XP_MEMCPY( buf, str, len );
|
||||||
|
}
|
||||||
|
return len + sizeof(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str )
|
||||||
|
{
|
||||||
|
return addStrWithLength( buf, buf + len, str );
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_U16
|
||||||
|
getNetShort( const XP_U8** ptr )
|
||||||
|
{
|
||||||
|
XP_U16 result;
|
||||||
|
memcpy( &result, *ptr, sizeof(result) );
|
||||||
|
*ptr += sizeof(result);
|
||||||
|
return ntohs( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_U32
|
||||||
|
getNetLong( const XP_U8** ptr )
|
||||||
|
{
|
||||||
|
XP_U32 result;
|
||||||
|
memcpy( &result, *ptr, sizeof(result) );
|
||||||
|
*ptr += sizeof(result);
|
||||||
|
return ntohl( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf )
|
||||||
|
{
|
||||||
|
memcpy( buf, *ptr, len );
|
||||||
|
*ptr += len;
|
||||||
|
buf[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
writeHeader( XP_U8* dest, XWRelayReg cmd )
|
||||||
|
{
|
||||||
|
int indx = 0;
|
||||||
|
dest[indx++] = XWPDEV_PROTO_VERSION;
|
||||||
|
uint32_t packetNum = htonl(0);
|
||||||
|
memcpy( &dest[indx], &packetNum, sizeof(packetNum) );
|
||||||
|
indx += sizeof(packetNum);
|
||||||
|
dest[indx++] = cmd;
|
||||||
|
return indx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
readHeader( const XP_U8** buf, MsgHeader* header )
|
||||||
|
{
|
||||||
|
const XP_U8* ptr = *buf;
|
||||||
|
bool ok = XWPDEV_PROTO_VERSION == *ptr++;
|
||||||
|
assert( ok );
|
||||||
|
uint32_t packetID;
|
||||||
|
memcpy( &packetID, ptr, sizeof(packetID) );
|
||||||
|
ptr += sizeof(packetID);
|
||||||
|
header->packetID = ntohl( packetID );
|
||||||
|
XP_LOGF( "%s: got packet %d", __func__, header->packetID );
|
||||||
|
header->cmd = *ptr++;
|
||||||
|
*buf = ptr;
|
||||||
|
return ok;
|
||||||
|
}
|
47
xwords4/linux/relaycon.h
Normal file
47
xwords4/linux/relaycon.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2013 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 published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RELAYCON_H_
|
||||||
|
#define _RELAYCON_H_
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
typedef struct _Procs {
|
||||||
|
void (*msgReceived)( void* closure, const XP_U8* buf, XP_U16 len );
|
||||||
|
void (*msgNoticeReceived)( void* closure );
|
||||||
|
void (*devIDChanged)( void* closure, const XP_UCHAR* devID );
|
||||||
|
void (*msgErrorMsg)( void* closure, const XP_UCHAR* msg );
|
||||||
|
void (*socketChanged)( void* closure, int newSock, int oldSock,
|
||||||
|
SockReceiver proc, void* procClosure );
|
||||||
|
|
||||||
|
} RelayConnProcs;
|
||||||
|
|
||||||
|
void relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
|
||||||
|
void* procsClosure, const char* host, int port );
|
||||||
|
void relaycon_reg( LaunchParams* params, const XP_UCHAR* devID, DevIDType typ );
|
||||||
|
XP_S16 relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
|
||||||
|
XP_U32 gameID, const CommsAddrRec* addrRec );
|
||||||
|
XP_S16 relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
|
||||||
|
const XP_UCHAR* relayID, XP_U32 gameToken );
|
||||||
|
void relaycon_requestMsgs( LaunchParams* params, const XP_UCHAR* devID );
|
||||||
|
void relaycon_deleted( LaunchParams* params, const XP_UCHAR* devID,
|
||||||
|
XP_U32 gameToken );
|
||||||
|
|
||||||
|
void relaycon_cleanup( LaunchParams* params );
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@ APP_NEW=""
|
||||||
DO_CLEAN=""
|
DO_CLEAN=""
|
||||||
APP_NEW_PARAMS=""
|
APP_NEW_PARAMS=""
|
||||||
NGAMES=""
|
NGAMES=""
|
||||||
|
UDP_PCT=0
|
||||||
UPGRADE_ODDS=""
|
UPGRADE_ODDS=""
|
||||||
NROOMS=""
|
NROOMS=""
|
||||||
HOST=""
|
HOST=""
|
||||||
|
@ -188,7 +189,13 @@ build_cmds() {
|
||||||
DEV=0
|
DEV=0
|
||||||
for NLOCALS in ${LOCALS[@]}; do
|
for NLOCALS in ${LOCALS[@]}; do
|
||||||
DEV=$((DEV + 1))
|
DEV=$((DEV + 1))
|
||||||
FILE="${LOGDIR}/GAME_${GAME}_${DEV}.xwg"
|
if [ $((RANDOM % 100)) -gt $UDP_PCT ]; then
|
||||||
|
FILE="${LOGDIR}/GAME_${GAME}_${DEV}.xwg"
|
||||||
|
USE_UDP=""
|
||||||
|
else
|
||||||
|
FILE="${LOGDIR}/GAME_${GAME}_${DEV}.sql3"
|
||||||
|
USE_UDP=1
|
||||||
|
fi
|
||||||
LOG=${LOGDIR}/${GAME}_${DEV}_LOG.txt
|
LOG=${LOGDIR}/${GAME}_${DEV}_LOG.txt
|
||||||
> $LOG # clear the log
|
> $LOG # clear the log
|
||||||
|
|
||||||
|
@ -209,10 +216,15 @@ build_cmds() {
|
||||||
PARAMS="$PARAMS $BOARD_SIZE --room $ROOM --trade-pct 20 --sort-tiles "
|
PARAMS="$PARAMS $BOARD_SIZE --room $ROOM --trade-pct 20 --sort-tiles "
|
||||||
[ $UNDO_PCT -gt 0 ] && PARAMS="$PARAMS --undo-pct $UNDO_PCT "
|
[ $UNDO_PCT -gt 0 ] && PARAMS="$PARAMS --undo-pct $UNDO_PCT "
|
||||||
PARAMS="$PARAMS --game-dict $DICT --port $PORT --host $HOST "
|
PARAMS="$PARAMS --game-dict $DICT --port $PORT --host $HOST "
|
||||||
PARAMS="$PARAMS --file $FILE --slow-robot 1:3 --skip-confirm"
|
PARAMS="$PARAMS --slow-robot 1:3 --skip-confirm"
|
||||||
|
if [ -n "$USE_UDP" ]; then
|
||||||
|
PARAMS="$PARAMS --db $FILE"
|
||||||
|
else
|
||||||
|
PARAMS="$PARAMS --file $FILE"
|
||||||
|
fi
|
||||||
PARAMS="$PARAMS --drop-nth-packet $DROP_N $PLAT_PARMS"
|
PARAMS="$PARAMS --drop-nth-packet $DROP_N $PLAT_PARMS"
|
||||||
# PARAMS="$PARAMS --split-packets 2"
|
# PARAMS="$PARAMS --split-packets 2"
|
||||||
if [ -n $SEND_CHAT ]; then
|
if [ -n "$SEND_CHAT" ]; then
|
||||||
PARAMS="$PARAMS --send-chat $SEND_CHAT"
|
PARAMS="$PARAMS --send-chat $SEND_CHAT"
|
||||||
fi
|
fi
|
||||||
# PARAMS="$PARAMS --savefail-pct 10"
|
# PARAMS="$PARAMS --savefail-pct 10"
|
||||||
|
@ -316,7 +328,7 @@ kill_from_log() {
|
||||||
if [ -n "$RELAYID" ]; then
|
if [ -n "$RELAYID" ]; then
|
||||||
OBITS="$OBITS -d $RELAYID"
|
OBITS="$OBITS -d $RELAYID"
|
||||||
if [ 0 -eq $(($RANDOM%2)) ]; then
|
if [ 0 -eq $(($RANDOM%2)) ]; then
|
||||||
../relay/rq -a $HOST $OBITS 2>/dev/null || true
|
../relay/rq -a $HOST $OBITS 2>/dev/null || /bin/true
|
||||||
OBITS=""
|
OBITS=""
|
||||||
fi
|
fi
|
||||||
return 0 # success
|
return 0 # success
|
||||||
|
@ -332,7 +344,7 @@ maybe_resign() {
|
||||||
if grep -q XWRELAY_ALLHERE $LOG; then
|
if grep -q XWRELAY_ALLHERE $LOG; then
|
||||||
if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then
|
if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then
|
||||||
echo "making $LOG $(connName $LOG) resign..."
|
echo "making $LOG $(connName $LOG) resign..."
|
||||||
kill_from_log $LOG && close_device $KEY $DEADDIR "resignation forced" || true
|
kill_from_log $LOG && close_device $KEY $DEADDIR "resignation forced" || /bin/true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -380,18 +392,18 @@ check_game() {
|
||||||
# kill_from_logs $OTHERS $KEY
|
# kill_from_logs $OTHERS $KEY
|
||||||
for ID in $OTHERS $KEY; do
|
for ID in $OTHERS $KEY; do
|
||||||
echo -n "${LOGS[$ID]}, "
|
echo -n "${LOGS[$ID]}, "
|
||||||
kill_from_log ${LOGS[$ID]} || true
|
kill_from_log ${LOGS[$ID]} || /bin/true
|
||||||
close_device $ID $DONEDIR "game over"
|
close_device $ID $DONEDIR "game over"
|
||||||
done
|
done
|
||||||
echo ""
|
echo ""
|
||||||
# XWRELAY_ERROR_DELETED may be old
|
# XWRELAY_ERROR_DELETED may be old
|
||||||
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
|
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
|
||||||
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
||||||
kill_from_log $LOG || true
|
kill_from_log $LOG || /bin/true
|
||||||
close_device $KEY $DEADDIR "other resigned"
|
close_device $KEY $DEADDIR "other resigned"
|
||||||
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then
|
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then
|
||||||
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
||||||
kill_from_log $LOG || true
|
kill_from_log $LOG || /bin/true
|
||||||
close_device $KEY $DEADDIR "other resigned"
|
close_device $KEY $DEADDIR "other resigned"
|
||||||
else
|
else
|
||||||
maybe_resign $KEY
|
maybe_resign $KEY
|
||||||
|
@ -423,7 +435,7 @@ get_relayid() {
|
||||||
|
|
||||||
update_devid_cmd() {
|
update_devid_cmd() {
|
||||||
KEY=$1
|
KEY=$1
|
||||||
HELP="$(${APPS[$KEY]} --help 2>&1 || true)"
|
HELP="$(${APPS[$KEY]} --help 2>&1 || /bin/true)"
|
||||||
if echo $HELP | grep -q '\-\-devid'; then
|
if echo $HELP | grep -q '\-\-devid'; then
|
||||||
CMD="--devid LINUX_TEST_$(printf %.5d ${KEY})"
|
CMD="--devid LINUX_TEST_$(printf %.5d ${KEY})"
|
||||||
LOG=${LOGS[$KEY]}
|
LOG=${LOGS[$KEY]}
|
||||||
|
@ -467,7 +479,8 @@ run_cmds() {
|
||||||
try_upgrade $KEY
|
try_upgrade $KEY
|
||||||
launch $KEY &
|
launch $KEY &
|
||||||
PID=$!
|
PID=$!
|
||||||
renice +1 $PID >/dev/null
|
# renice doesn't work on one of my machines...
|
||||||
|
renice -n 1 -p $PID >/dev/null 2>&1 || /bin/true
|
||||||
PIDS[$KEY]=$PID
|
PIDS[$KEY]=$PID
|
||||||
ROOM_PIDS[$ROOM]=$PID
|
ROOM_PIDS[$ROOM]=$PID
|
||||||
MINEND[$KEY]=$(($NOW + $MINRUN))
|
MINEND[$KEY]=$(($NOW + $MINRUN))
|
||||||
|
@ -476,7 +489,7 @@ run_cmds() {
|
||||||
if [ -d /proc/$PID ]; then
|
if [ -d /proc/$PID ]; then
|
||||||
SLEEP=$((${MINEND[$KEY]} - $NOW))
|
SLEEP=$((${MINEND[$KEY]} - $NOW))
|
||||||
[ $SLEEP -gt 0 ] && sleep $SLEEP
|
[ $SLEEP -gt 0 ] && sleep $SLEEP
|
||||||
kill $PID || true
|
kill $PID || /bin/true
|
||||||
wait $PID
|
wait $PID
|
||||||
fi
|
fi
|
||||||
PIDS[$KEY]=0
|
PIDS[$KEY]=0
|
||||||
|
@ -487,7 +500,7 @@ run_cmds() {
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
[ -n "$OBITS" ] && ../relay/rq -a $HOST $OBITS 2>/dev/null || true
|
[ -n "$OBITS" ] && ../relay/rq -a $HOST $OBITS 2>/dev/null || /bin/true
|
||||||
|
|
||||||
# kill any remaining games
|
# kill any remaining games
|
||||||
if [ $COUNT -gt 0 ]; then
|
if [ $COUNT -gt 0 ]; then
|
||||||
|
@ -528,7 +541,7 @@ run_via_rq() {
|
||||||
launch $KEY &
|
launch $KEY &
|
||||||
PID=$!
|
PID=$!
|
||||||
sleep 2
|
sleep 2
|
||||||
kill $PID || true
|
kill $PID || /bin/true
|
||||||
wait $PID
|
wait $PID
|
||||||
fi
|
fi
|
||||||
[ "$DROP_N" -ge 0 ] && increment_drop $KEY
|
[ "$DROP_N" -ge 0 ] && increment_drop $KEY
|
||||||
|
@ -544,6 +557,7 @@ function getArg() {
|
||||||
function usage() {
|
function usage() {
|
||||||
[ $# -gt 0 ] && echo "Error: $1" >&2
|
[ $# -gt 0 ] && echo "Error: $1" >&2
|
||||||
echo "Usage: $(basename $0) \\" >&2
|
echo "Usage: $(basename $0) \\" >&2
|
||||||
|
echo " [--via-udp <pct>] \\" >&2
|
||||||
echo " [--clean-start] \\" >&2
|
echo " [--clean-start] \\" >&2
|
||||||
echo " [--game-dict <path/to/dict>]* \\" >&2
|
echo " [--game-dict <path/to/dict>]* \\" >&2
|
||||||
echo " [--old-app <path/to/app]* \\" >&2
|
echo " [--old-app <path/to/app]* \\" >&2
|
||||||
|
@ -571,6 +585,10 @@ function usage() {
|
||||||
|
|
||||||
while [ "$#" -gt 0 ]; do
|
while [ "$#" -gt 0 ]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
|
--via-udp)
|
||||||
|
UDP_PCT=$(getArg $*)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
--clean-start)
|
--clean-start)
|
||||||
DO_CLEAN=1
|
DO_CLEAN=1
|
||||||
;;
|
;;
|
||||||
|
@ -626,14 +644,14 @@ while [ "$#" -gt 0 ]; do
|
||||||
UNDO_PCT=$(getArg $*)
|
UNDO_PCT=$(getArg $*)
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--send-chat)
|
--send-chat)
|
||||||
SEND_CHAT=$(getArg $*)
|
SEND_CHAT=$(getArg $*)
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--resign-ratio)
|
--resign-ratio)
|
||||||
RESIGN_RATIO=$(getArg $*)
|
RESIGN_RATIO=$(getArg $*)
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--help)
|
--help)
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
|
|
7
xwords4/relay/scripts/list-psql-users.sh
Executable file
7
xwords4/relay/scripts/list-psql-users.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Show pids of processes holding onto the xwgames DB in some way
|
||||||
|
|
||||||
|
# from http://newstrib.com/main.asp?SectionID=2&SubSectionID=27&ArticleID=26068
|
||||||
|
|
||||||
|
echo "select pg_class.relname,pg_locks.* from pg_class,pg_locks where pg_class.relfilenode=pg_locks.relation;" | psql xwgames
|
|
@ -1053,7 +1053,7 @@ handlePutMessage( SafeCref& scr, HostID hid, const AddrInfo* addr,
|
||||||
if ( getNetByte( bufp, end, &cmd )
|
if ( getNetByte( bufp, end, &cmd )
|
||||||
&& getNetByte( bufp, end, &src )
|
&& getNetByte( bufp, end, &src )
|
||||||
&& getNetByte( bufp, end, &dest ) ) {
|
&& getNetByte( bufp, end, &dest ) ) {
|
||||||
success = true; // meaning, buffer content looks ok
|
success = true; // meaning, buffer content looks ok
|
||||||
*bufp = start + len;
|
*bufp = start + len;
|
||||||
if ( ( cmd == XWRELAY_MSG_TORELAY_NOCONN ) && ( hid == dest ) ) {
|
if ( ( cmd == XWRELAY_MSG_TORELAY_NOCONN ) && ( hid == dest ) ) {
|
||||||
scr.PutMsg( src, addr, dest, start, len );
|
scr.PutMsg( src, addr, dest, start, len );
|
||||||
|
@ -1092,7 +1092,7 @@ handleProxyMsgs( int sock, const AddrInfo* addr, const unsigned char* bufp,
|
||||||
unsigned short nMsgs;
|
unsigned short nMsgs;
|
||||||
if ( getNetShort( &bufp, end, &nMsgs ) ) {
|
if ( getNetShort( &bufp, end, &nMsgs ) ) {
|
||||||
SafeCref scr( connName );
|
SafeCref scr( connName );
|
||||||
while ( nMsgs-- > 0 ) {
|
while ( scr.IsValid() && nMsgs-- > 0 ) {
|
||||||
unsigned short len;
|
unsigned short len;
|
||||||
if ( getNetShort( &bufp, end, &len ) ) {
|
if ( getNetShort( &bufp, end, &len ) ) {
|
||||||
if ( handlePutMessage( scr, hid, addr, len, &bufp, end ) ) {
|
if ( handlePutMessage( scr, hid, addr, len, &bufp, end ) ) {
|
||||||
|
|
Loading…
Reference in a new issue