var Session; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; Session = (function() { function Session() { this.xmpp = new Strophe.Connection('/xmpp'); this.roster = {}; this.listeners = { card: [], message: [], presence: [], roster: [] }; } Session.prototype.connect = function(jid, password, callback) { return this.xmpp.connect(jid, password, __bind(function(status) { switch (status) { case Strophe.Status.AUTHFAIL: case Strophe.Status.CONNFAIL: return callback(false); case Strophe.Status.CONNECTED: this.xmpp.addHandler((__bind(function(el) { return this.handleIq(el); }, this)), null, 'iq'); this.xmpp.addHandler((__bind(function(el) { return this.handleMessage(el); }, this)), null, 'message'); this.xmpp.addHandler((__bind(function(el) { return this.handlePresence(el); }, this)), null, 'presence'); callback(true); return this.findRoster(__bind(function() { this.notify('roster'); this.xmpp.send(this.xml('')); return this.findCards(); }, this)); } }, this)); }; Session.prototype.disconnect = function() { return this.xmpp.disconnect(); }; Session.prototype.onCard = function(callback) { return this.listeners['card'].push(callback); }; Session.prototype.onRoster = function(callback) { return this.listeners['roster'].push(callback); }; Session.prototype.onMessage = function(callback) { return this.listeners['message'].push(callback); }; Session.prototype.onPresence = function(callback) { return this.listeners['presence'].push(callback); }; Session.prototype.connected = function() { return this.xmpp.jid && this.xmpp.jid.length > 0; }; Session.prototype.jid = function() { return this.xmpp.jid; }; Session.prototype.bareJid = function() { return this.xmpp.jid.split('/')[0]; }; Session.prototype.uniqueId = function() { return this.xmpp.getUniqueId(); }; Session.prototype.avatar = function(jid) { var card; card = this.loadCard(jid); if (card && card.photo) { return "data:" + card.photo.type + ";base64," + card.photo.binval; } else { return '/lib/images/default-user.png'; } }; Session.prototype.loadCard = function(jid) { var found; jid = jid.split('/')[0]; found = localStorage['vcard:' + jid]; if (found) { return JSON.parse(found); } }; Session.prototype.storeCard = function(card) { return localStorage['vcard:' + card.jid] = JSON.stringify(card); }; Session.prototype.findCards = function() { var contacts, jid, jids, success; jids = (function() { var _ref, _results; _ref = this.roster; _results = []; for (jid in _ref) { contacts = _ref[jid]; if (!this.loadCard(jid)) { _results.push(jid); } } return _results; }).call(this); if (!this.loadCard(this.bareJid())) { jids.push(this.bareJid()); } success = __bind(function(card) { this.findCard(jids.shift(), success); if (card) { this.storeCard(card); return this.notify('card', card); } }, this); return this.findCard(jids.shift(), success); }; Session.prototype.findCard = function(jid, callback) { var node; if (!jid) { return; } node = this.xml("\n \n"); return this.sendIQ(node, function(result) { var bin, card, photo, type, vcard; card = $('vCard', result); photo = $('PHOTO', card); type = $('TYPE', photo).text(); bin = $('BINVAL', photo).text(); photo = type && bin ? { type: type, binval: bin.replace(/\n/g, '') } : null; vcard = { jid: jid, photo: photo, retrieved: new Date() }; return callback(card.size() > 0 ? vcard : null); }); }; Session.prototype.parseRoster = function(node) { return $('item', node).map(function() { return new Contact(this); }).get(); }; Session.prototype.findRoster = function(callback) { var node; node = this.xml("\n \n"); return this.sendIQ(node, __bind(function(result) { var contact, contacts, _i, _len; contacts = this.parseRoster(result); for (_i = 0, _len = contacts.length; _i < _len; _i++) { contact = contacts[_i]; this.roster[contact.jid] = contact; } return callback(); }, this)); }; Session.prototype.sendMessage = function(jid, message) { var node; node = this.xml("\n \n"); $('body', node).text(message); return this.xmpp.send(node); }; Session.prototype.sendPresence = function(away, status) { var node; node = $(this.xml('')); if (away) { node.append($(this.xml('xa'))); if (status !== 'Away') { node.append($(this.xml('')).text(status)); } } else { if (status !== 'Available') { node.append($(this.xml('')).text(status)); } } return this.xmpp.send(node); }; Session.prototype.sendIQ = function(node, callback) { return this.xmpp.sendIQ(node, callback, callback, 5000); }; Session.prototype.updateContact = function(contact, add) { var group, node, _i, _len, _ref; node = this.xml("\n \n \n \n"); $('item', node).attr('name', contact.name); _ref = contact.groups; for (_i = 0, _len = _ref.length; _i < _len; _i++) { group = _ref[_i]; $('item', node).append($(this.xml('')).text(group)); } this.xmpp.send(node); if (add) { return this.sendSubscribe(contact.jid); } }; Session.prototype.removeContact = function(jid) { var node; node = this.xml("\n \n \n \n"); return this.xmpp.send(node); }; Session.prototype.sendSubscribe = function(jid) { return this.xmpp.send(this.presence(jid, 'subscribe')); }; Session.prototype.sendSubscribed = function(jid) { return this.xmpp.send(this.presence(jid, 'subscribed')); }; Session.prototype.sendUnsubscribed = function(jid) { return this.xmpp.send(this.presence(jid, 'unsubscribed')); }; Session.prototype.presence = function(to, type) { return this.xml(""); }; Session.prototype.handleIq = function(node) { var contact, contacts, ns, old, type, _i, _len; node = $(node); type = node.attr('type'); ns = node.find('query').attr('xmlns'); if (type === 'set' && ns === 'jabber:iq:roster') { contacts = this.parseRoster(node); for (_i = 0, _len = contacts.length; _i < _len; _i++) { contact = contacts[_i]; if (contact.subscription === 'remove') { delete this.roster[contact.jid]; } else { old = this.roster[contact.jid]; if (old) { contact.presence = old.presence; } this.roster[contact.jid] = contact; } } this.notify('roster'); } return true; }; Session.prototype.handleMessage = function(node) { var body, from, html, thread, to, type; node = $(node); to = node.attr('to'); from = node.attr('from'); type = node.attr('type'); thread = node.find('thread').first(); body = node.find('body').first(); html = node.find('span').first(); if (type === 'chat' && body.size() > 0) { this.notify('message', { to: to, from: from, type: type, thread: thread.text(), text: body.text(), html: html.text(), received: new Date(), node: node }); } return true; }; Session.prototype.handlePresence = function(node) { var contact, from, presence, show, status, to, type; node = $(node); to = node.attr('to'); from = node.attr('from'); type = node.attr('type'); show = node.find('show').first(); status = node.find('status').first(); presence = { to: to, from: from, status: status.text(), show: show.text(), type: type, offline: type === 'unavailable' || type === 'error', away: show.text() === 'away' || show.text() === 'xa', dnd: show.text() === 'dnd', node: node }; contact = this.roster[from.split('/')[0]]; if (contact) { contact.update(presence); } this.notify('presence', presence); return true; }; Session.prototype.notify = function(type, obj) { var callback, _i, _len, _ref, _results; _ref = this.listeners[type] || []; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { callback = _ref[_i]; _results.push(callback(obj)); } return _results; }; Session.prototype.xml = function(xml) { return $.parseXML(xml).documentElement; }; return Session; })();