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 )
|
||||
{
|
||||
XWJNI_START();
|
||||
if ( !!state->game.comms ) {
|
||||
comms_start( state->game.comms );
|
||||
CommsCtxt* comms = 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();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
<string name="key_sms_port">key_sms_port</string>
|
||||
<string name="key_dict_host">key_dict_host3</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_init_hintsallowed">key_init_hintsallowed</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="gamel_menu_storedb">Write DB to 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-->
|
||||
|
||||
|
|
|
@ -295,6 +295,15 @@
|
|||
android:summary="@string/git_rev"
|
||||
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"
|
||||
android:title="@string/logging_on"
|
||||
android:defaultValue="false"
|
||||
|
|
|
@ -29,7 +29,6 @@ import android.bluetooth.BluetoothSocket;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -49,7 +48,7 @@ import junit.framework.Assert;
|
|||
import org.eehouse.android.xw4.MultiService.MultiEvent;
|
||||
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 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 NHE_STR = "HER";
|
||||
|
||||
private static MultiService s_srcMgr = null;
|
||||
|
||||
private enum BTCmd {
|
||||
PING,
|
||||
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 )
|
||||
{
|
||||
Intent intent = getIntentTo( context, RADIO );
|
||||
|
@ -316,12 +303,6 @@ public class BTService extends Service {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind( Intent intent )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private class BTListenerThread extends Thread {
|
||||
private BluetoothServerSocket m_serverSocket;
|
||||
|
||||
|
@ -852,11 +833,6 @@ public class BTService extends Service {
|
|||
sendResult( MultiEvent.SCAN_DONE, (Object)(names()) );
|
||||
}
|
||||
|
||||
private void sendResult( MultiEvent event, Object ... args )
|
||||
{
|
||||
s_srcMgr.sendResult( event, args );
|
||||
}
|
||||
|
||||
private void listLocalBTGames( boolean force )
|
||||
{
|
||||
if ( null == s_devGames ) {
|
||||
|
|
|
@ -190,6 +190,23 @@ public class BoardActivity extends XWActivity
|
|||
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 )
|
||||
{
|
||||
boolean delivered = false;
|
||||
|
@ -1693,7 +1710,7 @@ public class BoardActivity extends XWActivity
|
|||
|
||||
if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) {
|
||||
m_xport = new CommsTransport( m_jniGamePtr, this, this,
|
||||
m_gi.serverRole );
|
||||
m_rowid, m_gi.serverRole );
|
||||
}
|
||||
|
||||
CommonPrefs cp = CommonPrefs.get( this );
|
||||
|
|
|
@ -57,6 +57,7 @@ public class CommsTransport implements TransportProcs,
|
|||
private ByteBuffer m_bytesIn;
|
||||
|
||||
private Context m_context;
|
||||
private long m_rowid;
|
||||
|
||||
// assembling inbound packet
|
||||
private byte[] m_packetIn;
|
||||
|
@ -64,11 +65,12 @@ public class CommsTransport implements TransportProcs,
|
|||
|
||||
public CommsTransport( int jniGamePtr, Context context,
|
||||
TransportProcs.TPMsgHandler handler,
|
||||
DeviceRole role )
|
||||
long rowid, DeviceRole role )
|
||||
{
|
||||
m_jniGamePtr = jniGamePtr;
|
||||
m_context = context;
|
||||
m_tpHandler = handler;
|
||||
m_rowid = rowid;
|
||||
m_buffersOut = new Vector<ByteBuffer>();
|
||||
m_bytesIn = ByteBuffer.allocate( 2048 );
|
||||
|
||||
|
@ -377,6 +379,9 @@ public class CommsTransport implements TransportProcs,
|
|||
|
||||
switch ( addr.conType ) {
|
||||
case COMMS_CONN_RELAY:
|
||||
if ( XWPrefs.getUDPEnabled( m_context ) ) {
|
||||
nSent = RelayService.sendPacket( m_context, m_rowid, buf );
|
||||
} else {
|
||||
if ( NetStateCache.netAvail( m_context ) ) {
|
||||
putOut( buf ); // add to queue
|
||||
if ( null == m_thread ) {
|
||||
|
@ -385,6 +390,7 @@ public class CommsTransport implements TransportProcs,
|
|||
}
|
||||
nSent = buf.length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COMMS_CONN_SMS:
|
||||
nSent = SMSService.sendPacket( m_context, addr.sms_phone,
|
||||
|
|
|
@ -265,6 +265,11 @@ public class DlgDelegate {
|
|||
(String)args[0] );
|
||||
asToast = false;
|
||||
break;
|
||||
case RELAY_ALERT:
|
||||
msg = (String)args[0];
|
||||
asToast = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
DbgUtils.logf( "eventOccurred: unhandled event %s", event.toString() );
|
||||
}
|
||||
|
@ -452,9 +457,17 @@ public class DlgDelegate {
|
|||
|
||||
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 );
|
||||
// DbgUtils.logf( "addState: there are now %d active dialogs",
|
||||
// m_dlgStates.size() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,6 +58,14 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
protected void onMessage( Context context, Intent intent )
|
||||
{
|
||||
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" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
|
@ -81,11 +89,6 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
}
|
||||
}
|
||||
|
||||
value = intent.getStringExtra( "checkUpdates" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
UpdateCheckReceiver.checkVersions( context, true );
|
||||
}
|
||||
|
||||
value = intent.getStringExtra( "msg" );
|
||||
if ( null != value ) {
|
||||
String title = intent.getStringExtra( "title" );
|
||||
|
@ -95,6 +98,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void init( Application app )
|
||||
{
|
||||
|
|
|
@ -74,8 +74,9 @@ public class GamesList extends XWExpandableListActivity
|
|||
private static final String SAVE_DICTNAMES = "SAVE_DICTNAMES";
|
||||
|
||||
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 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 RESET_GAME_ACTION = 2;
|
||||
|
@ -388,6 +389,7 @@ public class GamesList extends XWExpandableListActivity
|
|||
m_gameLaunched = false;
|
||||
Assert.assertNotNull( intent );
|
||||
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
|
||||
invalRowID( intent.getLongExtra( ROWID_EXTRA, -1 ) );
|
||||
startFirstHasDict( intent );
|
||||
startNewNetGame( 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
|
||||
// present.
|
||||
private void startFirstHasDict( String[] relayIDs )
|
||||
private boolean startFirstHasDict( String[] relayIDs )
|
||||
{
|
||||
boolean launched = false;
|
||||
if ( null != relayIDs ) {
|
||||
outer:
|
||||
for ( String relayID : relayIDs ) {
|
||||
|
@ -931,19 +941,33 @@ public class GamesList extends XWExpandableListActivity
|
|||
for ( long rowid : rowids ) {
|
||||
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
||||
launchGame( rowid );
|
||||
launched = true;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return launched;
|
||||
}
|
||||
|
||||
private void startFirstHasDict( long rowid )
|
||||
{
|
||||
if ( -1 != rowid ) {
|
||||
if ( GameUtils.gameDictsHere( this, rowid ) ) {
|
||||
launchGame( rowid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startFirstHasDict( Intent intent )
|
||||
{
|
||||
if ( null != intent ) {
|
||||
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;
|
||||
}
|
||||
|
||||
public static Intent makeRelayIdsIntent( Context context,
|
||||
String[] relayIDs )
|
||||
public static Intent makeRowidIntent( Context context, long rowid )
|
||||
{
|
||||
Intent intent = makeSelfIntent( context );
|
||||
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
|
||||
intent.putExtra( ROWID_EXTRA, rowid );
|
||||
return intent;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public class MultiMsgSink implements TransportProcs {
|
|||
|
||||
public int transportSend( byte[] buf, final CommsAddrRec addr, int gameID )
|
||||
{
|
||||
Assert.fail();
|
||||
Assert.fail(); // implement if this is getting called!!!
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class MultiMsgSink implements TransportProcs {
|
|||
|
||||
public boolean relayNoConnProc( byte[] buf, String relayID )
|
||||
{
|
||||
Assert.fail();
|
||||
Assert.fail(); // implement if this is getting called!!!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ public class MultiService {
|
|||
, SMS_SEND_OK
|
||||
, SMS_SEND_FAILED
|
||||
, SMS_SEND_FAILED_NORADIO
|
||||
|
||||
, RELAY_ALERT
|
||||
};
|
||||
|
||||
public interface MultiEventListener {
|
||||
|
|
|
@ -41,6 +41,7 @@ public class PrefsActivity extends PreferenceActivity
|
|||
private String m_keyLogging;
|
||||
private String m_smsToasting;
|
||||
private String m_smsEnable;
|
||||
private String m_udpEnabled;
|
||||
private String m_downloadPath;
|
||||
|
||||
@Override
|
||||
|
@ -122,6 +123,7 @@ public class PrefsActivity extends PreferenceActivity
|
|||
m_keyLogging = getString( R.string.key_logging_on );
|
||||
m_smsToasting = getString( R.string.key_show_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 );
|
||||
|
||||
Button button = (Button)findViewById( R.id.revert_colors );
|
||||
|
@ -161,6 +163,8 @@ public class PrefsActivity extends PreferenceActivity
|
|||
DbgUtils.logEnable( sp.getBoolean( key, false ) );
|
||||
} else if ( key.equals( m_smsToasting ) ) {
|
||||
SMSService.smsToastEnable( sp.getBoolean( key, false ) );
|
||||
} else if ( key.equals( m_udpEnabled ) ) {
|
||||
RelayService.udpChanged( this );
|
||||
} else if ( key.equals( m_smsEnable ) ) {
|
||||
if ( sp.getBoolean( key, true ) ) {
|
||||
SMSService.checkForInvites( this );
|
||||
|
|
|
@ -25,24 +25,113 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
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.UtilCtxt;
|
||||
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_BUF = MAX_SEND - 2;
|
||||
|
||||
private static final String CMD_STR = "CMD";
|
||||
|
||||
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 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,
|
||||
String[] msgs64 )
|
||||
|
@ -64,27 +153,19 @@ public class RelayService extends Service {
|
|||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
|
||||
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;
|
||||
startFetchThreadIf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand( Intent intent, int flags, int startId )
|
||||
{
|
||||
DbgUtils.logf( "RelayService::onStartCommand" );
|
||||
int result;
|
||||
if ( null != intent ) {
|
||||
int cmd = intent.getIntExtra( CMD_STR, -1 );
|
||||
switch( cmd ) {
|
||||
case -1:
|
||||
break;
|
||||
case PROCESS_MSGS:
|
||||
String[] relayIDs = new String[1];
|
||||
relayIDs[0] = intent.getStringExtra( RELAY_ID );
|
||||
|
@ -100,9 +181,37 @@ public class RelayService extends Service {
|
|||
process( msgs, rowIDs, relayIDs );
|
||||
}
|
||||
break;
|
||||
case UDP_CHANGED:
|
||||
DbgUtils.logf( "RelayService::onStartCommand::UDP_CHANGED" );
|
||||
if ( XWPrefs.getUDPEnabled( this ) ) {
|
||||
stopFetchThreadIf();
|
||||
startUDPThreadsIfNot();
|
||||
registerWithRelay();
|
||||
} else {
|
||||
stopUDPThreadsIf();
|
||||
startFetchThreadIf();
|
||||
}
|
||||
stopSelf( startId );
|
||||
return Service.START_NOT_STICKY;
|
||||
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();
|
||||
}
|
||||
|
||||
result = Service.START_STICKY;
|
||||
} else {
|
||||
result = Service.START_STICKY_COMPATIBILITY;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setupNotification( String[] relayIDs )
|
||||
|
@ -111,14 +220,376 @@ public class RelayService extends Service {
|
|||
long[] rowids = DBUtils.getRowIDsFor( this, relayID );
|
||||
if ( null != rowids ) {
|
||||
for ( long rowid : rowids ) {
|
||||
Intent intent =
|
||||
GamesList.makeRelayIdsIntent( this,
|
||||
new String[] {relayID} );
|
||||
setupNotification( 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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,16 +727,34 @@ public class RelayService extends Service {
|
|||
private class RelayMsgSink extends MultiMsgSink {
|
||||
|
||||
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 )
|
||||
{
|
||||
if ( -1 == m_rowid ) {
|
||||
sendToRelay( context, m_msgLists );
|
||||
} else {
|
||||
Assert.assertNull( m_msgLists );
|
||||
}
|
||||
}
|
||||
|
||||
/***** 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 )
|
||||
{
|
||||
if ( -1 != m_rowid ) {
|
||||
sendNoConnMessage( m_rowid, relayID, buf );
|
||||
} else {
|
||||
if ( null == m_msgLists ) {
|
||||
m_msgLists = new HashMap<String,ArrayList<byte[]>>();
|
||||
}
|
||||
|
@ -276,9 +765,41 @@ public class RelayService extends Service {
|
|||
m_msgLists.put( relayID, list );
|
||||
}
|
||||
list.add( buf );
|
||||
|
||||
}
|
||||
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.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.SmsManager;
|
||||
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.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 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 SEND = 3;
|
||||
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 ADDED_MISSING = 7;
|
||||
private static final int STOP_SELF = 8;
|
||||
|
@ -77,7 +76,6 @@ public class SMSService extends Service {
|
|||
private static final String PHONE = "PHONE";
|
||||
|
||||
private static Boolean s_showToasts = null;
|
||||
private static MultiService s_srcMgr = null;
|
||||
|
||||
// All messages are base64-encoded byte arrays. The first byte is
|
||||
// always one of these. What follows depends.
|
||||
|
@ -196,16 +194,6 @@ public class SMSService extends Service {
|
|||
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 )
|
||||
{
|
||||
if ( null == s_showToasts ) {
|
||||
|
@ -303,12 +291,6 @@ public class SMSService extends Service {
|
|||
return result;
|
||||
} // onStartCommand
|
||||
|
||||
@Override
|
||||
public IBinder onBind( Intent intent )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private void inviteRemote( String phone, int gameID, String gameName,
|
||||
int lang, String dict,
|
||||
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()
|
||||
{
|
||||
registerReceiver( new BroadcastReceiver() {
|
||||
|
|
|
@ -54,8 +54,7 @@ public class XWActivity extends Activity
|
|||
protected void onResume()
|
||||
{
|
||||
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
||||
BTService.setListener( this );
|
||||
SMSService.setListener( this );
|
||||
XWService.setListener( this );
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
|
@ -63,8 +62,7 @@ public class XWActivity extends Activity
|
|||
protected void onPause()
|
||||
{
|
||||
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
||||
BTService.setListener( null );
|
||||
SMSService.setListener( null );
|
||||
XWService.setListener( null );
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,10 @@ public class XWApp extends Application {
|
|||
|
||||
RelayReceiver.RestartTimer( this );
|
||||
UpdateCheckReceiver.restartTimer( this );
|
||||
|
||||
BTService.startService( this );
|
||||
|
||||
SMSService.checkForInvites( this );
|
||||
|
||||
RelayService.startService( this );
|
||||
GCMIntentService.init( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,22 @@ public class XWExpandableListActivity extends ExpandableListActivity
|
|||
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
|
||||
protected void onSaveInstanceState( Bundle outState )
|
||||
{
|
||||
|
|
|
@ -51,8 +51,7 @@ public class XWListActivity extends ListActivity
|
|||
protected void onResume()
|
||||
{
|
||||
DbgUtils.logf( "%s.onResume(this=%H)", getClass().getName(), this );
|
||||
BTService.setListener( this );
|
||||
SMSService.setListener( this );
|
||||
XWService.setListener( this );
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
|
@ -60,8 +59,7 @@ public class XWListActivity extends ListActivity
|
|||
protected void onPause()
|
||||
{
|
||||
DbgUtils.logf( "%s.onPause(this=%H)", getClass().getName(), this );
|
||||
BTService.setListener( null );
|
||||
SMSService.setListener( null );
|
||||
XWService.setListener( null );
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,16 @@ public class XWPrefs {
|
|||
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 )
|
||||
{
|
||||
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.
|
||||
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 );
|
||||
if ( null != 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_RELAY = 1;
|
||||
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 );
|
||||
void deviceRegistered( int devIDType, String idRelay );
|
||||
|
|
|
@ -234,6 +234,7 @@ public class XwJNI {
|
|||
|
||||
// Comms
|
||||
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_getAddr( int gamePtr, CommsAddrRec addr );
|
||||
public static native CommsAddrRec[] comms_getAddrs( int gamePtr );
|
||||
|
|
|
@ -467,8 +467,11 @@ comms_transportFailed( CommsCtxt* comms )
|
|||
void
|
||||
comms_destroy( CommsCtxt* comms )
|
||||
{
|
||||
CommsAddrRec aNew;
|
||||
aNew.conType = COMMS_CONN_NONE;
|
||||
/* did I call comms_stop()? */
|
||||
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 );
|
||||
|
||||
cleanupInternal( comms );
|
||||
|
@ -665,6 +668,14 @@ comms_start( CommsCtxt* comms )
|
|||
sendConnect( comms, XP_FALSE );
|
||||
} /* comms_start */
|
||||
|
||||
void
|
||||
comms_stop( CommsCtxt* comms )
|
||||
{
|
||||
if ( COMMS_CONN_RELAY == comms->addr.conType ) {
|
||||
relayDisconnect( comms );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sendConnect( CommsCtxt* comms, XP_Bool breakExisting )
|
||||
{
|
||||
|
@ -1185,6 +1196,14 @@ gameID( const CommsCtxt* comms )
|
|||
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
|
||||
be. Would be nice not to have to use gameID. */
|
||||
if ( 0 == gameID ) {
|
||||
|
|
|
@ -198,6 +198,7 @@ CommsCtxt* comms_makeFromStream( MPFORMAL XWStreamCtxt* stream,
|
|||
XW_UtilCtxt* util,
|
||||
const TransportProcs* procs );
|
||||
void comms_start( CommsCtxt* comms );
|
||||
void comms_stop( CommsCtxt* comms );
|
||||
void comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||
XP_U16 saveToken );
|
||||
void comms_saveSucceeded( CommsCtxt* comms, XP_U16 saveToken );
|
||||
|
|
|
@ -249,7 +249,7 @@ typedef struct _PlayerDicts {
|
|||
# define RELAY_ROOM_DEFAULT "Room 1"
|
||||
#endif
|
||||
#ifndef RELAY_PORT_DEFAULT
|
||||
# define RELAY_PORT_DEFAULT 10999
|
||||
# define RELAY_PORT_DEFAULT 10997
|
||||
#endif
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
|
|
|
@ -133,13 +133,15 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
|||
board_prefsChanged( game->board, cp );
|
||||
} /* game_makeNewGame */
|
||||
|
||||
void
|
||||
XP_Bool
|
||||
game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||
XW_UtilCtxt* XP_UNUSED_STANDALONE(util),
|
||||
CommonPrefs* cp, const TransportProcs* procs )
|
||||
{
|
||||
XP_Bool result = XP_FALSE;
|
||||
XP_U16 ii;
|
||||
|
||||
if ( !!game->model ) {
|
||||
XP_ASSERT( !!game->model );
|
||||
XP_ASSERT( !!gi );
|
||||
|
||||
|
@ -189,6 +191,9 @@ game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
|
|||
|
||||
server_prefsChanged( game->server, cp );
|
||||
board_prefsChanged( game->board, cp );
|
||||
result = XP_TRUE;
|
||||
}
|
||||
return result;
|
||||
} /* game_reset */
|
||||
|
||||
#ifdef XWFEATURE_CHANGEDICT
|
||||
|
@ -335,6 +340,7 @@ game_dispose( XWGame* game )
|
|||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
if ( !!game->comms ) {
|
||||
comms_stop( game->comms );
|
||||
comms_destroy( game->comms );
|
||||
game->comms = NULL;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
|||
,XP_U16 gameSeed
|
||||
#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 );
|
||||
void game_changeDict( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||
DictionaryCtxt* dict );
|
||||
|
|
|
@ -78,19 +78,21 @@ checkIsText( MemPoolEntry* entry )
|
|||
{
|
||||
unsigned char* txt = (unsigned char*)entry->ptr;
|
||||
XP_U32 len = entry->size;
|
||||
char* result = NULL;
|
||||
|
||||
if ( 0 < len ) {
|
||||
while ( len-- ) {
|
||||
unsigned char c = *txt++;
|
||||
if ( c < 32 || c > 127 ) {
|
||||
if ( len == 0 && c == '\0' ) {
|
||||
return (char*)entry->ptr;
|
||||
} else {
|
||||
return (char*)NULL;
|
||||
result = (char*)entry->ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (char*)NULL;
|
||||
return result;
|
||||
} /* checkIsText */
|
||||
#endif
|
||||
|
||||
|
@ -226,6 +228,7 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
|
|||
if ( !entry ) {
|
||||
XP_LOGF( "findEntryFor failed; called from %s, line %ld in %s",
|
||||
func, lineNo, file );
|
||||
XP_ASSERT( 0 );
|
||||
} else {
|
||||
|
||||
#ifdef MPOOL_DEBUG
|
||||
|
@ -249,11 +252,7 @@ mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
|
|||
|
||||
++mpool->nFree;
|
||||
--mpool->nUsed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
XP_ASSERT( 0 );
|
||||
} /* mpool_free */
|
||||
|
||||
void
|
||||
|
|
1
xwords4/linux/.gitignore
vendored
1
xwords4/linux/.gitignore
vendored
|
@ -6,3 +6,4 @@ obj_linux_rel
|
|||
log_*_*.txt
|
||||
discon_ok2.sh_logs
|
||||
test_backsend.sh_*
|
||||
games.db
|
||||
|
|
|
@ -101,6 +101,7 @@ DEFINES += -DXWFEATURE_WALKDICT
|
|||
DEFINES += -DXWFEATURE_WALKDICT_FILTER
|
||||
DEFINES += -DXWFEATURE_DICTSANITY
|
||||
DEFINES += -DHASH_STREAM
|
||||
DEFINES += -DRELAY_NAME_DEFAULT="\"localhost\""
|
||||
#DEFINES += -DXWFEATURE_SCOREONEPASS
|
||||
### Enable zero or one of these two ###
|
||||
#DEFINES += -DXWFEATURE_TRAYUNDO_ALL
|
||||
|
@ -112,6 +113,7 @@ DEFINES += -DXWFEATURE_HILITECELL
|
|||
DEFINES += -DXWFEATURE_CHANGEDICT
|
||||
DEFINES += -DXWFEATURE_DEVID
|
||||
DEFINES += -DXWFEATURE_COMMSACK
|
||||
DEFINES += -DCOMMS_XPORT_FLAGSPROC
|
||||
|
||||
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
||||
DEFINES += -DMAX_ROWS=32
|
||||
|
@ -169,6 +171,7 @@ INCLUDES += ${EXTRAINCS}
|
|||
ifdef DO_GTK
|
||||
GTK_OBJS = \
|
||||
$(BUILD_PLAT_DIR)/gtkmain.o \
|
||||
$(BUILD_PLAT_DIR)/gtkboard.o \
|
||||
$(BUILD_PLAT_DIR)/gtkdraw.o \
|
||||
$(BUILD_PLAT_DIR)/gtkask.o \
|
||||
$(BUILD_PLAT_DIR)/gtkletterask.o \
|
||||
|
@ -201,6 +204,8 @@ OBJ = \
|
|||
$(BUILD_PLAT_DIR)/linuxsms.o \
|
||||
$(BUILD_PLAT_DIR)/linuxdict.o \
|
||||
$(BUILD_PLAT_DIR)/linuxutl.o \
|
||||
$(BUILD_PLAT_DIR)/gamesdb.o \
|
||||
$(BUILD_PLAT_DIR)/relaycon.o \
|
||||
$(CURSES_OBJS) $(GTK_OBJS) $(MAIN_OBJS)
|
||||
|
||||
LIBS = -lm -luuid $(GPROFFLAG)
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
/* Figure out how many lines there are and how wide the widest is.
|
||||
*/
|
||||
short
|
||||
cursesask( CursesAppGlobals* globals, char* question, short numButtons,
|
||||
char* button1, ... )
|
||||
cursesask( CursesAppGlobals* globals, const char* question, short numButtons,
|
||||
const char* button1, ... )
|
||||
{
|
||||
WINDOW* confWin;
|
||||
int x, y, rows, row, nLines;
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
#include "cursesmain.h"
|
||||
|
||||
short cursesask( CursesAppGlobals* globals, char* question,
|
||||
short numButtons, char* button1, ... );
|
||||
short cursesask( CursesAppGlobals* globals, const char* question,
|
||||
short numButtons, const char* button1, ... );
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ measureAskText( const XP_UCHAR* question, int width, FormatInfo* fip )
|
|||
|
||||
void
|
||||
drawButtons( WINDOW* win, XP_U16 line, short spacePerButton,
|
||||
short numButtons, short curSelButton, char** button1 )
|
||||
short numButtons, short curSelButton, const char** button1 )
|
||||
{
|
||||
short 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 drawButtons( WINDOW* confWin, XP_U16 line, short spacePerButton,
|
||||
short numButtons, short curSelButton, char** button1 );
|
||||
short numButtons, short curSelButton, const char** button1 );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,7 +57,7 @@ curses_askLetter( CursesAppGlobals* globals, XP_UCHAR* query,
|
|||
short curSelButton = 1; /* force draw by being different */
|
||||
short maxWidth;
|
||||
short numCtlButtons;
|
||||
char* ctlButtons[] = { "Ok", "Cancel" };
|
||||
const char* ctlButtons[] = { "Ok", "Cancel" };
|
||||
XP_Bool dismissed = XP_FALSE;
|
||||
FormatInfo fi;
|
||||
int len;
|
||||
|
@ -138,7 +138,7 @@ curses_askLetter( CursesAppGlobals* globals, XP_UCHAR* query,
|
|||
MAX_TILE_BUTTON_WIDTH-1,
|
||||
nInRow,
|
||||
newSelButton - textsOffsets[i],
|
||||
(char**)&textPtrs[textsOffsets[i]] );
|
||||
(const char**)&textPtrs[textsOffsets[i]] );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "linuxmain.h"
|
||||
#include "linuxutl.h"
|
||||
#include "linuxdict.h"
|
||||
#include "cursesmain.h"
|
||||
#include "cursesask.h"
|
||||
#include "cursesletterask.h"
|
||||
|
@ -61,6 +62,8 @@
|
|||
#include "dbgutil.h"
|
||||
#include "linuxsms.h"
|
||||
#include "linuxudp.h"
|
||||
#include "gamesdb.h"
|
||||
#include "relaycon.h"
|
||||
|
||||
#ifdef CURSES_SMALL_SCREEN
|
||||
# define MENU_WINDOW_HEIGHT 1
|
||||
|
@ -208,7 +211,7 @@ static CursesMenuHandler getHandlerForKey( const MenuList* list, char ch );
|
|||
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
# define MEMPOOL params->util->mpool,
|
||||
# define MEMPOOL cGlobals->util->mpool,
|
||||
#else
|
||||
# define MEMPOOL
|
||||
#endif
|
||||
|
@ -237,7 +240,7 @@ curses_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
|||
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||
char query[128];
|
||||
XP_S16 index;
|
||||
char* playerName = globals->cGlobals.params->gi.players[playerNum].name;
|
||||
char* playerName = globals->cGlobals.gi->players[playerNum].name;
|
||||
|
||||
snprintf( query, sizeof(query),
|
||||
"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;
|
||||
char query[128];
|
||||
XP_S16 index;
|
||||
char* playerName = globals->cGlobals.params->gi.players[playerNum].name;
|
||||
char* playerName = globals->cGlobals.gi->players[playerNum].name;
|
||||
|
||||
snprintf( query, sizeof(query),
|
||||
"Pick tile for %s! (Tab or type letter to select "
|
||||
|
@ -343,7 +346,7 @@ cursesShowFinalScores( CursesAppGlobals* globals )
|
|||
XWStreamCtxt* stream;
|
||||
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, CHANNEL_NONE, NULL );
|
||||
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 );
|
||||
}
|
||||
|
||||
static void
|
||||
curses_util_setIsServer( XW_UtilCtxt* uc, XP_Bool isServer )
|
||||
{
|
||||
LOG_FUNC();
|
||||
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||
linuxSetIsServer( cGlobals, isServer );
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_HILITECELL
|
||||
static XP_Bool
|
||||
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) ) {
|
||||
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
||||
int fd = g_io_channel_unix_get_fd( source );
|
||||
unsigned char buf[256];
|
||||
unsigned char buf[1024];
|
||||
int nBytes;
|
||||
CommsAddrRec addrRec;
|
||||
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
|
||||
shot. So just call the idle proc. */
|
||||
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
|
||||
} /* 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
|
||||
static gboolean
|
||||
handle_quitwrite( GIOChannel* XP_UNUSED(source), GIOCondition XP_UNUSED(condition), gpointer data )
|
||||
|
@ -1284,7 +1304,7 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch )
|
|||
globals );
|
||||
} else {
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
unsigned char buf[256];
|
||||
unsigned char buf[1024];
|
||||
int nBytes;
|
||||
CommsAddrRec addrRec;
|
||||
CommsAddrRec* addrp = NULL;
|
||||
|
@ -1489,7 +1509,7 @@ curses_util_remSelected( XW_UtilCtxt* uc )
|
|||
XWStreamCtxt* stream;
|
||||
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, CHANNEL_NONE, NULL );
|
||||
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_notifyGameOver = curses_util_notifyGameOver;
|
||||
util->vtable->m_util_informNetDict = curses_util_informNetDict;
|
||||
util->vtable->m_util_setIsServer = curses_util_setIsServer;
|
||||
|
||||
#ifdef XWFEATURE_HILITECELL
|
||||
util->vtable->m_util_hiliteCell = curses_util_hiliteCell;
|
||||
#endif
|
||||
|
@ -1609,7 +1631,7 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height )
|
|||
XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth;
|
||||
BoardCtxt* board = globals->cGlobals.game.board;
|
||||
int remWidth = width;
|
||||
int nRows = globals->cGlobals.params->gi.boardSize;
|
||||
int nRows = globals->cGlobals.gi->boardSize;
|
||||
|
||||
cellWidth = CURSES_CELL_WIDTH;
|
||||
cellHt = CURSES_CELL_HT;
|
||||
|
@ -1719,6 +1741,119 @@ handle_stdin( GIOChannel* XP_UNUSED_DBG(source), GIOCondition condition,
|
|||
}
|
||||
#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
|
||||
chatsTimerFired( gpointer data )
|
||||
{
|
||||
|
@ -1748,6 +1883,7 @@ void
|
|||
cursesmain( XP_Bool isServer, LaunchParams* params )
|
||||
{
|
||||
int width, height;
|
||||
CommonGlobals* cGlobals = &g_globals.cGlobals;
|
||||
|
||||
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.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.cp.showBoardArrow = XP_TRUE;
|
||||
|
@ -1778,7 +1917,11 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
g_globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
||||
#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
|
||||
if ( params->conType == COMMS_CONN_RELAY ) {
|
||||
|
@ -1792,12 +1935,14 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
cursesListenOnSocket( &g_globals, 0, handle_stdin );
|
||||
}
|
||||
setOneSecondTimer( &g_globals.cGlobals );
|
||||
|
||||
# ifdef DEBUG
|
||||
int piperesult =
|
||||
# endif
|
||||
pipe( g_globals.quitpipe );
|
||||
XP_ASSERT( piperesult == 0 );
|
||||
cursesListenOnSocket( &g_globals, g_globals.quitpipe[0], handle_quitwrite );
|
||||
|
||||
#else
|
||||
cursesListenOnSocket( &g_globals, 0 ); /* stdin */
|
||||
|
||||
|
@ -1824,7 +1969,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
.rconnd = relay_connd_curses,
|
||||
.rerror = relay_error_curses,
|
||||
.sendNoConn = relay_sendNoConn_curses,
|
||||
.flags = COMMS_XPORT_FLAGS_HASNOCONN,
|
||||
# ifdef COMMS_XPORT_FLAGSPROC
|
||||
.getFlags = curses_getFlags,
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1846,7 +1993,40 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
cursesDrawCtxtMake( g_globals.boardWin );
|
||||
|
||||
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,
|
||||
&g_globals );
|
||||
#ifdef USE_SQLITE
|
||||
|
@ -1855,27 +2035,40 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
#endif
|
||||
}
|
||||
|
||||
if ( NULL == cGlobals->dict ) {
|
||||
if ( !!stream ) {
|
||||
(void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game,
|
||||
¶ms->gi, params->dict, ¶ms->dicts,
|
||||
params->util,
|
||||
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 ) {
|
||||
(void)game_makeFromStream( MEMPOOL stream, &cGlobals->game,
|
||||
cGlobals->gi, cGlobals->dict,
|
||||
&cGlobals->dicts, cGlobals->util,
|
||||
(DrawCtx*)g_globals.draw,
|
||||
&g_globals.cGlobals.cp, &procs );
|
||||
|
||||
stream_destroy( stream );
|
||||
if ( !isServer && params->gi.serverRole == SERVER_ISSERVER ) {
|
||||
if ( !isServer && cGlobals->gi->serverRole == SERVER_ISSERVER ) {
|
||||
isServer = XP_TRUE;
|
||||
}
|
||||
opened = XP_TRUE;
|
||||
}
|
||||
if ( !opened ) {
|
||||
game_makeNewGame( MEMPOOL &g_globals.cGlobals.game, ¶ms->gi,
|
||||
params->util, (DrawCtx*)g_globals.draw,
|
||||
game_makeNewGame( MEMPOOL &cGlobals->game, cGlobals->gi,
|
||||
cGlobals->util, (DrawCtx*)g_globals.draw,
|
||||
&g_globals.cGlobals.cp, &procs, params->gameSeed );
|
||||
g_globals.cGlobals.selRow = -1;
|
||||
saveGame( &g_globals.cGlobals );
|
||||
}
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
if ( g_globals.cGlobals.game.comms ) {
|
||||
if ( cGlobals->game.comms ) {
|
||||
CommsAddrRec addr = {0};
|
||||
|
||||
if ( 0 ) {
|
||||
|
@ -1907,22 +2100,22 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
sizeof(params->connInfo.bt.hostAddr) );
|
||||
# endif
|
||||
}
|
||||
comms_setAddr( g_globals.cGlobals.game.comms, &addr );
|
||||
comms_setAddr( cGlobals->game.comms, &addr );
|
||||
}
|
||||
#endif
|
||||
|
||||
model_setDictionary( g_globals.cGlobals.game.model, params->dict );
|
||||
setSquareBonuses( &g_globals.cGlobals );
|
||||
model_setDictionary( cGlobals->game.model, cGlobals->dict );
|
||||
setSquareBonuses( cGlobals );
|
||||
positionSizeStuff( &g_globals, width, height );
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
/* send any events that need to get off before the event loop begins */
|
||||
if ( !isServer ) {
|
||||
if ( 1 /* stream_open( params->info.clientInfo.stream ) */) {
|
||||
server_initClientConnection( g_globals.cGlobals.game.server,
|
||||
server_initClientConnection( cGlobals->game.server,
|
||||
mem_stream_make( MEMPOOL
|
||||
params->vtMgr,
|
||||
&g_globals.cGlobals,
|
||||
cGlobals,
|
||||
(XP_PlayerAddr)0,
|
||||
sendOnClose ) );
|
||||
} else {
|
||||
|
@ -1961,10 +2154,13 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
}
|
||||
#endif
|
||||
}
|
||||
if ( !!g_globals.cGlobals.game.comms ) {
|
||||
comms_stop( g_globals.cGlobals.game.comms );
|
||||
}
|
||||
saveGame( &g_globals.cGlobals );
|
||||
|
||||
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
|
||||
linux_bt_close( &g_globals.cGlobals );
|
||||
|
@ -1977,5 +2173,12 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
#endif
|
||||
|
||||
endwin();
|
||||
|
||||
if ( !!params->dbName ) {
|
||||
closeGamesDB( g_globals.cGlobals.pDb );
|
||||
}
|
||||
relaycon_cleanup( params );
|
||||
|
||||
linux_util_vt_destroy( g_globals.cGlobals.util );
|
||||
} /* cursesmain */
|
||||
#endif /* PLATFORM_NCURSES */
|
||||
|
|
|
@ -68,6 +68,7 @@ struct CursesAppGlobals {
|
|||
XP_Bool doDraw;
|
||||
const struct MenuList* menuList;
|
||||
XP_U16 nLinesMenu;
|
||||
gchar* lastErr;
|
||||
|
||||
XP_U16 nChatsSent;
|
||||
|
||||
|
@ -98,13 +99,6 @@ struct CursesAppGlobals {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef USE_GLIBLOOP
|
||||
typedef struct _SourceData {
|
||||
GIOChannel* channel;
|
||||
gint watch;
|
||||
} SourceData;
|
||||
#endif
|
||||
|
||||
DrawCtx* cursesDrawCtxtMake( WINDOW* boardWin );
|
||||
|
||||
/* 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_
|
||||
#define _GTKASK_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
/* Returns true for "yes" or "ok" answer, false otherwise.
|
||||
*/
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef _GTKASKDICT_H_
|
||||
#define _GTKASKDICT_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
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"
|
||||
|
||||
gchar*
|
||||
gtkGetChatMessage( GtkAppGlobals* XP_UNUSED(globals) )
|
||||
gtkGetChatMessage( GtkGameGlobals* XP_UNUSED(globals) )
|
||||
{
|
||||
gchar* result = NULL;
|
||||
GtkWidget* dialog = gtk_dialog_new_with_buttons( "message text", NULL, //GtkWindow *parent,
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#ifdef PLATFORM_GTK
|
||||
|
||||
#include <glib.h>
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
gchar* gtkGetChatMessage( GtkAppGlobals* globals );
|
||||
gchar* gtkGetChatMessage( GtkGameGlobals* globals );
|
||||
|
||||
#endif
|
||||
#endif /* #ifndef _GTKCHAT_H_ */
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "gtkutils.h"
|
||||
|
||||
typedef struct _GtkConnsState {
|
||||
GtkAppGlobals* globals;
|
||||
GtkGameGlobals* globals;
|
||||
CommsAddrRec* addr;
|
||||
DeviceRole role;
|
||||
|
||||
|
@ -179,7 +179,7 @@ makeBTPage( GtkConnsState* state )
|
|||
} /* makeBTPage */
|
||||
|
||||
gboolean
|
||||
gtkConnsDlg( GtkAppGlobals* globals, CommsAddrRec* addr, DeviceRole role,
|
||||
gtkConnsDlg( GtkGameGlobals* globals, CommsAddrRec* addr, DeviceRole role,
|
||||
XP_Bool readOnly )
|
||||
{
|
||||
GtkConnsState state;
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#ifndef _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 );
|
||||
|
||||
#endif /* _GTKCONNSDLG_H_ */
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <gdk/gdkdrawable.h>
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
#include "draw.h"
|
||||
#include "board.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;
|
||||
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;
|
||||
GdkColor* cursor =
|
||||
((flags & CELL_ISCURSOR) != 0) ? &dctx->cursor : NULL;
|
||||
|
@ -1305,7 +1306,7 @@ allocAndSet( GdkColormap* map, GdkColor* color, unsigned short red,
|
|||
} /* allocAndSet */
|
||||
|
||||
DrawCtx*
|
||||
gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
|
||||
gtkDrawCtxtMake( GtkWidget* drawing_area, GtkGameGlobals* globals )
|
||||
{
|
||||
GtkDrawCtx* dctx = g_malloc0( sizeof(GtkDrawCtx) );
|
||||
GdkColormap* map;
|
||||
|
@ -1423,7 +1424,7 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
|
|||
void
|
||||
draw_gtk_status( GtkDrawCtx* dctx, char ch )
|
||||
{
|
||||
GtkAppGlobals* globals = dctx->globals;
|
||||
GtkGameGlobals* globals = dctx->globals;
|
||||
|
||||
XP_Rect rect = {
|
||||
.left = globals->netStatLeft,
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "draw.h"
|
||||
|
||||
DrawCtx* gtkDrawCtxtMake( GtkWidget *widget, GtkAppGlobals* globals );
|
||||
DrawCtx* gtkDrawCtxtMake( GtkWidget *widget, GtkGameGlobals* globals );
|
||||
|
||||
void draw_gtk_status( GtkDrawCtx* draw, char ch );
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#ifndef _GTKLETTERASK_H_
|
||||
#define _GTKLETTERASK_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
XP_S16 gtkletterask( const PickInfo* pi, XP_Bool forTray,
|
||||
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; -*- */
|
||||
/* Copyright 1997 - 2005 by Eric House (xwords@eehouse.org) All rights
|
||||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/* Copyright 1997 - 2013 by Eric House (xwords@eehouse.org) All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -20,155 +20,11 @@
|
|||
#ifndef _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 "game.h"
|
||||
#include "dictnry.h"
|
||||
#include "gtkboard.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 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 */
|
||||
int gtkmain( LaunchParams* params );
|
||||
void windowDestroyed( GtkGameGlobals* globals );
|
||||
void onGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime );
|
||||
|
||||
#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.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -22,16 +22,18 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
#include "linuxutl.h"
|
||||
#include "linuxmain.h"
|
||||
#include "gtknewgame.h"
|
||||
#include "strutils.h"
|
||||
#include "nwgamest.h"
|
||||
#include "gtkconnsdlg.h"
|
||||
#include "gtkutils.h"
|
||||
|
||||
#define MAX_SIZE_CHOICES 10
|
||||
#define MAX_SIZE_CHOICES 32
|
||||
|
||||
typedef struct GtkNewGameState {
|
||||
GtkAppGlobals* globals;
|
||||
GtkGameGlobals* globals;
|
||||
CurGameInfo* gi;
|
||||
NewGameCtx* newGameCtxt;
|
||||
|
||||
CommsAddrRec addr;
|
||||
|
@ -43,6 +45,7 @@ typedef struct GtkNewGameState {
|
|||
XP_Bool fireConnDlg;
|
||||
gboolean isNewGame;
|
||||
short nCols; /* for board size */
|
||||
gchar* dict;
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
GtkWidget* remoteChecks[MAX_NUM_PLAYERS];
|
||||
|
@ -153,6 +156,14 @@ size_combo_changed( GtkComboBox* combo, gpointer gp )
|
|||
}
|
||||
} /* 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
|
||||
handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
||||
{
|
||||
|
@ -199,6 +210,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
#endif
|
||||
GtkWidget* nPlayersCombo;
|
||||
GtkWidget* boardSizeCombo;
|
||||
GtkWidget* dictCombo;
|
||||
CurGameInfo* gi;
|
||||
short ii;
|
||||
|
||||
|
@ -237,7 +249,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
nPlayersCombo = gtk_combo_box_new_text();
|
||||
state->nPlayersCombo = nPlayersCombo;
|
||||
|
||||
gi = &state->globals->cGlobals.params->gi;
|
||||
gi = state->gi;
|
||||
|
||||
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||
char buf[2] = { ii + '1', '\0' };
|
||||
|
@ -334,12 +346,26 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Dictionary: "),
|
||||
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 );
|
||||
|
||||
GSList* dicts = listDicts( state->globals->cGlobals.params );
|
||||
GSList* iter;
|
||||
for ( iter = dicts, ii = 0; !!iter; iter = iter->next, ++ii ) {
|
||||
const gchar* name = iter->data;
|
||||
gtk_combo_box_append_text( GTK_COMBO_BOX(dictCombo), name );
|
||||
if ( !!gi->dictName ) {
|
||||
gtk_box_pack_start( GTK_BOX(hbox),
|
||||
gtk_label_new(gi->dictName),
|
||||
FALSE, TRUE, 0 );
|
||||
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 );
|
||||
|
||||
|
@ -516,17 +542,17 @@ gtk_newgame_attr_set( void* closure, NewGameAttr attr, NGValue value )
|
|||
}
|
||||
|
||||
gboolean
|
||||
newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr, XP_Bool isNewGame,
|
||||
XP_Bool fireConnDlg )
|
||||
newGameDialog( GtkGameGlobals* globals, CurGameInfo* gi, CommsAddrRec* addr,
|
||||
XP_Bool isNewGame, XP_Bool fireConnDlg )
|
||||
{
|
||||
GtkNewGameState state;
|
||||
XP_MEMSET( &state, 0, sizeof(state) );
|
||||
|
||||
state.globals = globals;
|
||||
state.newGameCtxt = newg_make( MPPARM(globals->cGlobals.params
|
||||
->util->mpool)
|
||||
state.gi = gi;
|
||||
state.newGameCtxt = newg_make( MPPARM(globals->cGlobals.util->mpool)
|
||||
isNewGame,
|
||||
globals->cGlobals.params->util,
|
||||
globals->cGlobals.util,
|
||||
gtk_newgame_col_enable,
|
||||
gtk_newgame_attr_enable,
|
||||
gtk_newgame_col_get,
|
||||
|
@ -542,22 +568,25 @@ newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr, XP_Bool isNewGame,
|
|||
|
||||
state.revert = FALSE;
|
||||
state.loaded = XP_FALSE;
|
||||
state.nCols = globals->cGlobals.params->gi.boardSize;
|
||||
state.role = globals->cGlobals.params->gi.serverRole;
|
||||
state.nCols = gi->boardSize;
|
||||
if ( 0 == state.nCols ) {
|
||||
state.nCols = globals->cGlobals.params->pgi.boardSize;
|
||||
}
|
||||
state.role = gi->serverRole;
|
||||
|
||||
XP_MEMCPY( &state.addr, addr, sizeof(state.addr) );
|
||||
|
||||
dialog = makeNewGameDialog( &state );
|
||||
|
||||
newg_load( state.newGameCtxt,
|
||||
&globals->cGlobals.params->gi );
|
||||
newg_load( state.newGameCtxt, gi );
|
||||
state.loaded = XP_TRUE;
|
||||
|
||||
gtk_main();
|
||||
if ( !state.cancelled && !state.revert ) {
|
||||
if ( newg_store( state.newGameCtxt, &globals->cGlobals.params->gi,
|
||||
XP_TRUE ) ) {
|
||||
globals->cGlobals.params->gi.boardSize = state.nCols;
|
||||
if ( newg_store( state.newGameCtxt, gi, XP_TRUE ) ) {
|
||||
gi->boardSize = state.nCols;
|
||||
replaceStringIfDifferent( globals->cGlobals.util->mpool,
|
||||
&gi->dictName, state.dict );
|
||||
} else {
|
||||
/* Do it again if we warned user of inconsistency. */
|
||||
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.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -24,10 +24,11 @@
|
|||
#ifndef _GTKNEWGAME_H_
|
||||
#define _GTKNEWGAME_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
gboolean newGameDialog( GtkAppGlobals* globals, CommsAddrRec* addr,
|
||||
XP_Bool isNewGame, XP_Bool fireConnDlg );
|
||||
gboolean newGameDialog( GtkGameGlobals* globals, CurGameInfo* gi,
|
||||
CommsAddrRec* addr, XP_Bool isNewGame,
|
||||
XP_Bool fireConnDlg );
|
||||
|
||||
#endif /* _GTKNEWGAME_H_ */
|
||||
#endif /* PLATFORM_GTK */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef _GTKNTILESASK_H_
|
||||
#define _GTKNTILESASK_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
XP_U16 askNTiles( XP_U16 nTilesMax, XP_U16 deflt );
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#ifndef _GTKUTILS_H_
|
||||
#define _GTKUTILS_H_
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkboard.h"
|
||||
|
||||
GtkWidget* makeButton( char* text, GCallback func, gpointer data );
|
||||
GtkWidget* makeLabeledField( const char* labelText, GtkWidget** field );
|
||||
|
|
|
@ -360,7 +360,7 @@ linux_bt_open( CommonGlobals* globals, XP_Bool amMaster )
|
|||
LinBtStuff* btStuff = globals->btStuff;
|
||||
if ( !btStuff ) {
|
||||
btStuff = globals->btStuff
|
||||
= lbt_make( MPPARM(globals->params->util->mpool) amMaster );
|
||||
= lbt_make( MPPARM(globals->util->mpool) amMaster );
|
||||
btStuff->globals = globals;
|
||||
btStuff->socket = -1;
|
||||
|
||||
|
@ -413,7 +413,7 @@ linux_bt_close( CommonGlobals* globals )
|
|||
(void)close( btStuff->socket );
|
||||
}
|
||||
|
||||
XP_FREE( globals->params->util->mpool, btStuff );
|
||||
XP_FREE( globals->util->mpool, btStuff );
|
||||
globals->btStuff = NULL;
|
||||
}
|
||||
} /* 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,
|
||||
unsigned char* bufPtr, XP_U16 nBytes );
|
||||
const unsigned char* bufPtr, XP_U16 nBytes );
|
||||
XP_UCHAR* strFromStream( XWStreamCtxt* stream );
|
||||
|
||||
void catGameHistory( CommonGlobals* cGlobals );
|
||||
|
@ -73,8 +73,6 @@ XP_Bool getDictPath( const LaunchParams *params, const char* name,
|
|||
GSList* listDicts( const LaunchParams *params );
|
||||
void saveGame( CommonGlobals* cGlobals );
|
||||
|
||||
int blocking_read( int fd, unsigned char* buf, int len );
|
||||
|
||||
void linux_close_socket( CommonGlobals* cGlobals );
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
|
@ -94,4 +92,23 @@ void setOneSecondTimer( CommonGlobals* cGlobals );
|
|||
# define setOneSecondTimer( cGlobals )
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
* reserved.
|
||||
|
@ -93,7 +93,7 @@ linux_sms_init( CommonGlobals* globals, const CommsAddrRec* addr )
|
|||
{
|
||||
LinSMSData* data = globals->smsData;
|
||||
if ( !data ) {
|
||||
data = XP_MALLOC( globals->params->util->mpool, sizeof(*data) );
|
||||
data = XP_MALLOC( globals->util->mpool, sizeof(*data) );
|
||||
XP_ASSERT( !!data );
|
||||
XP_MEMSET( data, 0, sizeof(*data) );
|
||||
globals->smsData = data;
|
||||
|
@ -125,7 +125,7 @@ linux_sms_close( CommonGlobals* globals )
|
|||
{
|
||||
LinSMSData* data = globals->smsData;
|
||||
if ( !!data ) {
|
||||
XP_FREE( globals->params->util->mpool, data );
|
||||
XP_FREE( globals->util->mpool, data );
|
||||
globals->smsData = NULL;
|
||||
}
|
||||
} /* linux_sms_close */
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include "linuxutl.h"
|
||||
#include "main.h"
|
||||
#include "linuxdict.h"
|
||||
#include "linuxmain.h"
|
||||
#include "LocalizedStrIncludes.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -148,7 +150,7 @@ setSquareBonuses( const CommonGlobals* cGlobals )
|
|||
{
|
||||
XP_U16 nBonuses;
|
||||
XWBonusType* bonuses =
|
||||
bonusesFor( cGlobals->params->gi.boardSize, &nBonuses );
|
||||
bonusesFor( cGlobals->gi->boardSize, &nBonuses );
|
||||
if ( !!bonuses ) {
|
||||
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*
|
||||
linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ )
|
||||
{
|
||||
XP_UCHAR* result;
|
||||
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||
if ( !!cGlobals->params->rDevID ) {
|
||||
*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;
|
||||
return linux_getDevID( cGlobals->params, typ );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -390,6 +381,9 @@ linux_util_deviceRegistered( XW_UtilCtxt* uc, DevIDType typ,
|
|||
void
|
||||
linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
|
||||
{
|
||||
#ifdef MEM_DEBUG
|
||||
util->mpool = mpool;
|
||||
#endif
|
||||
util->vtable = XP_MALLOC( mpool, sizeof(UtilVtable) );
|
||||
|
||||
util->vtable->m_util_makeEmptyDict = linux_util_makeEmptyDict;
|
||||
|
@ -611,7 +605,7 @@ writeNoConnMsgs( CommonGlobals* cGlobals, int fd )
|
|||
XP_ASSERT( 0 < nMsgs );
|
||||
|
||||
XWStreamCtxt* stream =
|
||||
mem_stream_make( MPPARM(cGlobals->params->util->mpool)
|
||||
mem_stream_make( MPPARM(cGlobals->util->mpool)
|
||||
cGlobals->params->vtMgr,
|
||||
cGlobals, CHANNEL_NONE, NULL );
|
||||
stream_putU16( stream, 1 ); /* number of relayIDs */
|
||||
|
|
|
@ -32,9 +32,6 @@ void linux_debugf(const char*, ...)
|
|||
__attribute__ ((format (printf, 1, 2)));
|
||||
#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_destroy( XW_UtilCtxt* util );
|
||||
|
@ -49,6 +46,7 @@ XP_Bool storeNoConnMsg( CommonGlobals* cGlobals, const XP_U8* msg, XP_U16 len,
|
|||
const XP_UCHAR* relayID );
|
||||
void writeNoConnMsgs( CommonGlobals* cGlobals, int fd );
|
||||
|
||||
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
void setSquareBonuses( const CommonGlobals* cGlobals );
|
||||
#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.
|
||||
*
|
||||
* 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 */
|
||||
#endif
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "comtypes.h"
|
||||
#include "util.h"
|
||||
#include "game.h"
|
||||
|
@ -42,26 +44,33 @@ typedef struct LinuxUtilCtxt {
|
|||
UtilVtable* vtable;
|
||||
} LinuxUtilCtxt;
|
||||
|
||||
typedef void (*SockReceiver)( void* closure, int socket );
|
||||
typedef void (*NewSocketProc)( void* closure, int newSock, int oldSock,
|
||||
SockReceiver proc, void* procClosure );
|
||||
|
||||
typedef struct LaunchParams {
|
||||
/* CommPipeCtxt* pipe; */
|
||||
XW_UtilCtxt* util;
|
||||
DictionaryCtxt* dict;
|
||||
CurGameInfo gi;
|
||||
PlayerDicts dicts;
|
||||
CurGameInfo pgi;
|
||||
|
||||
GSList* dictDirs;
|
||||
char* fileName;
|
||||
char* dbName;
|
||||
sqlite3* pDb; /* null unless opened */
|
||||
XP_U16 saveFailPct;
|
||||
const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS];
|
||||
#ifdef USE_SQLITE
|
||||
char* dbFileName;
|
||||
XP_U32 dbFileID;
|
||||
#endif
|
||||
void* relayConStorage; /* opaque outside of relaycon.c */
|
||||
char* pipe;
|
||||
char* nbs;
|
||||
char* bonusFile;
|
||||
#ifdef XWFEATURE_DEVID
|
||||
char* devID;
|
||||
char* rDevID;
|
||||
XP_Bool noAnonDevid;
|
||||
XP_UCHAR devIDStore[16];
|
||||
#endif
|
||||
VTableMgr* vtMgr;
|
||||
XP_U16 nLocalPlayers;
|
||||
|
@ -140,7 +149,7 @@ typedef struct LaunchParams {
|
|||
ServerInfo serverInfo;
|
||||
ClientInfo clientInfo;
|
||||
} info;
|
||||
|
||||
MPSLOT
|
||||
} LaunchParams;
|
||||
|
||||
typedef struct CommonGlobals CommonGlobals;
|
||||
|
@ -165,17 +174,29 @@ typedef struct _TimerInfo {
|
|||
#endif
|
||||
} TimerInfo;
|
||||
|
||||
typedef void (*OnSaveFunc)( void* closure, sqlite3_int64 rowid,
|
||||
XP_Bool firstTime );
|
||||
|
||||
struct CommonGlobals {
|
||||
LaunchParams* params;
|
||||
CommonPrefs cp;
|
||||
XW_UtilCtxt* util;
|
||||
|
||||
XWGame game;
|
||||
CurGameInfo* gi;
|
||||
CommsAddrRec addr;
|
||||
DictionaryCtxt* dict;
|
||||
PlayerDicts dicts;
|
||||
XP_U16 lastNTilesToUse;
|
||||
XP_U16 lastStreamSize;
|
||||
XP_Bool manualFinal; /* use asked for final scores */
|
||||
sqlite3* pDb;
|
||||
sqlite3_int64 selRow;
|
||||
|
||||
SocketChangedFunc socketChanged;
|
||||
void* socketChangedClosure;
|
||||
OnSaveFunc onSave;
|
||||
void* onSaveClosure;
|
||||
GSList* packetQueue;
|
||||
XP_U32 nextPacketID; /* for debugging */
|
||||
|
||||
|
@ -210,4 +231,24 @@ struct CommonGlobals {
|
|||
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
|
||||
|
|
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=""
|
||||
APP_NEW_PARAMS=""
|
||||
NGAMES=""
|
||||
UDP_PCT=0
|
||||
UPGRADE_ODDS=""
|
||||
NROOMS=""
|
||||
HOST=""
|
||||
|
@ -188,7 +189,13 @@ build_cmds() {
|
|||
DEV=0
|
||||
for NLOCALS in ${LOCALS[@]}; do
|
||||
DEV=$((DEV + 1))
|
||||
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 # clear the log
|
||||
|
||||
|
@ -209,10 +216,15 @@ build_cmds() {
|
|||
PARAMS="$PARAMS $BOARD_SIZE --room $ROOM --trade-pct 20 --sort-tiles "
|
||||
[ $UNDO_PCT -gt 0 ] && PARAMS="$PARAMS --undo-pct $UNDO_PCT "
|
||||
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 --split-packets 2"
|
||||
if [ -n $SEND_CHAT ]; then
|
||||
if [ -n "$SEND_CHAT" ]; then
|
||||
PARAMS="$PARAMS --send-chat $SEND_CHAT"
|
||||
fi
|
||||
# PARAMS="$PARAMS --savefail-pct 10"
|
||||
|
@ -316,7 +328,7 @@ kill_from_log() {
|
|||
if [ -n "$RELAYID" ]; then
|
||||
OBITS="$OBITS -d $RELAYID"
|
||||
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=""
|
||||
fi
|
||||
return 0 # success
|
||||
|
@ -332,7 +344,7 @@ maybe_resign() {
|
|||
if grep -q XWRELAY_ALLHERE $LOG; then
|
||||
if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then
|
||||
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
|
||||
|
@ -380,18 +392,18 @@ check_game() {
|
|||
# kill_from_logs $OTHERS $KEY
|
||||
for ID in $OTHERS $KEY; do
|
||||
echo -n "${LOGS[$ID]}, "
|
||||
kill_from_log ${LOGS[$ID]} || true
|
||||
kill_from_log ${LOGS[$ID]} || /bin/true
|
||||
close_device $ID $DONEDIR "game over"
|
||||
done
|
||||
echo ""
|
||||
# XWRELAY_ERROR_DELETED may be old
|
||||
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
|
||||
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"
|
||||
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then
|
||||
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"
|
||||
else
|
||||
maybe_resign $KEY
|
||||
|
@ -423,7 +435,7 @@ get_relayid() {
|
|||
|
||||
update_devid_cmd() {
|
||||
KEY=$1
|
||||
HELP="$(${APPS[$KEY]} --help 2>&1 || true)"
|
||||
HELP="$(${APPS[$KEY]} --help 2>&1 || /bin/true)"
|
||||
if echo $HELP | grep -q '\-\-devid'; then
|
||||
CMD="--devid LINUX_TEST_$(printf %.5d ${KEY})"
|
||||
LOG=${LOGS[$KEY]}
|
||||
|
@ -467,7 +479,8 @@ run_cmds() {
|
|||
try_upgrade $KEY
|
||||
launch $KEY &
|
||||
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
|
||||
ROOM_PIDS[$ROOM]=$PID
|
||||
MINEND[$KEY]=$(($NOW + $MINRUN))
|
||||
|
@ -476,7 +489,7 @@ run_cmds() {
|
|||
if [ -d /proc/$PID ]; then
|
||||
SLEEP=$((${MINEND[$KEY]} - $NOW))
|
||||
[ $SLEEP -gt 0 ] && sleep $SLEEP
|
||||
kill $PID || true
|
||||
kill $PID || /bin/true
|
||||
wait $PID
|
||||
fi
|
||||
PIDS[$KEY]=0
|
||||
|
@ -487,7 +500,7 @@ run_cmds() {
|
|||
fi
|
||||
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
|
||||
if [ $COUNT -gt 0 ]; then
|
||||
|
@ -528,7 +541,7 @@ run_via_rq() {
|
|||
launch $KEY &
|
||||
PID=$!
|
||||
sleep 2
|
||||
kill $PID || true
|
||||
kill $PID || /bin/true
|
||||
wait $PID
|
||||
fi
|
||||
[ "$DROP_N" -ge 0 ] && increment_drop $KEY
|
||||
|
@ -544,6 +557,7 @@ function getArg() {
|
|||
function usage() {
|
||||
[ $# -gt 0 ] && echo "Error: $1" >&2
|
||||
echo "Usage: $(basename $0) \\" >&2
|
||||
echo " [--via-udp <pct>] \\" >&2
|
||||
echo " [--clean-start] \\" >&2
|
||||
echo " [--game-dict <path/to/dict>]* \\" >&2
|
||||
echo " [--old-app <path/to/app]* \\" >&2
|
||||
|
@ -571,6 +585,10 @@ function usage() {
|
|||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case $1 in
|
||||
--via-udp)
|
||||
UDP_PCT=$(getArg $*)
|
||||
shift
|
||||
;;
|
||||
--clean-start)
|
||||
DO_CLEAN=1
|
||||
;;
|
||||
|
|
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
|
|
@ -1092,7 +1092,7 @@ handleProxyMsgs( int sock, const AddrInfo* addr, const unsigned char* bufp,
|
|||
unsigned short nMsgs;
|
||||
if ( getNetShort( &bufp, end, &nMsgs ) ) {
|
||||
SafeCref scr( connName );
|
||||
while ( nMsgs-- > 0 ) {
|
||||
while ( scr.IsValid() && nMsgs-- > 0 ) {
|
||||
unsigned short len;
|
||||
if ( getNetShort( &bufp, end, &len ) ) {
|
||||
if ( handlePutMessage( scr, hid, addr, len, &bufp, end ) ) {
|
||||
|
|
Loading…
Reference in a new issue