PageRenderTime 27ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/southpark/application/components/jabberclient.js

https://github.com/sigmonky/LivingRoom
JavaScript | 436 lines | 286 code | 90 blank | 60 comment | 34 complexity | daef9e0bed40ac928727826a5b5a687e MD5 | raw file
  1. //
  2. // Declare namespace
  3. //
  4. //Models
  5. //=======
  6. // This is tool from [JavascriptMVC](http://javascriptmvc.com/) framework.
  7. // It used to create binded to `this` callbacks, when _.bind() can not do this.
  8. Jabber.JsmvcCallback = {
  9. callback: function( funcs ) {
  10. var makeArray = $.makeArray,
  11. isFunction = $.isFunction,
  12. isArray = $.isArray,
  13. extend = $.extend,
  14. concatArgs = function(arr, args){
  15. return arr.concat(makeArray(args));
  16. };
  17. // args that should be curried
  18. var args = makeArray(arguments),
  19. self;
  20. funcs = args.shift();
  21. if (!$.isArray(funcs) ) {
  22. funcs = [funcs];
  23. }
  24. self = this;
  25. for( var i =0; i< funcs.length;i++ ) {
  26. if(typeof funcs[i] == "string" && !isFunction(this[funcs[i]])){
  27. throw ("class.js does not have a "+funcs[i]+" method!");
  28. }
  29. }
  30. return function class_cb() {
  31. var cur = concatArgs(args, arguments),
  32. isString,
  33. length = funcs.length,
  34. f = 0,
  35. func;
  36. for (; f < length; f++ ) {
  37. func = funcs[f];
  38. if (!func ) {
  39. continue;
  40. }
  41. isString = typeof func == "string";
  42. if ( isString && self._set_called ) {
  43. self.called = func;
  44. }
  45. cur = (isString ? self[func] : func).apply(self, cur || []);
  46. if ( f < length - 1 ) {
  47. cur = !isArray(cur) || cur._use_call ? [cur] : cur;
  48. }
  49. }
  50. return cur;
  51. };
  52. }
  53. };
  54. //Contact model
  55. //--------------
  56. //Presence updated with `updatePrecense`. While updating,
  57. //program selects best status from `Jabber.Contact.Statuses`
  58. Jabber.Contact = Backbone.Model.extend({
  59. updatePrecense: function(presence){
  60. var status;
  61. if ($(presence).attr('type')) {
  62. status = $(presence).attr('type');
  63. } else {
  64. if ($(presence).find('show').length) {
  65. status = $(presence).find('show').text();
  66. } else {
  67. status = 'available';
  68. }
  69. }
  70. if (_.indexOf(Jabber.Contact.Statuses, status) > _.indexOf(Jabber.Contact.Statuses, this.status)) {
  71. this.set({status: status});
  72. }
  73. }
  74. });
  75. Jabber.Contact.Statuses = ['unavailable', 'xa', 'dnd', 'away', 'available', 'chat'];
  76. //Roster model
  77. //-------------
  78. //
  79. //It has special method to hold information about
  80. //started conversation, current manager and so on.
  81. Jabber.Roster = Backbone.Collection.extend({
  82. initialize: function(){
  83. // While conversation started, program should keep messaging only with
  84. // selected manager
  85. this._freezeManager = false;
  86. this.manager = null;
  87. this.bind('change:status', function(contact, new_status){
  88. this.updateManager();
  89. });
  90. this.bind('add', function(){
  91. this.updateManager();
  92. });
  93. // all of the object's function properties will be bound to ``this``.
  94. _.bindAll(this);
  95. },
  96. // public method
  97. freezeManager: function(){
  98. this._freezeManager = true;
  99. },
  100. updateManager: function(){
  101. if (!this._freezeManager) {
  102. this.manager = this.reduce(function(old_val, new_val){
  103. // First available:
  104. if (old_val === null){
  105. return new_val;
  106. }
  107. var new_status = _.indexOf(Jabber.Contact.Statuses, new_val.get('status')),
  108. old_status = _.indexOf(Jabber.Contact.Statuses, old_val.get('status'));
  109. if (new_status >= old_status){
  110. return new_val;
  111. } else {
  112. return old_val;
  113. }
  114. }, this.manager);
  115. }
  116. },
  117. model: Jabber.Contact
  118. });
  119. //Static method to create rosters from XMPP stanzas
  120. Jabber.Roster.serializeRoster = function(roster){
  121. res = [];
  122. $(roster).find('item').each(function(index, el){
  123. if ($(el).attr('subscription') === 'both'){
  124. res.push({
  125. jid: $(el).attr('jid'),
  126. bare_jid: Strophe.getBareJidFromJid($(el).attr('jid')),
  127. name: $(el).attr('name'),
  128. status: 'unavailable'
  129. });
  130. };
  131. });
  132. return res;
  133. };
  134. //
  135. //Main class
  136. //==========
  137. //
  138. Jabber.Xmpp = function(options) {
  139. if (!options) options = {};
  140. if (this.defaults) options = _.extend(this.defaults, options);
  141. this.options = options;
  142. this.initialize();
  143. };
  144. //Xmpp class implementation
  145. //-------------------------
  146. _.extend(Jabber.Xmpp.prototype, Jabber.JsmvcCallback, Backbone.Events, {
  147. connection:null,
  148. initialize: function(){
  149. var BOSH_SERVICE = '/http-bind';
  150. this.connection = new Strophe.Connection(BOSH_SERVICE);
  151. // Strophe.log = function (lvl, msg) { log(msg); };
  152. this.connection.attach(Attacher.JID, Attacher.SID, Attacher.RID, this.callback('onConnect'));
  153. this.connection.rawInput = function (data) {
  154. log('RECV: ' + data);
  155. };
  156. this.connection.rawOutput = function (data) {
  157. log('SENT: ' + data);
  158. };
  159. // send disco#info to jabber.org
  160. var iq = $iq({to: 'jabber.org', type: 'get',id: 'disco-1'}).c('query', {xmlns: Strophe.NS.DISCO_INFO}).tree()
  161. this.connection.send(iq);
  162. this.roster = new Jabber.Roster();
  163. this.bind('connected', this.onConnect);
  164. this.chatViews = new Array();
  165. },
  166. addView: function(jid){
  167. this.chatViews[jid].bind('send:message', this.callback('sendMessage'));
  168. },
  169. onConnect: function(){
  170. // console.log('onConnect join Room'+this.joinRoom() );
  171. this.joinRoom();
  172. this.setVcard();
  173. this.subscribeFriends();
  174. this.getFriends();
  175. console.log('subscribeFriends');
  176. var that = this;
  177. // this.connection.addHandler(this.callback('onContactPresence'), null, 'presence');
  178. this.connection.addHandler(this.callback('onPrivateMessage'), null, 'message', 'chat');
  179. this.connection.addHandler(this.callback('onGroupMessage'), null, 'message', 'groupchat');
  180. return true;
  181. },
  182. subscribeFriends: function(){
  183. var that = this;
  184. _.each(FriendsWhoInstalledApp.data, function(friend){
  185. var data = {};
  186. data.jid = friend.uid+'@'+Application.domain;
  187. data.name = friend.name;
  188. // console.log('subscribeFriends add data.name '+data.name );
  189. // console.log('subscribeFriends add data.jid '+data.jid);
  190. var iq = $iq({type: "set"}).c("query", {xmlns: "jabber:iq:roster"}).c("item", data);
  191. that.connection.send(iq);
  192. var subscribe = $pres({to: data.jid, "type": "subscribe"});
  193. that.connection.send(subscribe);
  194. })
  195. },
  196. getFriends: function(){
  197. console.log('getFriends');
  198. var roster_iq = $iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'});
  199. this.connection.sendIQ(roster_iq, this.callback('onRoster'));
  200. //this.trigger('ui:roster');
  201. // add handlers
  202. this.connection.addHandler(this.callback('onContactPresence'), null, 'presence');
  203. },
  204. joinRoom: function(){
  205. console.log('join Room');
  206. //* IF MY FACEBOOK ID */
  207. var facebook_user_id = MyFacebookUser.id;
  208. var facebook_name = MyFacebookUser.name;
  209. //* OTHERWISE JOIN AS GUEST */
  210. if (facebook_user_id == ''){
  211. var nickname = 'guest_'+Math.floor(Math.random()*9999);
  212. }else{
  213. facebook_name = facebook_name.replace(/ /g,"_")
  214. var nickname = facebook_name+'-'+facebook_user_id;
  215. }
  216. console.log('join Room facebook_name'+facebook_name);
  217. this.connection.muc.join(RoomJid, nickname);
  218. },
  219. onSetVcard: function(){
  220. console.log('onSetVcard')
  221. },
  222. setVcard: function(){
  223. console.log('setVcard');
  224. console.log('setVcard FB ID' +MyFacebookUser.id);
  225. var facebook_user_id = MyFacebookUser.id;
  226. var vCardEl = document.createElement('nickname');
  227. var text = document.createTextNode(facebook_user_id);
  228. vCardEl.appendChild(text);
  229. this.connection.vcard.set(this.callback('onSetVcard'), vCardEl, facebook_user_id+'@'+Application.domain);
  230. },
  231. onRoster: function(roster){
  232. console.log('onRoster ')
  233. this.connection.send($pres());
  234. // this.trigger('ui:ready');
  235. // this.view.setStatus(Jabber.viewstates.online);
  236. //
  237. var items = Jabber.Roster.serializeRoster(roster);
  238. for (var i=0; i<items.length; i++) {
  239. this.roster.add(items[i]);
  240. }
  241. return true;
  242. },
  243. onContactPresence: function(presence){
  244. console.log('onContactPresence from '+$(presence).attr('from'));
  245. var from = Strophe.getBareJidFromJid($(presence).attr('from'));
  246. var contact = this.roster.detect(function(c){return c.get('bare_jid') === from;});
  247. if (contact) {
  248. contact.updatePrecense(presence);
  249. }
  250. var ptype = $(presence).attr('type');
  251. console.log('onContactPresence presence type '+ptype);
  252. if (ptype === 'subscribe') {
  253. // populate pending_subscriber
  254. this.connection.send($pres({to: from, "type": "subscribed"}));
  255. this.connection.send($pres({to: from,"type": "subscribe"}));
  256. }
  257. return true;
  258. },
  259. // `sendMessage` used for send all messages
  260. sendMessage: function(message, to, type){
  261. console.log('send message');
  262. if (typeof(message) === 'string'){
  263. var msg = new models.ChatEntry({
  264. text: message,
  265. from: '',
  266. to: to,
  267. facebook_id: '',
  268. incoming: false,
  269. dt: new Date()
  270. });
  271. } else {
  272. var msg = new models.ChatEntry(message);
  273. }
  274. if (type == 'private'){
  275. msg.send(this.connection, 'private');
  276. }else{
  277. msg.send(this.connection);
  278. }
  279. },
  280. // Handler for incoming messages
  281. onGroupMessage: function(message){
  282. console.log('onGroupMessage ')
  283. /* Nickname is Equal to FB Photo ID */
  284. var photo = $(message).find('nick').text();
  285. console.log('onMessage photo' +photo);
  286. var from = $(message).attr('from');
  287. var pos = from.indexOf('/') + 1;
  288. //console.log('pos '+pos);
  289. var full_nickname = from.substring(pos,from.length);
  290. var user_nick = full_nickname.split('-')[0];
  291. var facebook_id = full_nickname.split('-')[1];
  292. user_nick=user_nick.replace(/_/g," ");
  293. console.log('onMessage photo from' +from);
  294. console.log('onMessage photo full_nickname' +full_nickname);
  295. console.log('onMessage photo user_nick' +user_nick);
  296. console.log('onMessage photo facebook_id' +facebook_id);
  297. var messageSrc = $(message).find('body').text();
  298. var formattedMsg = emoticons(messageSrc);
  299. var msg = new models.ChatEntry({
  300. text: formattedMsg,
  301. from: user_nick,
  302. to: $(message).attr('to'),
  303. facebook_id: facebook_id,
  304. incoming: true,
  305. dt: new Date()
  306. });
  307. //console.log('onmessage from = '+$(message).attr('from'));
  308. ///console.log('onmessage to = '+$(message).attr('to'));
  309. this.chatViews[RoomJid].collection.add(msg);
  310. return true;
  311. },
  312. // Handler for incoming messages
  313. onPrivateMessage: function(message){
  314. console.log('onPrivateMessage ')
  315. /* Nickname is Equal to FB Photo ID */
  316. var from = $(message).attr('from');
  317. var facebook_id = from.substring(0, from.indexOf('@'));
  318. console.log('onPrivateMessage photo from' +from);
  319. console.log('onMesonPrivateMessagesage photo facebook_id' +facebook_id);
  320. //
  321. var messageSrc = $(message).find('body').text();
  322. var formattedMsg = emoticons(messageSrc);
  323. console.log('onPrivateMessage msg' +messageSrc);
  324. var msg = new models.ChatEntry({
  325. text: formattedMsg,
  326. from: from,
  327. to: '',
  328. facebook_id: facebook_id,
  329. incoming: true,
  330. dt: new Date()
  331. });
  332. //
  333. // //console.log('onmessage from = '+$(message).attr('from'));
  334. // ///console.log('onmessage to = '+$(message).attr('to'));
  335. //
  336. // for (chat in this.chatViews){
  337. // console.log('chat view '+chat);
  338. // }
  339. this.chatViews[facebook_id].collection.add(msg);
  340. return true;
  341. },
  342. // Only trigger view event
  343. onMessageAdd: function(message){
  344. this.view.trigger('add:message', message);
  345. }
  346. });