mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-06 20:45:54 +01:00
Merge branch 'android_branch' into android_gcm
Conflicts: xwords4/android/XWords4/res/values/common_rsrc.xml
This commit is contained in:
commit
c93dfd6605
33 changed files with 416 additions and 135 deletions
|
@ -22,7 +22,7 @@
|
|||
to come from a domain that you own or have control over. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.eehouse.android.xw4"
|
||||
android:versionCode="44"
|
||||
android:versionCode="45"
|
||||
android:versionName="@string/app_version"
|
||||
>
|
||||
|
||||
|
|
|
@ -64,6 +64,49 @@
|
|||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- networked game -->
|
||||
<TextView style="@style/config_separator"
|
||||
android:layout_marginTop="10dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/newgame_networked_header"
|
||||
/>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginBottom="10dip"
|
||||
>
|
||||
<ImageView android:src="@drawable/relaygame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
/>
|
||||
<TextView android:text="@string/newgame_networked_desc"
|
||||
style="@style/relay_explain"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<Button android:id="@+id/newgame_invite"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/newgame_invite"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/newgame_net_config"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/newgame_net_config"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- SMS game -->
|
||||
<TextView android:id="@+id/sms_separator"
|
||||
style="@style/config_separator"
|
||||
|
@ -132,49 +175,6 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- networked game -->
|
||||
<TextView style="@style/config_separator"
|
||||
android:layout_marginTop="10dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="@string/newgame_networked_header"
|
||||
/>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginBottom="10dip"
|
||||
>
|
||||
<ImageView android:src="@drawable/relaygame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
/>
|
||||
<TextView android:text="@string/newgame_networked_desc"
|
||||
style="@style/relay_explain"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<Button android:id="@+id/newgame_invite"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/newgame_invite"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/newgame_net_config"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/newgame_net_config"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Bluetooth -->
|
||||
<TextView android:id="@+id/bt_separator"
|
||||
style="@style/config_separator"
|
||||
|
|
|
@ -5,16 +5,34 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<b>Crosswords 4.4 beta 52 release</b>
|
||||
<b>Crosswords 4.4 beta 53 release</b>
|
||||
<ul>
|
||||
<li>Remember wordlist browser position, word size, etc.</li>
|
||||
|
||||
<li>Fix wordlist browser bugs for languages with more than one
|
||||
letter on a tile</li>
|
||||
<li>Add a second way devices can play: via SMS. If you and your
|
||||
friends have unlimited texting plans (ONLY IF!!) this is the way to
|
||||
go: connecting is easier, moves get transmitted more quickly, and
|
||||
less battery is required. <a
|
||||
href="http://xwords.sf.net/and_faq.php">See the FAQ</a></li>
|
||||
|
||||
<li>New word lookup URLs for Catalan language lists</li>
|
||||
<li>In the main games-list screen, replace green highlighting of the
|
||||
player whose turn it is with green transitioning to red over three
|
||||
days. That way you can see how long it's been that person's turn.
|
||||
Nothing happens -- yet -- when the three days is up. Maybe later
|
||||
that'll force a resignation.</li>
|
||||
|
||||
<li>Display wordlist comment if present</li>
|
||||
<li>Download wordlists without using the browser when possible</li>
|
||||
|
||||
<li>Warn when you join a network game with a different wordlist from
|
||||
the host's, and give a chance to download and switch.</li>
|
||||
|
||||
<li>Don't allow networked games to have different wordlist for each
|
||||
player. That feature is for local games only now.</li>
|
||||
|
||||
<li>There's now a preference for where downloaded wordlists are
|
||||
stored instead of a question asked each time.</li>
|
||||
|
||||
<li>Recast game-over feature as "resigning".</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>Please remember that this is beta software. Please let me know (at
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<string name="app_version">4.4 beta 52</string>
|
||||
<string name="app_version">4.4 beta 53</string>
|
||||
</resources>
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
<string name="key_connstat_data">key_connstat_data</string>
|
||||
<string name="key_dev_id">key_dev_id</string>
|
||||
<string name="key_gcm_regid">key_gcm_regid</string>
|
||||
<string name="key_checked_sms">key_checked_sms</string>
|
||||
|
||||
<string name="key_notagain_sync">key_notagain_sync</string>
|
||||
<string name="key_notagain_chat">key_notagain_chat</string>
|
||||
|
|
|
@ -1786,8 +1786,9 @@
|
|||
|
||||
<!-- Another paragraph in the about dialog -->
|
||||
<string name="about_web">For a manual or sourcecode see:
|
||||
http://xwords.sf.net. To report bugs, suggest features, offer to
|
||||
help, etc., please email: xwords@eehouse.org.</string>
|
||||
http://xwords.sf.net/android.php. To report bugs, suggest
|
||||
features, offer to help, etc., please email:
|
||||
xwords@eehouse.org.</string>
|
||||
|
||||
<!-- Empty in English, this should contain the name of the
|
||||
translator/creator of the strings.xml file for this
|
||||
|
@ -2074,7 +2075,7 @@
|
|||
phones with unlimited texting plans. Once you enable it dozens of
|
||||
SMS (text) messages will be sent (invisibly) for each game
|
||||
played. If you don\'t have an unlimited plan your carrier may
|
||||
charge you for each and every one!\n\nShould play via SMS be
|
||||
charge you for each and every message!\n\nShould play via SMS be
|
||||
enabled?</string>
|
||||
<!-- -->
|
||||
<string name="confirm_sms_prompt">Enable play via SMS?</string>
|
||||
|
@ -2140,4 +2141,5 @@
|
|||
<string name="default_loc">Store wordlists internally</string>
|
||||
<string name="default_loc_summary">(Not in external/sdcard memory)</string>
|
||||
|
||||
<string name="sms_searching_toast">Searching SMS messages...</string>
|
||||
</resources>
|
||||
|
|
|
@ -101,6 +101,7 @@ public class BoardActivity extends XWActivity
|
|||
private static final int VALUES_ACTION = 16;
|
||||
private static final int BT_PICK_ACTION = 17;
|
||||
private static final int SMS_PICK_ACTION = 18;
|
||||
private static final int SMS_CONFIG_ACTION = 19;
|
||||
|
||||
private static final String DLG_TITLE = "DLG_TITLE";
|
||||
private static final String DLG_TITLESTR = "DLG_TITLESTR";
|
||||
|
@ -787,7 +788,7 @@ public class BoardActivity extends XWActivity
|
|||
|
||||
case R.id.board_menu_file_prefs:
|
||||
m_firingPrefs = true;
|
||||
startActivity( new Intent( this, PrefsActivity.class ) );
|
||||
Utils.launchSettings( this );
|
||||
break;
|
||||
|
||||
case R.id.board_menu_file_about:
|
||||
|
@ -836,6 +837,10 @@ public class BoardActivity extends XWActivity
|
|||
GameUtils.launchSMSInviter( this, m_nMissingPlayers,
|
||||
SMS_INVITE_RESULT );
|
||||
break;
|
||||
case SMS_CONFIG_ACTION:
|
||||
Utils.launchSettings( this );
|
||||
break;
|
||||
|
||||
case COMMIT_ACTION:
|
||||
cmd = JNICmd.CMD_COMMIT;
|
||||
break;
|
||||
|
@ -1904,7 +1909,9 @@ public class BoardActivity extends XWActivity
|
|||
switch( m_connType ) {
|
||||
case COMMS_CONN_SMS:
|
||||
if ( XWApp.SMSSUPPORTED && !XWPrefs.getSMSEnabled( this ) ) {
|
||||
showOKOnlyDialog( R.string.warn_sms_disabled );
|
||||
showConfirmThen( R.string.warn_sms_disabled,
|
||||
R.string.newgame_enable_sms,
|
||||
SMS_CONFIG_ACTION );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -404,7 +404,7 @@ public class GameUtils {
|
|||
|
||||
public static long saveNew( Context context, CurGameInfo gi )
|
||||
{
|
||||
long rowid = -1;
|
||||
long rowid = DBUtils.ROWID_NOTFOUND;
|
||||
byte[] bytes = XwJNI.gi_to_stream( gi );
|
||||
if ( null != bytes ) {
|
||||
GameLock lock = DBUtils.saveNewGame( context, bytes );
|
||||
|
@ -438,9 +438,11 @@ public class GameUtils {
|
|||
Assert.assertTrue( gi.nPlayers == nPlayersT );
|
||||
rowid = saveNew( context, gi );
|
||||
|
||||
GameLock lock = new GameLock( rowid, true ).lock();
|
||||
applyChanges( context, gi, addr, inviteID, lock, false );
|
||||
lock.unlock();
|
||||
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
|
||||
GameLock lock = new GameLock( rowid, true ).lock();
|
||||
applyChanges( context, gi, addr, inviteID, lock, false );
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return rowid;
|
||||
}
|
||||
|
|
|
@ -587,8 +587,7 @@ public class GamesList extends XWListActivity
|
|||
break;
|
||||
|
||||
case R.id.gamel_menu_prefs:
|
||||
intent = new Intent( this, PrefsActivity.class );
|
||||
startActivity( intent );
|
||||
Utils.launchSettings( this );
|
||||
break;
|
||||
|
||||
case R.id.gamel_menu_about:
|
||||
|
|
|
@ -39,6 +39,7 @@ public class PrefsActivity extends PreferenceActivity
|
|||
|
||||
private String m_keyLogging;
|
||||
private String m_smsToasting;
|
||||
private String m_smsEnable;
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog( int id )
|
||||
|
@ -118,6 +119,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 );
|
||||
|
||||
Button button = (Button)findViewById( R.id.revert_colors );
|
||||
button.setOnClickListener( new View.OnClickListener() {
|
||||
|
@ -156,6 +158,12 @@ 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_smsEnable ) ) {
|
||||
if ( sp.getBoolean( key, true ) ) {
|
||||
SMSService.checkForInvites( this );
|
||||
} else {
|
||||
XWPrefs.setHaveCheckedSMS( this, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +174,7 @@ public class PrefsActivity extends PreferenceActivity
|
|||
|
||||
// Now replace this activity with a new copy
|
||||
// so the new values get loaded.
|
||||
startActivity( new Intent( this, PrefsActivity.class ) );
|
||||
Utils.launchSettings( this );
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.app.Activity;
|
|||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
@ -76,7 +77,6 @@ public class SMSService extends Service {
|
|||
|
||||
private static Boolean s_showToasts = null;
|
||||
private static MultiService s_srcMgr = null;
|
||||
private static boolean s_dbCheckPending = true;
|
||||
|
||||
// All messages are base64-encoded byte arrays. The first byte is
|
||||
// always one of these. What follows depends.
|
||||
|
@ -101,7 +101,8 @@ public class SMSService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
public static void handleFrom( Context context, String buffer, String phone )
|
||||
public static void handleFrom( Context context, String buffer,
|
||||
String phone )
|
||||
{
|
||||
Intent intent = getIntentTo( context, HANDLE );
|
||||
intent.putExtra( BUFFER, buffer );
|
||||
|
@ -230,15 +231,14 @@ public class SMSService extends Service {
|
|||
int cmd = intent.getIntExtra( CMD_STR, -1 );
|
||||
switch( cmd ) {
|
||||
case CHECK_MSGDB:
|
||||
if ( s_dbCheckPending ) {
|
||||
if ( Utils.firstBootEver( this ) ) {
|
||||
new Thread( new Runnable() {
|
||||
if ( ! XWPrefs.getHaveCheckedSMS( this ) ) {
|
||||
Utils.showToast( this, R.string.sms_searching_toast );
|
||||
XWPrefs.setHaveCheckedSMS( this, true );
|
||||
new Thread( new Runnable() {
|
||||
public void run() {
|
||||
checkMsgDB();
|
||||
}
|
||||
} ).start();
|
||||
}
|
||||
s_dbCheckPending = false;
|
||||
}
|
||||
break;
|
||||
case HANDLE:
|
||||
|
@ -288,7 +288,7 @@ public class SMSService extends Service {
|
|||
result = Service.START_STICKY_COMPATIBILITY;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // onStartCommand
|
||||
|
||||
@Override
|
||||
public IBinder onBind( Intent intent )
|
||||
|
@ -632,25 +632,27 @@ public class SMSService extends Service {
|
|||
private void checkMsgDB()
|
||||
{
|
||||
Uri uri = Uri.parse( "content://sms/inbox" );
|
||||
ContentResolver resolver = getContentResolver();
|
||||
String[] columns = new String[] { "body","address" };
|
||||
Cursor cursor = getContentResolver().query( uri, columns,
|
||||
null, null, null );
|
||||
try {
|
||||
int bodyIndex = cursor.getColumnIndexOrThrow( "body" );
|
||||
int phoneIndex = cursor.getColumnIndexOrThrow( "address" );
|
||||
while ( cursor.moveToNext() ) {
|
||||
String msg = fromPublicFmt( cursor.getString( bodyIndex ) );
|
||||
if ( null != msg ) {
|
||||
String number = cursor.getString( phoneIndex );
|
||||
if ( null != number ) {
|
||||
handleFrom( this, msg, number );
|
||||
Cursor cursor = resolver.query( uri, columns, null, null, null );
|
||||
if ( 0 < cursor.getCount() ) {
|
||||
try {
|
||||
int bodyIndex = cursor.getColumnIndexOrThrow( "body" );
|
||||
int phoneIndex = cursor.getColumnIndexOrThrow( "address" );
|
||||
while ( cursor.moveToNext() ) {
|
||||
String msg = fromPublicFmt( cursor.getString( bodyIndex ) );
|
||||
if ( null != msg ) {
|
||||
String number = cursor.getString( phoneIndex );
|
||||
if ( null != number ) {
|
||||
handleFrom( this, msg, number );
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( Exception ee ) {
|
||||
DbgUtils.loge( ee );
|
||||
}
|
||||
cursor.close();
|
||||
} catch ( Exception ee ) {
|
||||
DbgUtils.loge( ee );
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
private void sendResult( MultiEvent event, Object ... args )
|
||||
|
|
|
@ -153,6 +153,11 @@ public class XWActivity extends Activity
|
|||
m_delegate.showConfirmThen( msg, action );
|
||||
}
|
||||
|
||||
protected void showConfirmThen( int msg, int posButton, int action )
|
||||
{
|
||||
m_delegate.showConfirmThen( getString(msg), posButton, action );
|
||||
}
|
||||
|
||||
public void showEmailOrSMSThen( int action )
|
||||
{
|
||||
m_delegate.showEmailOrSMSThen( action );
|
||||
|
|
|
@ -204,6 +204,16 @@ public class XWPrefs {
|
|||
return getPrefsBoolean( context, R.string.key_default_loc, true );
|
||||
}
|
||||
|
||||
public static boolean getHaveCheckedSMS( Context context )
|
||||
{
|
||||
return getPrefsBoolean( context, R.string.key_checked_sms, false );
|
||||
}
|
||||
|
||||
public static void setHaveCheckedSMS( Context context, boolean newValue )
|
||||
{
|
||||
setPrefsBoolean( context, R.string.key_checked_sms, newValue );
|
||||
}
|
||||
|
||||
public static DictUtils.DictLoc getDefaultLoc( Context context )
|
||||
{
|
||||
boolean internal = getDefaultLocInternal( context );
|
||||
|
|
58
xwords4/android/scripts/a.py
Executable file
58
xwords4/android/scripts/a.py
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from mod_python import apache
|
||||
|
||||
def a(req):
|
||||
return """
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/xw4mobile.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
|
||||
<title>What gibberish is my friend sending me?</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>Gibberish Text explained</h3>
|
||||
|
||||
<p>You probably reached this page because a friend sent you a text
|
||||
message with this URL and a bunch of gibberish.</p>
|
||||
|
||||
<p>Well, that gibberish was meant for an Android app called
|
||||
<a href="http://xwords.sf.net/android.php">Crosswords</a>, and your
|
||||
friend hoped you had it installed and would want to play. If you
|
||||
like,
|
||||
|
||||
<span style="color:red">
|
||||
AND YOU HAVE AN UNLIMITED TEXT MESSAGING PLAN,
|
||||
</span>
|
||||
|
||||
you can download it via the button below. It's free (costs you neither
|
||||
money nor time with annoying advertising) and open-source -- and
|
||||
besides, your friend is recommending it. :-)</p>
|
||||
|
||||
<div>
|
||||
<form method="get" action="http://eehouse.org/market_redir.php">
|
||||
<input type="submit" value="Install Crosswords via Google Play"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p>(If you don't have access to the Google Play store from your
|
||||
device you can
|
||||
instead <a href="http://eehouse.org/sms_latest.apk">download
|
||||
Crosswords directly</a>.)
|
||||
</p>
|
||||
|
||||
<p style="color:red"> Do not play Crosswords via SMS unless you
|
||||
have an unlimited Text Messaging plan with your cellular carrier.
|
||||
When communicating via SMS Crosswords can send and receive 50-100
|
||||
messages in the course of a single game. If each one costs you 25 or
|
||||
50 cents -- well, do the math.</p>
|
||||
|
||||
<p>If you don't have an unlimited texting plan, you can
|
||||
still <a href="http://eehouse.org/market_redir.php">install
|
||||
Crosswords</a> and play with your friend over the internet. Just
|
||||
don't enable the SMS feature. (And don't worry: that's impossible
|
||||
to do accidentally.)</p>
|
||||
|
||||
</body> </html>
|
||||
"""
|
|
@ -185,6 +185,11 @@ static XP_Bool sendNoConn( CommsCtxt* comms,
|
|||
const MsgQueueElem* elem, XWHostID destID );
|
||||
static XWHostID getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo );
|
||||
static void set_reset_timer( CommsCtxt* comms );
|
||||
# ifdef XWFEATURE_DEVID
|
||||
static void putDevID( const CommsCtxt* comms, XWStreamCtxt* stream );
|
||||
# else
|
||||
# define putDevID( comms, stream )
|
||||
# endif
|
||||
# ifdef DEBUG
|
||||
static const char* relayCmdToStr( XWRELAY_Cmd cmd );
|
||||
# endif
|
||||
|
@ -2120,6 +2125,7 @@ msg_to_stream( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
|||
stream_putU8( stream, comms->r.nPlayersTotal );
|
||||
stream_putU16( stream, comms_getChannelSeed(comms) );
|
||||
stream_putU8( stream, comms->util->gameInfo->dictLang );
|
||||
putDevID( comms, stream );
|
||||
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||
break;
|
||||
|
||||
|
@ -2292,6 +2298,27 @@ relayDisconnect( CommsCtxt* comms )
|
|||
set_relay_state( comms, COMMS_RELAYSTATE_UNCONNECTED );
|
||||
}
|
||||
} /* relayDisconnect */
|
||||
|
||||
#ifdef XWFEATURE_DEVID
|
||||
static void
|
||||
putDevID( const CommsCtxt* comms, XWStreamCtxt* stream )
|
||||
{
|
||||
# if XWRELAY_PROTO_VERSION >= XWRELAY_PROTO_VERSION_CLIENTID
|
||||
DevIDType typ;
|
||||
const XP_UCHAR* devID = util_getDevID( comms->util, &typ );
|
||||
stream_putU8( stream, typ );
|
||||
if ( ID_TYPE_NONE != typ ) {
|
||||
stream_catString( stream, devID );
|
||||
stream_putU8( stream, '\0' );
|
||||
}
|
||||
# else
|
||||
XP_ASSERT(0);
|
||||
XP_USE(comms);
|
||||
XP_USE(stream);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
|
|
@ -55,6 +55,12 @@ typedef enum {
|
|||
, COMMS_RELAYSTATE_ALLCONNECTED
|
||||
} CommsRelayState;
|
||||
|
||||
typedef enum {
|
||||
ID_TYPE_NONE
|
||||
,ID_TYPE_LINUX
|
||||
,ID_TYPE_ANDROID_GCM
|
||||
} DevIDType;
|
||||
|
||||
#ifdef XWFEATURE_BLUETOOTH
|
||||
# define XW_BT_UUID "7be0d084-ff89-4d6d-9c78-594773a6f963"
|
||||
|
||||
|
|
|
@ -1384,6 +1384,9 @@ server_sendInitialMessage( ServerCtxt* server )
|
|||
XP_U16 nPlayers = server->vol.gi->nPlayers;
|
||||
CurGameInfo localGI;
|
||||
XP_U32 gameID = server->vol.gi->gameID;
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
XP_U8 streamVersion = server->nv.streamVersion;
|
||||
#endif
|
||||
|
||||
XP_ASSERT( server->nv.nDevices > 1 );
|
||||
for ( deviceIndex = 1; deviceIndex < server->nv.nDevices;
|
||||
|
@ -1397,8 +1400,8 @@ server_sendInitialMessage( ServerCtxt* server )
|
|||
writeProto( server, stream, XWPROTO_CLIENT_SETUP );
|
||||
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
XP_ASSERT( 0 < server->nv.streamVersion );
|
||||
stream_putU8( stream, server->nv.streamVersion );
|
||||
XP_ASSERT( 0 < streamVersion );
|
||||
stream_putU8( stream, streamVersion );
|
||||
#else
|
||||
stream_putU8( stream, CUR_STREAM_VERS );
|
||||
#endif
|
||||
|
@ -1411,7 +1414,7 @@ server_sendInitialMessage( ServerCtxt* server )
|
|||
|
||||
dict_writeToStream( dict, stream );
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
if ( STREAM_VERS_DICTNAME <= addr->streamVersion ) {
|
||||
if ( STREAM_VERS_DICTNAME <= streamVersion ) {
|
||||
stringToStream( stream, dict_getShortName(dict) );
|
||||
stringToStream( stream, dict_getMd5Sum(dict) );
|
||||
}
|
||||
|
@ -2429,6 +2432,7 @@ server_getLastMoveTime( const ServerCtxt* server )
|
|||
static void
|
||||
doEndGame( ServerCtxt* server, XP_S16 quitter )
|
||||
{
|
||||
XP_ASSERT( quitter < server->vol.gi->nPlayers );
|
||||
SETSTATE( server, XWSTATE_GAMEOVER );
|
||||
setTurn( server, -1 );
|
||||
server->nv.quitter = quitter;
|
||||
|
@ -2445,7 +2449,7 @@ putQuitter( const ServerCtxt* server, XWStreamCtxt* stream, XP_S16 quitter )
|
|||
}
|
||||
|
||||
static void
|
||||
getQuitter( const ServerCtxt* server, XWStreamCtxt* stream, XP_S16* quitter )
|
||||
getQuitter( const ServerCtxt* server, XWStreamCtxt* stream, XP_S8* quitter )
|
||||
{
|
||||
*quitter = STREAM_VERS_DICTNAME <= server->nv.streamVersion
|
||||
? stream_getU8( stream ) : -1;
|
||||
|
@ -2462,6 +2466,7 @@ static void
|
|||
endGameInternal( ServerCtxt* server, GameEndReason XP_UNUSED(why), XP_S16 quitter )
|
||||
{
|
||||
XP_ASSERT( server->nv.gameState != XWSTATE_GAMEOVER );
|
||||
XP_ASSERT( quitter < server->vol.gi->nPlayers );
|
||||
|
||||
if ( server->vol.gi->serverRole != SERVER_ISCLIENT ) {
|
||||
|
||||
|
@ -2756,7 +2761,7 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
|
|||
XP_FREE( server->mpool, msg );
|
||||
#endif
|
||||
} else if ( readStreamHeader( server, incoming ) ) {
|
||||
XP_S16 quitter;
|
||||
XP_S8 quitter;
|
||||
switch( code ) {
|
||||
/* case XWPROTO_MOVEMADE_INFO: */
|
||||
/* accepted = client_reflectMoveMade( server, incoming ); */
|
||||
|
|
|
@ -152,7 +152,9 @@ typedef struct UtilVtable {
|
|||
XP_Bool (*m_util_altKeyDown)( XW_UtilCtxt* uc );
|
||||
|
||||
XP_U32 (*m_util_getCurSeconds)( XW_UtilCtxt* uc );
|
||||
|
||||
#ifdef XWFEATURE_DEVID
|
||||
const XP_UCHAR* (*m_util_getDevID)( XW_UtilCtxt* uc, DevIDType* typ );
|
||||
#endif
|
||||
DictionaryCtxt* (*m_util_makeEmptyDict)( XW_UtilCtxt* uc );
|
||||
|
||||
const XP_UCHAR* (*m_util_getUserString)( XW_UtilCtxt* uc,
|
||||
|
@ -280,6 +282,11 @@ struct XW_UtilCtxt {
|
|||
#define util_getCurSeconds(uc) \
|
||||
(uc)->vtable->m_util_getCurSeconds((uc))
|
||||
|
||||
#ifdef XWFEATURE_DEVID
|
||||
# define util_getDevID( uc, t ) \
|
||||
(uc)->vtable->m_util_getDevID((uc),(t))
|
||||
#endif
|
||||
|
||||
#define util_makeEmptyDict( uc ) \
|
||||
(uc)->vtable->m_util_makeEmptyDict((uc))
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ DEFINES += -DXWFEATURE_BONUSALL
|
|||
DEFINES += -DXWFEATURE_HILITECELL
|
||||
# allow change dict inside running game
|
||||
DEFINES += -DXWFEATURE_CHANGEDICT
|
||||
# DEFINES += -DXWFEATURE_DEVID
|
||||
|
||||
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
||||
DEFINES += -DMAX_ROWS=32
|
||||
|
|
|
@ -216,6 +216,7 @@ void
|
|||
catFinalScores( const CommonGlobals* cGlobals, XP_S16 quitter )
|
||||
{
|
||||
XWStreamCtxt* stream;
|
||||
XP_ASSERT( quitter < cGlobals->params->gi.nPlayers );
|
||||
|
||||
stream = mem_stream_make( MPPARM(cGlobals->params->util->mpool)
|
||||
cGlobals->params->vtMgr,
|
||||
|
@ -502,6 +503,9 @@ typedef enum {
|
|||
,CMD_DICTDIR
|
||||
,CMD_PLAYERDICT
|
||||
,CMD_SEED
|
||||
#ifdef XWFEATURE_DEVID
|
||||
,CMD_DEVID
|
||||
#endif
|
||||
,CMD_GAMESEED
|
||||
,CMD_GAMEFILE
|
||||
,CMD_SAVEFAIL_PCT
|
||||
|
@ -595,6 +599,9 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
,{ CMD_DICTDIR, true, "dict-dir", "path to dir in which dicts will be sought" }
|
||||
,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" }
|
||||
,{ CMD_SEED, true, "seed", "random seed" }
|
||||
#ifdef XWFEATURE_DEVID
|
||||
,{ CMD_DEVID, true, "devid", "device ID (for testing GCM stuff)" }
|
||||
#endif
|
||||
,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" }
|
||||
,{ CMD_GAMEFILE, true, "file", "file to save to/read from" }
|
||||
,{ CMD_SAVEFAIL_PCT, true, "savefail-pct", "How often, at random, does save fail?" }
|
||||
|
@ -1584,6 +1591,9 @@ main( int argc, char** argv )
|
|||
mainParams.allowPeek = XP_TRUE;
|
||||
mainParams.showRobotScores = XP_FALSE;
|
||||
mainParams.useMmap = XP_TRUE;
|
||||
#ifdef XWFEATURE_DEVID
|
||||
mainParams.devID = "";
|
||||
#endif
|
||||
|
||||
char* envDictPath = getenv( "XW_DICTSPATH" );
|
||||
if ( !!envDictPath ) {
|
||||
|
@ -1669,6 +1679,11 @@ main( int argc, char** argv )
|
|||
case CMD_SEED:
|
||||
seed = atoi(optarg);
|
||||
break;
|
||||
#ifdef XWFEATURE_DEVID
|
||||
case CMD_DEVID:
|
||||
mainParams.devID = optarg;
|
||||
break;
|
||||
#endif
|
||||
case CMD_GAMESEED:
|
||||
mainParams.gameSeed = atoi(optarg);
|
||||
break;
|
||||
|
|
|
@ -344,6 +344,16 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code )
|
|||
}
|
||||
} /* linux_util_getUserString */
|
||||
|
||||
#ifdef XWFEATURE_DEVID
|
||||
static const XP_UCHAR*
|
||||
linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ )
|
||||
{
|
||||
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||
*typ = ID_TYPE_LINUX;
|
||||
return cGlobals->params->devID;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
|
||||
{
|
||||
|
@ -353,6 +363,9 @@ linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
|
|||
util->vtable->m_util_getSquareBonus = linux_util_getSquareBonus;
|
||||
util->vtable->m_util_getCurSeconds = linux_util_getCurSeconds;
|
||||
util->vtable->m_util_getUserString = linux_util_getUserString;
|
||||
#ifdef XWFEATURE_DEVID
|
||||
util->vtable->m_util_getDevID = linux_util_getDevID;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -59,6 +59,9 @@ typedef struct LaunchParams {
|
|||
char* pipe;
|
||||
char* nbs;
|
||||
char* bonusFile;
|
||||
#ifdef XWFEATURE_DEVID
|
||||
char* devID;
|
||||
#endif
|
||||
VTableMgr* vtMgr;
|
||||
XP_U16 nLocalPlayers;
|
||||
XP_U16 nHidden;
|
||||
|
|
|
@ -79,6 +79,9 @@ function pick_ndevs() {
|
|||
elif [ $RNUM -gt 75 -a $MAXDEVS -ge 3 ]; then
|
||||
NDEVS=3
|
||||
fi
|
||||
if [ -n "$MINDEVS" -a "$NDEVS" -lt "$MINDEVS" ]; then
|
||||
NDEVS=$MINDEVS
|
||||
fi
|
||||
echo $NDEVS
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,8 @@ CookieRef::Unlock() {
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::_Connect( int socket, int clientVersion, int nPlayersH, int nPlayersS, int seed,
|
||||
CookieRef::_Connect( int socket, int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS, int seed,
|
||||
bool seenSeed, in_addr& addr )
|
||||
{
|
||||
bool connected = false;
|
||||
|
@ -199,7 +200,8 @@ CookieRef::_Connect( int socket, int clientVersion, int nPlayersH, int nPlayersS
|
|||
if ( !connected ) {
|
||||
set<int> sockets = GetSockets();
|
||||
if ( sockets.end() == sockets.find( socket ) ) {
|
||||
pushConnectEvent( socket, clientVersion, nPlayersH, nPlayersS, seed, addr );
|
||||
pushConnectEvent( socket, clientVersion, devID, nPlayersH,
|
||||
nPlayersS, seed, addr );
|
||||
handleEvents();
|
||||
connected = HasSocket_locked( socket );
|
||||
} else {
|
||||
|
@ -210,8 +212,8 @@ CookieRef::_Connect( int socket, int clientVersion, int nPlayersH, int nPlayersS
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::_Reconnect( int socket, int clientVersion, HostID hid,
|
||||
int nPlayersH, int nPlayersS,
|
||||
CookieRef::_Reconnect( int socket, int clientVersion, DevID* devID,
|
||||
HostID hid, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr, bool gameDead )
|
||||
{
|
||||
bool spotTaken = false;
|
||||
|
@ -223,7 +225,8 @@ CookieRef::_Reconnect( int socket, int clientVersion, HostID hid,
|
|||
logf( XW_LOGINFO, "%s: dropping because already here",
|
||||
__func__ );
|
||||
} else {
|
||||
pushReconnectEvent( socket, clientVersion, hid, nPlayersH, nPlayersS, seed, addr );
|
||||
pushReconnectEvent( socket, clientVersion, devID, hid, nPlayersH,
|
||||
nPlayersS, seed, addr );
|
||||
}
|
||||
if ( gameDead ) {
|
||||
pushGameDead( socket );
|
||||
|
@ -243,7 +246,8 @@ CookieRef::_HandleAck( HostID hostID )
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::_PutMsg( HostID srcID, in_addr& addr, HostID destID, unsigned char* buf, int buflen )
|
||||
CookieRef::_PutMsg( HostID srcID, in_addr& addr, HostID destID,
|
||||
unsigned char* buf, int buflen )
|
||||
{
|
||||
CRefEvent evt( XWE_PROXYMSG );
|
||||
evt.u.fwd.src = srcID;
|
||||
|
@ -513,13 +517,15 @@ CookieRef::_Remove( int socket )
|
|||
} /* Forward */
|
||||
|
||||
void
|
||||
CookieRef::pushConnectEvent( int socket, int clientVersion, int nPlayersH, int nPlayersS,
|
||||
CookieRef::pushConnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr )
|
||||
{
|
||||
CRefEvent evt;
|
||||
evt.type = XWE_DEVCONNECT;
|
||||
evt.u.con.socket = socket;
|
||||
evt.u.con.clientVersion = clientVersion;
|
||||
evt.u.con.devID = devID;
|
||||
evt.u.con.srcID = HOST_ID_NONE;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersS = nPlayersS;
|
||||
|
@ -529,13 +535,14 @@ CookieRef::pushConnectEvent( int socket, int clientVersion, int nPlayersH, int n
|
|||
} /* pushConnectEvent */
|
||||
|
||||
void
|
||||
CookieRef::pushReconnectEvent( int socket, int clientVersion, HostID srcID,
|
||||
int nPlayersH, int nPlayersS, int seed,
|
||||
in_addr& addr )
|
||||
CookieRef::pushReconnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr )
|
||||
{
|
||||
CRefEvent evt( XWE_RECONNECT );
|
||||
evt.u.con.socket = socket;
|
||||
evt.u.con.clientVersion = clientVersion;
|
||||
evt.u.con.devID = devID;
|
||||
evt.u.con.srcID = srcID;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersS = nPlayersS;
|
||||
|
@ -879,7 +886,7 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp )
|
|||
evt->u.con.srcID =
|
||||
DBMgr::Get()->AddDevice( ConnName(), evt->u.con.srcID,
|
||||
evt->u.con.clientVersion, nPlayersH, seed,
|
||||
evt->u.con.addr, reconn );
|
||||
evt->u.con.addr, evt->u.con.devID, reconn );
|
||||
|
||||
HostID hostid = evt->u.con.srcID;
|
||||
if ( NULL != hidp ) {
|
||||
|
|
|
@ -63,6 +63,13 @@ public:
|
|||
class CookieRef* m_this;
|
||||
};
|
||||
|
||||
class DevID {
|
||||
public:
|
||||
DevID() { m_devIDType = 0; }
|
||||
string m_devIDString;
|
||||
unsigned char m_devIDType;
|
||||
};
|
||||
|
||||
class CookieRef {
|
||||
public:
|
||||
set<int> GetSockets();
|
||||
|
@ -119,10 +126,11 @@ class CookieRef {
|
|||
static void Delete( CookieID cid );
|
||||
static void Delete( const char* name );
|
||||
|
||||
bool _Connect( int socket, int clientVersion, int nPlayersH, int nPlayersS,
|
||||
int seed, bool seenSeed, in_addr& addr );
|
||||
bool _Reconnect( int socket, int clientVersion, HostID srcID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
bool _Connect( int socket, int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS, int seed, bool seenSeed,
|
||||
in_addr& addr );
|
||||
bool _Reconnect( int socket, int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr, bool gameDead );
|
||||
void _HandleAck( HostID hostID );
|
||||
void _PutMsg( HostID srcID, in_addr& addr, HostID destID, unsigned char* buf, int buflen );
|
||||
|
@ -157,6 +165,7 @@ class CookieRef {
|
|||
struct {
|
||||
int socket;
|
||||
int clientVersion;
|
||||
DevID* devID;
|
||||
int nPlayersH;
|
||||
int nPlayersS;
|
||||
int seed;
|
||||
|
@ -195,10 +204,11 @@ class CookieRef {
|
|||
bool cascade );
|
||||
void send_msg( int socket, HostID id, XWRelayMsg msg, XWREASON why,
|
||||
bool cascade );
|
||||
void pushConnectEvent( int socket, int clientVersion, int nPlayersH, int nPlayersS,
|
||||
void pushConnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr );
|
||||
void pushReconnectEvent( int socket, int clientVersion, HostID srcID,
|
||||
int nPlayersH, int nPlayersS,
|
||||
void pushReconnectEvent( int socket, int clientVersion, DevID* devID,
|
||||
HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed, in_addr& addr );
|
||||
void pushHeartbeatEvent( HostID id, int socket );
|
||||
void pushHeartFailedEvent( int socket );
|
||||
|
|
|
@ -590,12 +590,13 @@ CookieMapIterator::Next()
|
|||
|
||||
/* connect case */
|
||||
SafeCref::SafeCref( const char* cookie, int socket, int clientVersion,
|
||||
int nPlayersH, int nPlayersS,
|
||||
DevID* devID, int nPlayersH, int nPlayersS,
|
||||
unsigned short gameSeed, int langCode, bool wantsPublic,
|
||||
bool makePublic )
|
||||
: m_cinfo( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_clientVersion( clientVersion )
|
||||
, m_devID( devID )
|
||||
, m_isValid( false )
|
||||
, m_seenSeed( false )
|
||||
{
|
||||
|
@ -621,6 +622,7 @@ SafeCref::SafeCref( const char* connName, const char* cookie, HostID hid,
|
|||
: m_cinfo( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_clientVersion( clientVersion )
|
||||
, m_devID( NULL )
|
||||
, m_isValid( false )
|
||||
{
|
||||
CidInfo* cinfo;
|
||||
|
|
|
@ -172,7 +172,7 @@ class SafeCref {
|
|||
public:
|
||||
/* for connect */
|
||||
SafeCref( const char* cookie, int socket, int clientVersion,
|
||||
int nPlayersH, int nPlayersS,
|
||||
DevID* devID, int nPlayersH, int nPlayersS,
|
||||
unsigned short gameSeed, int langCode, bool wantsPublic,
|
||||
bool makePublic );
|
||||
/* for reconnect */
|
||||
|
@ -212,8 +212,8 @@ class SafeCref {
|
|||
if ( IsValid() ) {
|
||||
CookieRef* cref = m_cinfo->GetRef();
|
||||
assert( 0 != cref->GetCid() );
|
||||
return cref->_Connect( socket, m_clientVersion, nPlayersH,
|
||||
nPlayersS, seed,
|
||||
return cref->_Connect( socket, m_clientVersion, m_devID,
|
||||
nPlayersH, nPlayersS, seed,
|
||||
m_seenSeed, addr );
|
||||
} else {
|
||||
return false;
|
||||
|
@ -229,9 +229,9 @@ class SafeCref {
|
|||
if ( m_dead ) {
|
||||
*errp = XWRELAY_ERROR_DEADGAME;
|
||||
} else {
|
||||
success = cref->_Reconnect( socket, m_clientVersion, srcID,
|
||||
nPlayersH, nPlayersS, seed, addr,
|
||||
m_dead );
|
||||
success = cref->_Reconnect( socket, m_clientVersion, m_devID,
|
||||
srcID, nPlayersH, nPlayersS, seed,
|
||||
addr, m_dead );
|
||||
}
|
||||
}
|
||||
return success;
|
||||
|
@ -391,6 +391,7 @@ class SafeCref {
|
|||
CidInfo* m_cinfo;
|
||||
CRefMgr* m_mgr;
|
||||
int m_clientVersion;
|
||||
DevID* m_devID;
|
||||
bool m_isValid;
|
||||
bool m_locked;
|
||||
bool m_dead;
|
||||
|
|
|
@ -244,8 +244,9 @@ DBMgr::AllDevsAckd( const char* const connName )
|
|||
}
|
||||
|
||||
HostID
|
||||
DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion, int nToAdd,
|
||||
unsigned short seed, const in_addr& addr, bool ackd )
|
||||
DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion,
|
||||
int nToAdd, unsigned short seed, const in_addr& addr,
|
||||
const DevID* devID, bool ackd )
|
||||
{
|
||||
HostID newID = curID;
|
||||
|
||||
|
@ -260,14 +261,23 @@ DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion, int nTo
|
|||
}
|
||||
assert( newID <= 4 );
|
||||
|
||||
char devIDBuf[512] = {0};
|
||||
if ( !!devID ) {
|
||||
snprintf( devIDBuf, sizeof(devIDBuf),
|
||||
"devids[%d] = \'%s\', devTypes[%d] = %d,",
|
||||
newID, devID->m_devIDString.c_str(),
|
||||
newID, devID->m_devIDType );
|
||||
}
|
||||
|
||||
const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d,"
|
||||
" clntVers[%d] = %d,"
|
||||
" seeds[%d] = %d, addrs[%d] = \'%s\', mtimes[%d]='now', ack[%d]=\'%c\'"
|
||||
" seeds[%d] = %d, addrs[%d] = \'%s\', %s"
|
||||
" mtimes[%d]='now', ack[%d]=\'%c\'"
|
||||
" WHERE connName = '%s'";
|
||||
char query[256];
|
||||
char query[1024];
|
||||
snprintf( query, sizeof(query), fmt, newID, nToAdd, newID, clientVersion,
|
||||
newID, seed, newID, inet_ntoa(addr), newID,
|
||||
newID, ackd?'A':'a', connName );
|
||||
newID, seed, newID, inet_ntoa(addr), devIDBuf,
|
||||
newID, newID, ackd?'A':'a', connName );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
|
||||
|
||||
execSql( query );
|
||||
|
@ -437,7 +447,8 @@ DBMgr::RecordSent( const int* msgIDs, int nMsgIDs )
|
|||
}
|
||||
|
||||
void
|
||||
DBMgr::RecordAddress( const char* const connName, HostID hid, const in_addr& addr )
|
||||
DBMgr::RecordAddress( const char* const connName, HostID hid,
|
||||
const in_addr& addr )
|
||||
{
|
||||
assert( hid >= 0 && hid <= 4 );
|
||||
const char* fmt = "UPDATE " GAMES_TABLE " SET addrs[%d] = \'%s\'"
|
||||
|
@ -558,6 +569,22 @@ DBMgr::readArray( const char* const connName, int arr[] ) /* len 4 */
|
|||
PQclear( result );
|
||||
}
|
||||
|
||||
void
|
||||
DBMgr::getDevID( const char* connName, int hid, DevID& devID )
|
||||
{
|
||||
const char* fmt = "SELECT devids[%d], devTypes[%d] FROM " GAMES_TABLE " WHERE connName='%s'";
|
||||
char query[256];
|
||||
snprintf( query, sizeof(query), fmt, hid, hid, connName );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
|
||||
|
||||
PGresult* result = PQexec( getThreadConn(), query );
|
||||
assert( 1 == PQntuples( result ) );
|
||||
devID.m_devIDString = PQgetvalue( result, 0, 0 );
|
||||
devID.m_devIDType = (unsigned char)atoi( PQgetvalue( result, 0, 1 ) );
|
||||
assert( devID.m_devIDType <= 2 ); // for now!!!
|
||||
PQclear( result );
|
||||
}
|
||||
|
||||
/*
|
||||
id | connname | hid | msg
|
||||
----+-----------+-----+---------
|
||||
|
@ -598,16 +625,20 @@ void
|
|||
DBMgr::StoreMessage( const char* const connName, int hid,
|
||||
const unsigned char* buf, int len )
|
||||
{
|
||||
DevID devID;
|
||||
getDevID( connName, hid, devID );
|
||||
|
||||
size_t newLen;
|
||||
const char* fmt = "INSERT INTO " MSGS_TABLE " (connname, hid, msg, msglen)"
|
||||
" VALUES( '%s', %d, E'%s', %d)";
|
||||
const char* fmt = "INSERT INTO " MSGS_TABLE " (connname, hid, devid, devType, msg, msglen)"
|
||||
" VALUES( '%s', %d, '%s', %d, E'%s', %d)";
|
||||
|
||||
unsigned char* bytes = PQescapeByteaConn( getThreadConn(), buf, len, &newLen );
|
||||
assert( NULL != bytes );
|
||||
|
||||
char query[newLen+128];
|
||||
unsigned int siz = snprintf( query, sizeof(query), fmt, connName, hid,
|
||||
bytes, len );
|
||||
devID.m_devIDString.c_str(),
|
||||
devID.m_devIDType, bytes, len );
|
||||
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
|
||||
PQfreemem( bytes );
|
||||
assert( siz < sizeof(query) );
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "xwrelay.h"
|
||||
#include "xwrelay_priv.h"
|
||||
#include "cref.h"
|
||||
#include <libpq-fe.h>
|
||||
|
||||
using namespace std;
|
||||
|
@ -56,7 +57,8 @@ class DBMgr {
|
|||
bool AllDevsAckd( const char* const connName );
|
||||
|
||||
HostID AddDevice( const char* const connName, HostID curID, int clientVersion,
|
||||
int nToAdd, unsigned short seed, const in_addr& addr, bool unAckd );
|
||||
int nToAdd, unsigned short seed, const in_addr& addr,
|
||||
const DevID* devID, bool unAckd );
|
||||
void NoteAckd( const char* const connName, HostID id );
|
||||
HostID HIDForSeed( const char* const connName, unsigned short seed );
|
||||
bool RmDeviceByHid( const char* const connName, HostID id );
|
||||
|
@ -97,6 +99,7 @@ class DBMgr {
|
|||
DBMgr();
|
||||
bool execSql( const char* const query ); /* no-results query */
|
||||
void readArray( const char* const connName, int arr[] );
|
||||
void getDevID( const char* connName, int hid, DevID& devID );
|
||||
|
||||
PGconn* getThreadConn( void );
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ QUERY="WHERE NOT -NTOTAL = sum_array(nperdevice)"
|
|||
echo "Device (pid) count: $(pidof xwords | wc | awk '{print $2}')"
|
||||
echo "Row count:" $(psql -t xwgames -c "select count(*) FROM games $QUERY;")
|
||||
|
||||
echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,ack,nsent "\
|
||||
echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,devTypes,devids,ack,nsent "\
|
||||
"FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \
|
||||
| psql xwgames
|
||||
|
||||
echo "SELECT connname, hid, count(*), sum(msglen) "\
|
||||
echo "SELECT connname, hid, devType, devid, count(*), sum(msglen) "\
|
||||
"FROM msgs where connname in (SELECT connname from games where not games.dead group by connname)" \
|
||||
"GROUP BY connname, hid ORDER BY connname;" \
|
||||
"GROUP BY connname, hid, devType, devid ORDER BY connname;" \
|
||||
| psql xwgames
|
||||
|
||||
|
|
|
@ -228,6 +228,20 @@ getNetByte( unsigned char** bufpp, const unsigned char* end,
|
|||
return ok;
|
||||
} /* getNetByte */
|
||||
|
||||
static bool
|
||||
getNetString( unsigned char** bufpp, const unsigned char* end, string& out )
|
||||
{
|
||||
char* str = (char*)*bufpp;
|
||||
size_t len = 1 + strlen( str );
|
||||
bool success = str + len <= (char*)end;
|
||||
if ( success ) {
|
||||
out = str;
|
||||
*bufpp += len;
|
||||
}
|
||||
// logf( XW_LOGERROR, "%s => %d", __func__, out.c_str() );
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
static bool
|
||||
processHeartbeat( unsigned char* buf, int bufLen, int socket )
|
||||
|
@ -268,12 +282,14 @@ readStr( unsigned char** bufp, const unsigned char* end,
|
|||
|
||||
static XWREASON
|
||||
flagsOK( unsigned char** bufp, unsigned char const* end,
|
||||
unsigned short* clientVersion )
|
||||
unsigned short* clientVersion, unsigned short* flagsp )
|
||||
{
|
||||
XWREASON err = XWRELAY_ERROR_OLDFLAGS;
|
||||
unsigned char flags;
|
||||
if ( getNetByte( bufp, end, &flags ) ) {
|
||||
*flagsp = flags;
|
||||
switch ( flags ) {
|
||||
case XWRELAY_PROTO_VERSION_CLIENTID:
|
||||
case XWRELAY_PROTO_VERSION_CLIENTVERS:
|
||||
if ( getNetShort( bufp, end, clientVersion ) ) {
|
||||
err = XWRELAY_ERROR_NONE;
|
||||
|
@ -346,7 +362,8 @@ processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
cookie[0] = '\0';
|
||||
|
||||
unsigned short clientVersion;
|
||||
XWREASON err = flagsOK( &bufp, end, &clientVersion );
|
||||
unsigned short flags;
|
||||
XWREASON err = flagsOK( &bufp, end, &clientVersion, &flags );
|
||||
if ( err == XWRELAY_ERROR_NONE ) {
|
||||
/* HostID srcID; */
|
||||
unsigned char nPlayersH;
|
||||
|
@ -362,6 +379,17 @@ processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
&& getNetByte( &bufp, end, &nPlayersT )
|
||||
&& getNetShort( &bufp, end, &seed )
|
||||
&& getNetByte( &bufp, end, &langCode ) ) {
|
||||
|
||||
DevID devID;
|
||||
if ( XWRELAY_PROTO_VERSION_CLIENTID <= flags ) {
|
||||
unsigned char devIDType = 0;
|
||||
if ( getNetByte( &bufp, end, &devIDType )
|
||||
&& 0 != devIDType ) {
|
||||
getNetString( &bufp, end, devID.m_devIDString );
|
||||
devID.m_devIDType = devIDType;
|
||||
}
|
||||
}
|
||||
|
||||
logf( XW_LOGINFO, "%s(): langCode=%d; nPlayersT=%d; "
|
||||
"wantsPublic=%d; seed=%.4X",
|
||||
__func__, langCode, nPlayersT, wantsPublic, seed );
|
||||
|
@ -371,8 +399,9 @@ processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
MutexLock ml( &s_newCookieLock );
|
||||
|
||||
SafeCref scr( cookie, socket, clientVersion, nPlayersH, nPlayersT,
|
||||
seed, langCode, wantsPublic, makePublic );
|
||||
SafeCref scr( cookie, socket, clientVersion, &devID,
|
||||
nPlayersH, nPlayersT, seed, langCode,
|
||||
wantsPublic, makePublic );
|
||||
/* nPlayersT etc could be slots in SafeCref to avoid passing
|
||||
here */
|
||||
success = scr.Connect( socket, nPlayersH, nPlayersT, seed, addr );
|
||||
|
@ -396,7 +425,8 @@ processReconnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr )
|
|||
logf( XW_LOGINFO, "%s()", __func__ );
|
||||
|
||||
unsigned short clientVersion;
|
||||
XWREASON err = flagsOK( &bufp, end, &clientVersion );
|
||||
unsigned short flags;
|
||||
XWREASON err = flagsOK( &bufp, end, &clientVersion, &flags );
|
||||
if ( err == XWRELAY_ERROR_NONE ) {
|
||||
char cookie[MAX_INVITE_LEN+1];
|
||||
char connName[MAX_CONNNAME_LEN+1] = {0};
|
||||
|
|
|
@ -121,6 +121,7 @@ typedef unsigned char XWRELAY_Cmd;
|
|||
#define XWRELAY_PROTO_VERSION_LATE_COOKIEID 0x03
|
||||
#define XWRELAY_PROTO_VERSION_NOCLIENT 0x04
|
||||
#define XWRELAY_PROTO_VERSION_CLIENTVERS 0x05
|
||||
#define XWRELAY_PROTO_VERSION_CLIENTID 0x06
|
||||
#define XWRELAY_PROTO_VERSION XWRELAY_PROTO_VERSION_CLIENTVERS
|
||||
|
||||
/* Errors passed with denied */
|
||||
|
|
|
@ -58,6 +58,8 @@ cid integer
|
|||
,ctime TIMESTAMP (0) DEFAULT CURRENT_TIMESTAMP
|
||||
,mtimes TIMESTAMP(0)[]
|
||||
,addrs INET[]
|
||||
,devTypes INTEGER[]
|
||||
,devids TEXT[]
|
||||
);
|
||||
EOF
|
||||
|
||||
|
@ -67,6 +69,8 @@ id SERIAL
|
|||
,connName VARCHAR(64)
|
||||
,hid INTEGER
|
||||
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
,devType INTEGER
|
||||
,devid TEXT
|
||||
,msg BYTEA
|
||||
,msglen INTEGER
|
||||
,UNIQUE ( connName, hid, msg )
|
||||
|
|
Loading…
Add table
Reference in a new issue