1 Xmpp4Js.Lang.namespace( "Xmpp4Js.Roster" ); 2 3 /** 4 * @constructor 5 */ 6 Xmpp4Js.Roster.RosterItemManager = function() { 7 /** 8 * organized by jid, including resource 9 * @type Xmpp4Js.Roster.RosterEntry Array of Xmpp4Js.Roster.RosterEntry. 10 */ 11 this.map = {}; 12 13 this.addEvents({ 14 /** 15 * A new entry was added. 16 * @param {Xmpp4Js.Roster.RosterEntry} newEntry 17 */ 18 "add" : true, 19 /** 20 * An entry was updated. 21 * @param {Xmpp4Js.Roster.RosterEntry} oldEntry 22 * @param {Xmpp4Js.Roster.RosterEntry} newEntry 23 */ 24 "update" : true, 25 /** 26 * An entry was removed. 27 * @param {Xmpp4Js.Roster.RosterEntry} deletedEntry 28 */ 29 "remove" : true 30 }); 31 } 32 33 Xmpp4Js.Roster.RosterItemManager.prototype = { 34 /** 35 * Get a roster entry by JID. Roster entries are not stored by resource, 36 * so it is always stripped to a bare JID. 37 * 38 * @param {String or Xmpp4Js.Jid} jid 39 * @return Xmpp4Js.Roster.RosterEntry 40 */ 41 get: function(jid) { 42 jid = new Xmpp4Js.Jid(jid).withoutResource().toString(); 43 44 return this.map[jid]; 45 }, 46 47 /** 48 * Get a roster group by name. See documentation on 49 * return type for exact details. 50 * 51 * @param {String} name The name of the group 52 * @return Xmpp4Js.Roster.RosterGroup 53 */ 54 getGroup: function(name) { 55 var groups = this.getGroups(); 56 for( var i = 0; i < groups.length; i++ ) { 57 if( groups[i].name == name ) { 58 return groups[i]; 59 } 60 } 61 }, 62 63 /** 64 * Get an array of all groups 65 * 66 * @return Xmpp4Js.Roster.RosterGroup[] an array of Groups 67 */ 68 getGroups: function() { 69 var retGroups = []; 70 var groupNames = {}; 71 72 retGroups.push( this.getUnfiledContacts() ); 73 74 for( var k in this.map) { 75 var entry = this.map[k]; 76 for(var i = 0; i < entry.groups.length; i++) { 77 var groupName = entry.groups[i]; 78 if( groupNames[groupName] == undefined ) { 79 groupNames[ groupName ] = 1; 80 retGroups.push( new Xmpp4Js.Roster.RosterGroup( groupName, this ) ); 81 } 82 }; 83 84 }; 85 86 return retGroups; 87 }, 88 89 /** 90 * Get the special unfiled contacts group, and all entries that 91 * are not in any group. 92 * 93 * @return Xmpp4Js.Roster.RosterGroup 94 */ 95 getUnfiledContacts: function(){ 96 return new Xmpp4Js.Roster.UnfiledEntriesRosterGroup(this); 97 }, 98 99 /** 100 * Fires events after add/modify and before delete. 101 * Items are stored without taking resource into account. 102 * 103 * @param {String or Xmpp4Js.Jid} jid 104 * @param {String} alias 105 * @param {String} subscription 106 * @param {String} ask 107 * @param {String Array} groups 108 */ 109 update: function(jid, alias, subscription, ask, groups) { 110 jid = new Xmpp4Js.Jid(jid).withoutResource().toString(); 111 112 // TODO find out if this is ever sent from the server 113 if( subscription == "remove" ) { 114 this.remove(jid); 115 return; 116 } 117 var newEntry = new Xmpp4Js.Roster.RosterEntry(jid, alias, subscription, ask, groups, this); 118 var currentEntry = this.map[jid]; 119 120 // replace current entry with new one. 121 this.map[jid] = newEntry; 122 123 if( currentEntry == undefined ) { 124 this.fireEvent( "add", newEntry ); 125 } else { 126 this.fireEvent( "update", currentEntry, newEntry ); 127 } 128 129 return newEntry; 130 }, 131 132 /** 133 * Remove a contact from the roster. Fires the remove event and 134 * deletes the entry from the local map. 135 */ 136 remove: function(jid) { 137 var entry = this.map[jid]; 138 139 this.fireEvent( "remove", entry ); 140 141 delete this.map[jid]; 142 }, 143 144 /** 145 * Listens for regular roster packets and calls update as needed. 146 * 147 * FIXME This must be manually added to a connection. 148 * 149 * @param {Xmpp4Js.Packet.IQ} packet Could be class of roster packet. 150 */ 151 rosterPacketListener: function( packet ) { 152 var itemNodes = packet.getQuery().getElementsByTagName("item"); 153 for ( var i=0; i < itemNodes.getLength(); i++ ) { 154 var item = itemNodes.item(i); 155 156 var jid = item.getAttribute( "jid" ).toString(); 157 var name = item.getAttribute( "name" ).toString(); 158 var subscription = item.getAttribute( "subscription" ).toString(); // none, to, from, both, remove 159 var ask = item.getAttribute( "ask" ).toString(); // subscribe, unsubscribe 160 161 var groups = []; 162 163 var groupNodes = item.getElementsByTagName("group"); 164 for( var j = 0; j < groupNodes.getLength(); j++ ) { 165 var node = groupNodes.item(j); 166 groups.push( node.getStringValue() ); 167 } 168 169 this.update( jid, name, subscription, ask, groups ); 170 } 171 172 }, 173 174 /** 175 * Listens for roster information from legacy services. That is, 176 * these items exist on a transport's legacy roster but not necessarily 177 * in this account's native jabber roster. Calls update as needed. 178 * 179 * FIXME This must be manually added to a connection. 180 * 181 * 182 * See this document: http://delx.net.au/projects/pymsnt/jep/roster-subsync/ 183 * 184 * @param {Xmpp4Js.Packet.IQ} packet Could be class of roster packet. 185 */ 186 rosterSubSyncPacketListener: function( presence ) { 187 var subsyncNode = presence.getNode().getElementsByTagNameNS("http://jabber.org/protocol/roster-subsync", "x").item(0); 188 // TODO create a subsync packet filter. 189 if( !subsyncNode ) { 190 return; 191 } 192 193 // in subsync the JID is on the presence element, and not the item element. 194 var jid = presence.getFrom(); 195 196 var itemNodes = subsyncNode.getElementsByTagName("item"); 197 198 for ( var i=0; i < itemNodes.getLength(); i++ ) { 199 var item = itemNodes.item(i); 200 201 var name = item.getAttribute( "name" ).toString(); 202 var subscription = item.getAttribute( "subscription" ).toString(); // none, to, from, both, remove 203 var ask = item.getAttribute( "ask" ).toString(); // subscribe, unsubscribe 204 205 var groups = []; 206 207 var groupNodes = item.getElementsByTagName("group"); 208 for( var j = 0; j < groupNodes.getLength(); j++ ) { 209 var node = groupNodes.item(j); 210 groups.push( node.getStringValue() ); 211 } 212 213 this.update( jid, name, subscription, ask, groups ); 214 } 215 } 216 } 217 218 Xmpp4Js.Lang.extend( Xmpp4Js.Roster.RosterItemManager, Xmpp4Js.Event.EventProvider, Xmpp4Js.Roster.RosterItemManager.prototype); 219