I want to register as new users to the xmpp server (Openfire) through the android client and all the new users must be communicated. I create the users, but I'm not sure how to add these to the roster entries to start to talk. I dont know if its better to create a group and add all contacts, but I neither know how to do it.
try {
con.connect();
AccountManager am = con.getAccountManager();
am.createAccount(USERNAME, PASSWORD);
Log.i(TAG,"Creation complete");
}
catch (XMPPException e) {
Log.e(TAG,"Error at user creation "+e);
return false;
}
Can anyone please suggest me how to attain this... Any help will be grately appreciated...!!!
You add contacts to your roster by sending presence packets. See section "Adding Entries to the Roster" on http://www.igniterealtime.org/builds/smack/docs/latest/documentation/roster.html
And then you can add them to a Roster group: http://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/RosterGroup.html
Related
I have successfully created a user using the following code:
accountmanager = new org.jivesoftware.smack.AccountManager(connection);
accountmanager.createAccount(fbuserid,fbuserid);
But I am not able to add other users to the logged in user's roster using the following code :
public void createEntry(String user, String name, String[] groups) throws XMPPException {
// Create and send roster entry creation packet.
RosterPacket rosterPacket = new RosterPacket();
rosterPacket.setType(IQ.Type.SET);
RosterPacket.Item item = new RosterPacket.Item(user, name);
if (groups != null) {
for (String group : groups) {
if (group != null) {
item.addGroupName(group);
}
}
}
rosterPacket.addRosterItem(item);
// Wait up to a certain number of seconds for a reply from the server.
PacketCollector collector = connection.createPacketCollector(
new PacketIDFilter(rosterPacket.getPacketID()));
connection.sendPacket(rosterPacket);
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
// Create a presence subscription packet and send.
Presence presencePacket = new Presence(Presence.Type.subscribe);
presencePacket.setTo(user);
connection.sendPacket(presencePacket);
}
I am always getting the response as null. Someone please help me to solve this and Thanks in advance
Rosters and presence use a permissions-based model where users must give permission before they are added to someone else's roster. This protects a user's privacy by making sure that only approved users are able to view their presence information. Therefore, when you add a new roster entry it will be in a pending state until the other user accepts your request.
If another user requests a presence subscription so they can add you to their roster, you must accept or reject that request. Smack handles presence subscription requests in one of three ways:
Automatically accept all presence subscription requests.
Automatically reject all presence subscription requests.
Process presence subscription requests manually. The mode can be set using the
Roster.setSubscriptionMode(Roster.SubscriptionMode) method. Simple clients normally use one of the automated subscription modes, while full-featured clients should manually process subscription requests and let the end-user accept or reject each request. If using the manual mode, a PacketListener should be registered that listens for Presence packets that have a type of Presence.Type.subscribe.
Try this in code first to add user in roster as well as requesting the users permission.
roster = Roster.getInstanceFor(connection);
if (!roster.isLoaded())
try {
roster.reloadAndWait();
} catch (SmackException.NotLoggedInException e) {
Log.i(TAG, "NotLoggedInException");
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
Log.i(TAG, "NotConnectedException");
e.printStackTrace();
}
roster.createEntry(jID, name, null);
On other user side/ in your code after login from one user:
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
To make user status online:
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Online, Programmatically!");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
roster = Roster.getInstanceFor(connection);
In my chat application. I am using smack library , with the help of Subscription Management I have done the part of adding a friend to the Roster of a particular person.
Now I want that when some person denies the friend request, I send a UNSUBSCRIBE PACKET to the other user for the same, the friend is not deleted from the roster of the other user. It simply shows NONE subscription.
CODE:
Presence unsubscribe = new Presence(Presence.Type.unsubscribe);
unsubscribe.setTo(ABC#ABC.COM);
connection.sendPacket(unsubscribe);
How can I delete the user from the Roster of the friend. I can do it from openfire portal but don't know how to do it from code.
From the Smack forum, this code might work:
RosterPacket packet = new RosterPacket();
packet.setType(IQ.Type.SET);
RosterPacket.Item item = new RosterPacket.Item("ABC#ABC.COM", null);
item.setItemType(RosterPacket.ItemType.REMOVE);
packet.addRosterItem(item);
connection.sendPacket(packet);
This code worked for me
if(selectedRoster != null) {
Presence presence = new Presence(Presence.Type.unsubscribe);
presence.setTo(selectedRoster.getUser());
presence.setStatus("Offline");
presence.setShow("unavailable");
ConnectionController.GetInstance(this).getXMPPConnection().sendPacket(presence);
try {
roster.removeEntry(selectedRoster);
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I followed the guidlines given in the following SO question to connect to facebook chat using xmpp and I am able to connect to facebook and pull the correct number of contacts but when it prints the contacts they are all random numbers #chat.facebook.com and all return offline.
Android Facebook chat example project
public void connectToFb() throws XMPPException {
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
config.setSecurityMode(SecurityMode.required);
config.setRosterLoadedAtLogin(true);
config.setTruststorePath("/system/etc/security/cacerts.bks");
config.setTruststorePassword("changeit");
config.setTruststoreType("bks");
config.setSendPresence(false);
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, MemorizingTrustManager.getInstanceList(this), new java.security.SecureRandom());
config.setCustomSSLContext(sc);
} catch (GeneralSecurityException e) {
Log.w("TAG", "Unable to use MemorizingTrustManager", e);
}
XMPPConnection xmpp = new XMPPConnection(config);
try {
xmpp.connect();
xmpp.login("user.name", "password"); // Here you have to used only facebookusername from facebookusername#chat.facebook.com
Roster roster = xmpp.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
System.out.println("Connected!");
System.out.println("\n\n" + entries.size() + " buddy(ies):");
// shows first time onliners---->
String temp[] = new String[50];
int i = 0;
for (RosterEntry entry : entries) {
String user = entry.getUser();
Log.i("TAG", user);
}
} catch (XMPPException e) {
xmpp.disconnect();
e.printStackTrace();
}
}
It sounds like you just want to readable name, so try using
rosterEntry.getName()
which returns the users name, instead of
rosterEntry.getUser()
which returns the JID.
Not sure about your offline problem though. How are you checking? You have to set up a roster listener to get changes in presence.
Its a bug in XMPP library . There is a work around for that .
Step 1: Connect to XMPP.
Step 2: Login to facebook account through xmpp.
Step 3: get online friend list using this fql query .
SELECT uid, name, online_presence ,
sex FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me())
Then i concat address with string uid#chat.facebook.com and communicate via XMPP.
(It's not 100% clear what problem you're having regarding the online/offline thing may be a bug or something you're doing incorrectly), but you won't get back the user's actual user IDs in the response, this is mentioned in the docs:
The user's own Jabber ID (JID) is different from the Jabber ID that their contacts will see because the translation is done internally.
I am new to the use of smack library and making one chatting application. I have made upto much extent and at this step i want to ask two questions.
when i add a friend the friend got added in my list but there is not any notification sent to the FRIEND whom i have added, How to achieve the same. I have added the code below.
The second thing i want to ask is that how can I check whether the user which I am going to add is a part or member of the app or not ( mean it is on the server or not). So that the user who is not registered to the app should not be added in the friends list.
here is the code
public static boolean addFriend(String jid) {
String nickname = null;
nickname = StringUtils.parseBareAddress(jid);
RosterEntry entry4 = roster.getEntry("samsad");
if (!roster.contains(jid)) {
try {
Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo(jid);
connection.sendPacket(subscribe);
roster.createEntry(jid, nickname, null);
// Send a roster entry (any) to user2
RosterExchangeManager REM = new RosterExchangeManager(connection);
REM.send(entry4, jid);
return true;
} catch (XMPPException e) {
System.err.println("Error in adding friend");
return false;
}
} else {
return false;
}
}
Roster Exchange manager running in the service in background
/**Remotr Exchange Manager*/
RosterExchangeManager rem = new RosterExchangeManager(connection);
// Create a RosterExchangeListener that will iterate over the received roster entries
RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() {
public void entriesReceived(String from, Iterator remoteRosterEntries) {
notification("Receive==4");
while (remoteRosterEntries.hasNext()) {
try {
// Get the received entry
RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) remoteRosterEntries.next();
// Display the remote entry on the console
System.out.println(remoteRosterEntry);
// Add the entry to the user2's roster
roster.createEntry(
remoteRosterEntry.getUser(),
remoteRosterEntry.getName(),
remoteRosterEntry.getGroupArrayNames());
notification("Receive==1");
}
catch (XMPPException e) {
e.printStackTrace();
}
}
}
};
rem.addRosterListener(rosterExchangeListener);
}
else{
showToast("Connection lost-",0);
}
}
1, The problem is you must register a PacketListener for Presence.Type.subscribe before you connect to server. All the process of add and accept friend i answered in here
2, You can use UserSearch class to search for a specific user and if user is not found on server then you can assume that user is not registered on server.
I'm migrating my app from C2DM to GCM but the server on which i'll be sending the registration id will still be entertaining C2DM ids. So my question is what can I do from my app so that server can identify that this is GCM id. Google recommends to send a new bit along with registration id. How can I do that. Please give an exmaple.
Here's what you need to do if you're not using AppEngine.
In your server, you should already have a table that stores all the registration id (reg_id). You need to add another column to this table, say 'is_gcm_reg_id'. You would default all existing rows to '0' for this column since they are currently all C2DM reg_ids. You could also just create a new table to store the GCM reg_ids, if you like.
Then in your GCM enabled application, you just need to let your server know the reg_id is a GCM reg_id. You didn't mention how you upload the reg_id to your server (Web Service call? Simple POST request?). If using Web Service call, just create a new method that will be used exclusively by your new GCM-enabled app. If using POST request, just add another key value pair like 'gcm=true' and your server should look for this kvp.
Finally, you should have all the pieces needed to know the reg_id is of GCM, and update the 'is_gcm_reg_id' column field (or a new GCM table) accordingly.
Assuming you're using App Engine to implement GCM/C2DM.
In the deviceInfo entity for your App Engine there is already a "type" field. This is the field you will modify to either say "ac2dm" or "gcm".
An easy way to do this is to create a new registration request that simply passes "gcm" instead of "ac2dm". Take a look in your AppEngine project and locate the RegistrationInfo class. Look at the register() method. Simply replace "ac2dm" with "gcm".
EX:
// original
public void register() {
log.info("register " + this);
try {
doRegister(getDeviceRegistrationId(), "ac2dm", getDeviceId(), getAccountName());
} catch (Exception e) {
log.info("Got exception in registration: " + e + " - " + e.getMessage());
for (StackTraceElement ste : e.getStackTrace()) {
log.info(ste.toString());
}
}
log.info("Successfully registered");
}
// new version
public void register() {
log.info("register " + this);
try {
doRegister(getDeviceRegistrationId(), "gcm", getDeviceId(), getAccountName());
} catch (Exception e) {
log.info("Got exception in registration: " + e + " - " + e.getMessage());
for (StackTraceElement ste : e.getStackTrace()) {
log.info(ste.toString());
}
}
log.info("Successfully registered");
}
You will probably have to recompile the RPC service to get this to work.
Now, it's up to you to make sure your server checks for the "gcm" tag of the deviceInfo entity and acts accordingly. Also, read this if you haven't seen it https://developer.android.com/guide/google/gcm/c2dm.html