2014-08-29 01:04:17 +04:00
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set shiftwidth=4 tabstop=4 autoindent cindent expandtab: */
2014-08-29 01:13:45 +04:00
'use strict' ;
2014-08-29 01:04:17 +04:00
var LocalMsgConnection = function ( ) {
this . waitingForConnection = null ;
this . serverWaiting = null ;
this . clientWaiting = null ;
this . serverMessages = [ ] ;
this . clientMessages = [ ] ;
}
LocalMsgConnection . prototype . notifyConnection = function ( ) {
if ( this . waitingForConnection ) {
this . waitingForConnection ( ) ;
}
}
2014-10-17 02:04:31 +04:00
LocalMsgConnection . prototype . waitConnection = function ( ) {
return new Promise ( ( function ( resolve , reject ) {
this . waitingForConnection = function ( ) {
this . waitingForConnection = null ;
resolve ( ) ;
}
} ) . bind ( this ) ) ;
2014-08-29 01:04:17 +04:00
}
LocalMsgConnection . prototype . copyMessage = function ( messageQueue , data ) {
var msg = messageQueue . shift ( ) ;
for ( var i = 0 ; i < msg . length ; i ++ ) {
data [ i ] = msg . data [ i + msg . offset ] ;
}
2014-09-08 20:27:41 +04:00
return msg . length ;
2014-08-29 01:04:17 +04:00
}
LocalMsgConnection . prototype . sendMessageToClient = function ( message ) {
this . clientMessages . push ( message ) ;
if ( this . clientWaiting ) {
this . clientWaiting ( ) ;
}
}
2014-10-17 02:04:31 +04:00
LocalMsgConnection . prototype . clientReceiveMessage = function ( data ) {
return new Promise ( ( function ( resolve , reject ) {
if ( this . clientMessages . length == 0 ) {
this . clientWaiting = function ( ) {
this . clientWaiting = null ;
2014-08-29 01:04:17 +04:00
2014-10-17 02:04:31 +04:00
resolve ( this . copyMessage ( this . clientMessages , data ) ) ;
}
2014-08-29 01:04:17 +04:00
2014-10-17 02:04:31 +04:00
return ;
2014-08-29 01:04:17 +04:00
}
2014-10-17 02:04:31 +04:00
resolve ( this . copyMessage ( this . clientMessages , data ) ) ;
} ) . bind ( this ) ) ;
2014-08-29 01:04:17 +04:00
}
LocalMsgConnection . prototype . sendMessageToServer = function ( message ) {
this . serverMessages . push ( message ) ;
if ( this . serverWaiting ) {
this . serverWaiting ( ) ;
}
}
2014-10-17 02:04:31 +04:00
LocalMsgConnection . prototype . serverReceiveMessage = function ( data ) {
return new Promise ( ( function ( resolve , reject ) {
if ( this . serverMessages . length == 0 ) {
this . serverWaiting = function ( ) {
this . serverWaiting = null ;
2014-08-29 01:04:17 +04:00
2014-10-17 02:04:31 +04:00
resolve ( this . copyMessage ( this . serverMessages , data ) ) ;
}
return ;
2014-08-29 01:04:17 +04:00
}
2014-10-17 02:04:31 +04:00
resolve ( this . copyMessage ( this . serverMessages , data ) ) ;
} ) . bind ( this ) ) ;
2014-08-29 01:04:17 +04:00
}
2014-09-10 05:44:46 +04:00
var NokiaMessagingLocalMsgConnection = function ( ) {
2014-09-10 03:07:40 +04:00
LocalMsgConnection . call ( this ) ;
}
2014-09-10 05:44:46 +04:00
NokiaMessagingLocalMsgConnection . prototype = Object . create ( LocalMsgConnection . prototype ) ;
NokiaMessagingLocalMsgConnection . prototype . receiveSMS = function ( sms ) {
var encoder = new DataEncoder ( ) ;
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "MessageNotify" ) ;
2014-09-10 21:47:56 +04:00
encoder . put ( DataType . USHORT , "trans_id" , Date . now ( ) % 255 ) ; // The meaning of this field is unknown
2014-09-10 05:44:46 +04:00
encoder . put ( DataType . STRING , "type" , "SMS" ) ; // The name of this field is unknown
2014-09-10 21:42:51 +04:00
encoder . put ( DataType . ULONG , "message_id" , sms . id ) ;
2014-09-10 05:44:46 +04:00
encoder . putEnd ( DataType . STRUCT , "event" ) ;
var data = new TextEncoder ( ) . encode ( encoder . getData ( ) ) ;
this . sendMessageToClient ( {
data : data ,
length : data . length ,
offset : 0 ,
} ) ;
}
NokiaMessagingLocalMsgConnection . prototype . sendMessageToServer = function ( message ) {
var encoder = new DataEncoder ( ) ;
2014-09-10 03:07:40 +04:00
var decoder = new DataDecoder ( message . data , message . offset , message . length ) ;
2014-09-10 05:44:46 +04:00
decoder . getStart ( DataType . STRUCT ) ;
var name = decoder . getValue ( DataType . METHOD ) ;
2014-09-10 21:49:51 +04:00
2014-09-10 05:44:46 +04:00
switch ( name ) {
case "Common" :
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "Common" ) ;
encoder . putStart ( DataType . STRUCT , "message" ) ;
encoder . put ( DataType . METHOD , "name" , "ProtocolVersion" ) ;
encoder . put ( DataType . STRING , "version" , "2.[0-10]" ) ;
encoder . putEnd ( DataType . STRUCT , "message" ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
break ;
case "SubscribeMessages" :
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "SubscribeMessages" ) ;
2014-09-10 21:06:00 +04:00
encoder . put ( DataType . USHORT , "trans_id" , decoder . getValue ( DataType . USHORT ) ) ; // The meaning of this field is unknown
2014-09-10 05:44:46 +04:00
encoder . put ( DataType . STRING , "result" , "OK" ) ; // The name of this field is unknown
encoder . putEnd ( DataType . STRUCT , "event" ) ;
break ;
case "GetMessageEntity" :
2014-09-10 21:06:00 +04:00
var trans _id = decoder . getValue ( DataType . USHORT ) ;
2014-09-10 05:44:46 +04:00
var sms _id = decoder . getValue ( DataType . ULONG ) ;
var sms ;
2014-09-11 01:01:31 +04:00
for ( var i = 0 ; i < MIDP . nokiaSMSMessages . length ; i ++ ) {
if ( MIDP . nokiaSMSMessages [ i ] . id == sms _id ) {
sms = MIDP . nokiaSMSMessages [ i ] ;
break ;
2014-09-10 05:44:46 +04:00
}
}
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "GetMessageEntity" ) ;
2014-09-10 21:06:00 +04:00
encoder . put ( DataType . USHORT , "trans_id" , trans _id ) ; // The meaning of this field is unknown
2014-09-10 05:44:46 +04:00
encoder . put ( DataType . STRING , "result" , "OK" ) ; // The name of this field is unknown
encoder . put ( DataType . ULONG , "message_id" , sms _id ) ;
encoder . putStart ( DataType . LIST , "list_name_unknown" ) ; // The name of this field is unknown
encoder . put ( DataType . WSTRING , "body_text" , sms . text ) ;
encoder . put ( DataType . STRING , "address" , sms . addr ) ;
encoder . putEnd ( DataType . LIST ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
break ;
case "DeleteMessages" :
decoder . getValue ( DataType . USHORT ) ;
decoder . getStart ( DataType . ARRAY ) ;
var sms _id = decoder . getValue ( DataType . ULONG ) ;
2014-09-10 21:14:56 +04:00
2014-09-11 01:01:31 +04:00
for ( var i = 0 ; i < MIDP . nokiaSMSMessages . length ; i ++ ) {
if ( MIDP . nokiaSMSMessages [ i ] . id == sms _id ) {
MIDP . nokiaSMSMessages . splice ( i , 1 ) ;
break ;
2014-09-10 21:14:56 +04:00
}
}
2014-09-10 05:44:46 +04:00
break ;
default :
2014-09-19 22:35:12 +04:00
console . error ( "(nokia.messaging) event " + name + " not implemented " +
util . decodeUtf8 ( new Uint8Array ( message . data . buffer , message . offset , message . length ) ) ) ;
2014-09-10 05:44:46 +04:00
return ;
}
var data = new TextEncoder ( ) . encode ( encoder . getData ( ) ) ;
this . sendMessageToClient ( {
data : data ,
length : data . length ,
offset : 0 ,
} ) ;
2014-09-10 03:07:40 +04:00
}
2014-09-17 02:33:11 +04:00
var NokiaContactsLocalMsgConnection = function ( ) {
LocalMsgConnection . call ( this ) ;
}
2014-10-14 13:18:38 +04:00
var NokiaPhoneStatusLocalMsgConnection = function ( ) {
LocalMsgConnection . call ( this ) ;
} ;
NokiaPhoneStatusLocalMsgConnection . prototype = Object . create ( LocalMsgConnection . prototype ) ;
NokiaPhoneStatusLocalMsgConnection . prototype . sendMessageToServer = function ( message ) {
var decoder = new DataDecoder ( message . data , message . offset , message . length ) ;
decoder . getStart ( DataType . STRUCT ) ;
var name = decoder . getValue ( DataType . METHOD ) ;
var encoder = new DataEncoder ( ) ;
switch ( name ) {
case "Common" :
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "Common" ) ;
encoder . putStart ( DataType . STRUCT , "message" ) ;
encoder . put ( DataType . METHOD , "name" , "ProtocolVersion" ) ;
encoder . put ( DataType . STRING , "version" , "2.[0-10]" ) ;
encoder . putEnd ( DataType . STRUCT , "message" ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
break ;
case "Query" :
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "Query" ) ;
encoder . put ( DataType . STRING , "status" , "OK" ) ;
encoder . putStart ( DataType . LIST , "subscriptions" ) ;
// subscriptions
decoder . getStart ( DataType . LIST ) ;
while ( decoder . getTag ( ) == DataType . STRING ) {
switch ( decoder . getName ( ) ) {
case "network_status" :
encoder . putStart ( DataType . STRUCT , "network_status" ) ;
encoder . put ( DataType . STRING , "" , "" ) ; // unknow name
encoder . put ( DataType . BOOLEAN , "" , 1 ) ; // unknow name
encoder . putEnd ( DataType . STRUCT , "network_status" ) ;
break ;
case "wifi_status" :
encoder . putStart ( DataType . STRUCT , "wifi_status" ) ;
encoder . put ( DataType . BOOLEAN , "" , 1 ) ; // unknow name, but it should indicate if the wifi is connected, and let's assume it's always connected.
encoder . putEnd ( DataType . STRUCT , "wifi_status" ) ;
break ;
case "battery" :
encoder . putStart ( DataType . STRUCT , "battery" ) ;
encoder . put ( DataType . BYTE , "" , 1 ) ; // unknow name
encoder . put ( DataType . BOOLEAN , "" , 1 ) ; // unknow name
encoder . putEnd ( DataType . STRUCT , "battery" ) ;
break ;
default :
console . error ( "(nokia.phone-status) Query " + decoder . getName ( ) + " not implemented " +
util . decodeUtf8 ( new Uint8Array ( message . data . buffer , message . offset , message . length ) ) ) ;
break ;
}
decoder . getValue ( DataType . STRING ) ;
}
encoder . putEnd ( DataType . LIST , "subscriptions" ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
break ;
default :
console . error ( "(nokia.phone-status) event " + name + " not implemented " +
util . decodeUtf8 ( new Uint8Array ( message . data . buffer , message . offset , message . length ) ) ) ;
return ;
}
var data = new TextEncoder ( ) . encode ( encoder . getData ( ) ) ;
this . sendMessageToClient ( {
data : data ,
length : data . length ,
offset : 0 ,
} ) ;
} ;
2014-09-17 02:33:11 +04:00
NokiaContactsLocalMsgConnection . prototype = Object . create ( LocalMsgConnection . prototype ) ;
2014-09-19 22:30:35 +04:00
NokiaContactsLocalMsgConnection . prototype . sendContact = function ( trans _id , contact ) {
var encoder = new DataEncoder ( ) ;
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "Notify" ) ;
encoder . put ( DataType . ULONG , "trans_id" , trans _id ) ; // The meaning of this field is unknown
encoder . put ( DataType . BYTE , "type" , 1 ) ; // The name of this field is unknown (the value may be 1, 2, 3 according to the event (I'd guess CREATE, DELETE, UPDATE))
encoder . putStart ( DataType . LIST , "Contact" ) ;
encoder . put ( DataType . WSTRING , "ContactID" , contact . id . toString ( ) ) ;
encoder . put ( DataType . WSTRING , "DisplayName" , contact . name [ 0 ] ) ;
encoder . putStart ( DataType . ARRAY , "Numbers" ) ;
contact . tel . forEach ( function ( tel ) {
encoder . putStart ( DataType . LIST , "NumbersList" ) ; // The name of this field is unknown
// encoder.put(DataType.ULONG, "Kind", ???); // The meaning of this field is unknown
encoder . put ( DataType . WSTRING , "Number" , tel . value ) ;
encoder . putEnd ( DataType . LIST , "NumbersList" ) ;
} ) ;
encoder . putEnd ( DataType . ARRAY , "Numbers" ) ;
encoder . putEnd ( DataType . LIST , "Contact" ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
var data = new TextEncoder ( ) . encode ( encoder . getData ( ) ) ;
this . sendMessageToClient ( {
data : data ,
length : data . length ,
offset : 0 ,
} ) ;
} ;
2014-09-17 02:33:11 +04:00
2014-09-19 22:30:35 +04:00
NokiaContactsLocalMsgConnection . prototype . sendMessageToServer = function ( message ) {
2014-09-17 02:33:11 +04:00
var decoder = new DataDecoder ( message . data , message . offset , message . length ) ;
decoder . getStart ( DataType . STRUCT ) ;
var name = decoder . getValue ( DataType . METHOD ) ;
switch ( name ) {
case "Common" :
2014-09-19 22:30:35 +04:00
var encoder = new DataEncoder ( ) ;
2014-09-17 02:33:11 +04:00
encoder . putStart ( DataType . STRUCT , "event" ) ;
encoder . put ( DataType . METHOD , "name" , "Common" ) ;
encoder . putStart ( DataType . STRUCT , "message" ) ;
encoder . put ( DataType . METHOD , "name" , "ProtocolVersion" ) ;
encoder . put ( DataType . STRING , "version" , "2.[0-10]" ) ;
encoder . putEnd ( DataType . STRUCT , "message" ) ;
encoder . putEnd ( DataType . STRUCT , "event" ) ;
2014-09-19 22:30:35 +04:00
var data = new TextEncoder ( ) . encode ( encoder . getData ( ) ) ;
this . sendMessageToClient ( {
data : data ,
length : data . length ,
offset : 0 ,
} ) ;
2014-09-17 02:33:11 +04:00
break ;
case "NotifySubscribe" :
2014-09-19 22:30:35 +04:00
contacts . forEach ( this . sendContact . bind ( this , decoder . getValue ( DataType . ULONG ) ) ) ;
2014-09-17 02:33:11 +04:00
break ;
default :
2014-09-19 22:35:12 +04:00
console . error ( "(nokia.contacts) event " + name + " not implemented " +
util . decodeUtf8 ( new Uint8Array ( message . data . buffer , message . offset , message . length ) ) ) ;
2014-09-17 02:33:11 +04:00
return ;
}
}
2014-08-29 01:04:17 +04:00
MIDP . LocalMsgConnections = { } ;
2014-09-06 03:00:48 +04:00
// Add some fake servers because some MIDlets assume they exist.
2014-09-06 03:05:35 +04:00
// MIDlets are usually happy even if the servers don't reply, but we should
// remember to implement them in case they will be needed.
2014-10-14 13:18:38 +04:00
MIDP . FakeLocalMsgServers = [ "nokia.active-standby" , "nokia.profile" ,
2014-09-20 03:43:21 +04:00
"nokia.connectivity-settings" , "nokia.file-ui" ] ;
2014-09-06 04:01:30 +04:00
MIDP . FakeLocalMsgServers . forEach ( function ( server ) {
MIDP . LocalMsgConnections [ server ] = new LocalMsgConnection ( ) ;
} ) ;
2014-08-29 01:04:17 +04:00
2014-09-17 02:33:11 +04:00
MIDP . LocalMsgConnections [ "nokia.contacts" ] = new NokiaContactsLocalMsgConnection ( ) ;
2014-09-10 05:44:46 +04:00
MIDP . LocalMsgConnections [ "nokia.messaging" ] = new NokiaMessagingLocalMsgConnection ( ) ;
2014-10-14 13:18:38 +04:00
MIDP . LocalMsgConnections [ "nokia.phone-status" ] = new NokiaPhoneStatusLocalMsgConnection ( ) ;
2014-09-10 03:07:40 +04:00
2014-10-27 14:37:53 +03:00
Native . create ( "org/mozilla/io/LocalMsgConnection.init.(Ljava/lang/String;)V" , function ( jName ) {
2014-10-15 02:45:53 +04:00
var name = util . fromJavaString ( jName ) ;
2014-08-29 01:04:17 +04:00
2014-10-15 02:45:53 +04:00
this . server = ( name [ 2 ] == ":" ) ;
this . protocolName = name . slice ( ( name [ 2 ] == ':' ) ? 3 : 2 ) ;
2014-08-29 01:04:17 +04:00
2014-10-17 07:08:51 +04:00
return new Promise ( ( function ( resolve , reject ) {
if ( this . server ) {
MIDP . LocalMsgConnections [ this . protocolName ] = new LocalMsgConnection ( ) ;
MIDP . ConnectionRegistry . pushNotify ( "localmsg:" + this . protocolName ) ;
} else {
// Actually, there should always be a server, but we need this check
// for apps that use the Nokia built-in servers (because we haven't
// implemented them yet).
if ( ! MIDP . LocalMsgConnections [ this . protocolName ] ) {
console . warn ( "localmsg server (" + this . protocolName + ") unimplemented" ) ;
// Return without resolving the promise, we want the thread that is connecting
// to this unimplemented server to stop indefinitely.
return ;
}
2014-08-29 01:04:17 +04:00
2014-10-17 07:08:51 +04:00
if ( MIDP . FakeLocalMsgServers . indexOf ( this . protocolName ) != - 1 ) {
console . warn ( "connect to an unimplemented localmsg server (" + this . protocolName + ")" ) ;
}
MIDP . LocalMsgConnections [ this . protocolName ] . notifyConnection ( ) ;
2014-09-06 04:01:30 +04:00
}
2014-10-17 07:08:51 +04:00
resolve ( ) ;
} ) . bind ( this ) ) ;
2014-10-15 02:45:53 +04:00
} ) ;
2014-08-29 01:04:17 +04:00
2014-10-27 14:37:53 +03:00
Native . create ( "org/mozilla/io/LocalMsgConnection.waitConnection.()V" , function ( ) {
2014-10-17 02:04:31 +04:00
return MIDP . LocalMsgConnections [ this . protocolName ] . waitConnection ( ) ;
2014-10-15 02:45:53 +04:00
} ) ;
2014-08-29 01:04:17 +04:00
2014-10-27 14:37:53 +03:00
Native . create ( "org/mozilla/io/LocalMsgConnection.sendData.([BII)V" , function ( data , offset , length ) {
2014-08-29 01:04:17 +04:00
var message = {
data : data ,
offset : offset ,
length : length ,
} ;
2014-10-15 02:45:53 +04:00
if ( this . server ) {
MIDP . LocalMsgConnections [ this . protocolName ] . sendMessageToClient ( message ) ;
2014-08-29 01:04:17 +04:00
} else {
2014-10-15 02:45:53 +04:00
if ( MIDP . FakeLocalMsgServers . indexOf ( this . protocolName ) != - 1 ) {
console . warn ( "sendData (" + util . decodeUtf8 ( new Uint8Array ( data . buffer , offset , length ) ) + ") to an unimplemented localmsg server (" + this . protocolName + ")" ) ;
2014-09-06 04:01:30 +04:00
}
2014-10-15 02:45:53 +04:00
MIDP . LocalMsgConnections [ this . protocolName ] . sendMessageToServer ( message ) ;
2014-08-29 01:04:17 +04:00
}
2014-10-15 02:45:53 +04:00
} ) ;
2014-08-29 01:04:17 +04:00
2014-10-27 14:37:53 +03:00
Native . create ( "org/mozilla/io/LocalMsgConnection.receiveData.([B)I" , function ( data ) {
2014-10-17 02:04:31 +04:00
if ( this . server ) {
return MIDP . LocalMsgConnections [ this . protocolName ] . serverReceiveMessage ( data ) ;
}
2014-09-06 04:01:30 +04:00
2014-10-17 02:04:31 +04:00
if ( MIDP . FakeLocalMsgServers . indexOf ( this . protocolName ) != - 1 ) {
console . warn ( "receiveData from an unimplemented localmsg server (" + this . protocolName + ")" ) ;
2014-08-29 01:04:17 +04:00
}
2014-10-17 02:04:31 +04:00
return MIDP . LocalMsgConnections [ this . protocolName ] . clientReceiveMessage ( data ) ;
} ) ;
2014-08-29 01:04:17 +04:00
2014-10-27 14:37:53 +03:00
Native . create ( "org/mozilla/io/LocalMsgConnection.closeConnection.()V" , function ( ) {
2014-10-15 02:45:53 +04:00
if ( this . server ) {
delete MIDP . LocalMsgConnections [ this . protocolName ] ;
2014-08-29 01:04:17 +04:00
}
2014-10-15 02:45:53 +04:00
} ) ;