2012-04-13 17:05:16 +02:00
function jappixmini _addon _xor ( str1 , str2 ) {
if ( str1 . length != str2 . length ) throw "not same length" ;
encoded = "" ;
for ( i = 0 ; i < str1 . length ; i ++ ) {
var a = str1 . charCodeAt ( i ) ;
var b = str2 . charCodeAt ( i ) ;
var c = a ^ b ;
encoded += String . fromCharCode ( c ) ;
}
return encoded ;
}
function jappixmini _addon _set _client _secret ( password ) {
2012-04-14 18:23:42 +02:00
if ( ! password ) return ;
salt1 = "h8doCRekWto0njyQohKpdx6BN0UTyC6N" ;
salt2 = "jdX8OwFC1kWAq3s9uOyAcE8g3UNNO5t3" ;
client _secret1 = str _sha1 ( salt1 + password ) ;
client _secret2 = str _sha1 ( salt2 + password ) ;
client _secret = client _secret1 + client _secret2 ;
2012-04-15 23:19:37 +02:00
setPersistent ( 'jappix-mini' , 'client-secret' , client _secret ) ;
2012-04-14 18:23:42 +02:00
console . log ( "client secret set" ) ;
2012-04-13 17:05:16 +02:00
}
2012-04-15 22:57:25 +02:00
function jappixmini _addon _get _client _secret ( callback ) {
2012-04-15 23:19:37 +02:00
client _secret = getPersistent ( 'jappix-mini' , 'client-secret' ) ;
2012-04-13 17:05:16 +02:00
if ( client _secret === null ) {
2012-04-15 22:57:25 +02:00
div = document . getElementById ( "#jappixmini-password-query-div" ) ;
if ( ! div ) {
div = $ ( '<div id="jappixmini-password-query-div" style="position:fixed;padding:1em;background-color:#F00;color:#fff;top:50px;left:50px;">Retype your Friendica password for chatting:<br></div>' ) ;
input = $ ( '<input type="password" id="jappixmini-password-query-input">' )
div . append ( input ) ;
button = $ ( '<input type="button" value="OK" id="jappixmini-password-query-button">' ) ;
div . append ( button ) ;
$ ( "body" ) . append ( div ) ;
}
2012-04-13 17:05:16 +02:00
button . click ( function ( ) {
2012-04-15 22:57:25 +02:00
password = $ ( "#jappixmini-password-query-input" ) . val ( ) ;
2012-04-13 17:05:16 +02:00
jappixmini _addon _set _client _secret ( password ) ;
div . remove ( ) ;
2012-04-15 22:57:25 +02:00
2012-04-15 23:19:37 +02:00
client _secret = getPersistent ( 'jappix-mini' , 'client-secret' ) ;
2012-04-15 22:57:25 +02:00
callback ( client _secret ) ;
2012-04-13 17:05:16 +02:00
} ) ;
}
2012-04-15 22:57:25 +02:00
else {
callback ( client _secret ) ;
}
2012-04-13 17:05:16 +02:00
}
2012-04-15 22:57:25 +02:00
function jappixmini _addon _encrypt _password ( password , callback ) {
jappixmini _addon _get _client _secret ( function ( client _secret ) {
// add \0 to password until it has the same length as secret
if ( password . length > client _secret . length - 1 ) throw "password too long" ;
while ( password . length < client _secret . length ) {
password += "\0" ;
}
2012-04-13 17:05:16 +02:00
2012-04-15 22:57:25 +02:00
// xor password with secret
encrypted _password = jappixmini _addon _xor ( client _secret , password ) ;
2012-04-13 17:05:16 +02:00
2012-04-15 22:57:25 +02:00
encrypted _password = encodeURI ( encrypted _password )
callback ( encrypted _password ) ;
} ) ;
2012-04-13 17:05:16 +02:00
}
2012-04-15 22:57:25 +02:00
function jappixmini _addon _decrypt _password ( encrypted _password , callback ) {
2012-04-13 17:05:16 +02:00
encrypted _password = decodeURI ( encrypted _password ) ;
2012-04-15 22:57:25 +02:00
jappixmini _addon _get _client _secret ( function ( client _secret ) {
// xor password with secret
password = jappixmini _addon _xor ( client _secret , encrypted _password ) ;
2012-04-13 17:05:16 +02:00
2012-04-15 22:57:25 +02:00
// remove \0
first _null = password . indexOf ( "\0" )
2012-04-16 23:39:21 +02:00
if ( first _null == - 1 ) throw "Decrypted password does not contain \\0" ;
2012-04-15 22:57:25 +02:00
password = password . substr ( 0 , first _null ) ;
2012-04-13 17:05:16 +02:00
2012-04-15 22:57:25 +02:00
callback ( password ) ;
} ) ;
2012-04-13 17:05:16 +02:00
}
function jappixmini _manage _roster ( contacts , autoapprove , autosubscribe ) {
// listen for subscriptions
con . registerHandler ( 'presence' , function ( presence ) {
var type = presence . getType ( ) ;
if ( type != "subscribe" ) return ;
var from = fullXID ( getStanzaFrom ( presence ) ) ;
var xid = bareXID ( from ) ;
2012-04-16 23:40:40 +02:00
var pstatus = presence . getStatus ( ) ;
2012-04-13 17:05:16 +02:00
2012-04-16 23:40:40 +02:00
if ( autoapprove && contacts [ xid ] !== undefined ) {
// approve known address
approve = true ;
console . log ( "Approve known Friendica contact " + xid + "." ) ;
}
else if ( autoapprove && pstatus && pstatus . indexOf ( "Friendica" ) != - 1 ) {
// Unknown address claims to be a Friendica contact.
// This is probably because the other side knows our
// address, but we do not know the other side yet.
// But it's only a matter of time, so wait - do not
// approve yet and do not annoy the user by asking.
approve = false ;
console . log ( "Do not approve unknown Friendica contact " + xid + " - wait instead." ) ;
}
else {
// In all other cases, ask the user.
message = "Accept " + xid + " for chat?" ;
if ( pstatus ) message += "\n\nStatus:\n" + pstatus ;
approve = confirm ( message ) ;
2012-04-17 21:00:03 +02:00
// do not ask any more
if ( ! approve ) sendSubscribe ( xid , "unsubscribed" ) ;
2012-04-16 23:40:40 +02:00
}
2012-04-13 17:05:16 +02:00
if ( approve ) {
2012-04-14 18:23:42 +02:00
acceptSubscribe ( xid , contacts [ xid ] ) ;
console . log ( "Accepted " + xid + " for chat." ) ;
2012-04-13 17:05:16 +02:00
}
} ) ;
// autosubscribe
2012-04-16 01:04:45 +02:00
if ( ! autosubscribe ) return ;
var get _roster = new JSJaCIQ ( ) ;
get _roster . setType ( 'get' ) ;
get _roster . setQuery ( NS _ROSTER ) ;
con . send ( get _roster , function ( iq ) {
var handleXML = iq . getQuery ( ) ;
// filter out contacts that are already in the roster
$ ( handleXML ) . find ( 'item' ) . each ( function ( ) {
xid = $ ( this ) . attr ( "jid" ) ;
name = $ ( this ) . attr ( "name" ) ;
subscription = $ ( this ) . attr ( "subscription" ) ;
// ignore accounts not in the list
if ( contacts [ xid ] === undefined ) return ;
2012-04-17 00:41:22 +02:00
// add to Friendica group if necessary
groups = [ ] ;
$ ( this ) . find ( 'group' ) . each ( function ( ) {
var group _text = $ ( this ) . text ( ) ;
if ( group _text ) groups . push ( group _text ) ;
} ) ;
if ( $ . inArray ( "Friendica" , groups ) == - 1 ) {
console . log ( "Add " + xid + " to Friendica group." ) ;
groups . push ( "Friendica" ) ;
sendRoster ( xid , null , null , groups ) ;
console . log ( "Added " + xid + " to Friendica group." ) ;
}
// authorize if necessary
if ( subscription == "to" ) {
sendSubscribe ( xid , 'subscribed' ) ;
}
2012-04-16 01:04:45 +02:00
// remove from list
delete contacts [ xid ] ;
} ) ;
// go through remaining contacts
for ( var xid in contacts ) { if ( ! contacts . hasOwnProperty ( xid ) ) continue ;
// subscribe
var presence = new JSJaCPresence ( ) ;
presence . setTo ( xid ) ;
presence . setType ( "subscribe" ) ;
2012-04-16 23:40:40 +02:00
// must contain the word "~Friendica" so the other side knows
// how to handle this
presence . setStatus ( "I'm " + MINI _NICKNAME + " from ~Friendica.\n[machine-generated message]" ) ;
2012-04-16 01:04:45 +02:00
con . send ( presence ) ;
console . log ( "subscribed to " + xid ) ;
// add to roster
var iq = new JSJaCIQ ( ) ;
iq . setType ( 'set' ) ;
var iqQuery = iq . setQuery ( NS _ROSTER ) ;
var item = iqQuery . appendChild ( iq . buildNode ( 'item' , { 'xmlns' : NS _ROSTER , 'jid' : xid } ) ) ;
item . setAttribute ( 'name' , contacts [ xid ] ) ;
item . appendChild ( iq . buildNode ( 'group' , { 'xmlns' : NS _ROSTER } , "Friendica" ) ) ;
con . send ( iq ) ;
2012-04-17 00:04:34 +02:00
console . log ( "added to roster: " + xid ) ;
2012-04-13 17:05:16 +02:00
}
2012-04-16 01:04:45 +02:00
} ) ;
2012-04-13 17:05:16 +02:00
}
2012-04-15 12:20:53 +02:00
function jappixmini _addon _subscribe ( ) {
if ( ! window . con ) {
alert ( "Not connected." ) ;
return ;
}
xid = prompt ( "Jabber address" ) ;
sendSubscribe ( xid , "subscribe" ) ;
}
2012-04-16 21:16:24 +02:00
function jappixmini _addon _start ( server , username , proxy , bosh , encrypted , password , nickname , contacts , autoapprove , autosubscribe ) {
2012-04-15 22:57:25 +02:00
handler = function ( password ) {
// check if settings have changed, reinitialize jappix mini if this is the case
settings _identifier = str _sha1 ( server ) ;
settings _identifier += str _sha1 ( username ) ;
2012-04-16 23:39:46 +02:00
settings _identifier += str _sha1 ( proxy ) ;
2012-04-15 22:57:25 +02:00
settings _identifier += str _sha1 ( bosh ) ;
settings _identifier += str _sha1 ( password ) ;
settings _identifier += str _sha1 ( nickname ) ;
saved _identifier = getDB ( "jappix-mini" , "settings_identifier" ) ;
if ( saved _identifier != settings _identifier ) removeDB ( 'jappix-mini' , 'dom' ) ;
setDB ( "jappix-mini" , "settings_identifier" , settings _identifier ) ;
2012-04-16 21:16:24 +02:00
// set HOST_BOSH
if ( proxy )
HOST _BOSH = proxy + "?host_bosh=" + encodeURI ( bosh ) ;
else
HOST _BOSH = bosh ;
2012-04-15 22:57:25 +02:00
// start jappix mini
MINI _NICKNAME = nickname ;
2012-04-16 21:16:24 +02:00
LOCK _HOST = "off" ;
2012-04-15 22:57:25 +02:00
launchMini ( true , false , server , username , password ) ;
2012-04-16 23:38:00 +02:00
// increase priority over other Jabber clients
priority = 101 ;
sendPresence ( null , null , priority ) ;
2012-04-16 21:16:24 +02:00
jappixmini _manage _roster ( contacts , autoapprove , autosubscribe )
2012-04-15 22:57:25 +02:00
}
// decrypt password if necessary
2012-04-15 12:20:53 +02:00
if ( encrypted )
2012-04-15 22:57:25 +02:00
jappixmini _addon _decrypt _password ( password , handler ) ;
else
handler ( password ) ;
2012-04-13 17:05:16 +02:00
}