I am working on android chat application using ejabberd 2.1.11. For searching whether a particular user exists or not i'm using UserSearchManager
public boolean isUserExists(IrishContact ic) {
try {
UserSearchManager search = new UserSearchManager(connection);
Collection<String> services = search.getSearchServices();
if (services.isEmpty()) {
Log.v("IrishuserSearch ", "no service found");
}
Log.v("service name: ", connection.getServiceName());
Form searchForm = search.getSearchForm("vjud."
+ connection.getServiceName());
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", ic.getPhoneNumber());
org.jivesoftware.smackx.ReportedData data = search
.getSearchResults(answerForm,
"search." + connection.getServiceName());
if (data.getRows() != null) {
Iterator<Row> it = data.getRows();
if (it.hasNext()) {
return true;
} else
return false;
} else
return false;
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
On the basis on this answer
i'm using
Form searchForm = search.getSearchForm("vjud."
+ connection.getServiceName());
instead of
Form searchForm =
search.getSearchForm("search."+connection.getServiceName());
the later part was giving 503 service not found exception so i changed my code and it got solved, but now the problem is I am getting IllegalArgumentException at
answerForm.setAnswer("Username", true);
I am using asmack-android-8-0.8.10.
STACK_TRACE=java.lang.IllegalArgumentException: Field not found for the specified variable name.
at org.jivesoftware.smackx.Form.setAnswer(Form.java:258)
at com.irishtalk.utilities.IrishUserSearch.isUserExists(IrishUserSearch.java:42)
at com.irishtalk.utilities.IrishContactsHelper.addContactToDefaultRoster(IrishContactsHelper.java:51)
at com.irishtalk.utilities.IrishContactsHelper.getRoster(IrishContactsHelper.java:32)
at com.irishtalk.service.IXmppAidlStub$1.run(IXmppAidlStub.java:221)
can anyone help me out why this is happening? Thanks
Ejabberd does not support the field value "Username". It is used in openfire. Please use the field vale "user" and pass arguments as string in ejabberd. Thanks. Please Vote up if your error is solved.
Related
Hey i am developing Chat Application using XMPP Smack Library. Recently i am working on Group Chat While sending Group message some message will be drop so receiver wouldn't receives message from the sender side. it will gives me 400 bad request.
it is working sometimes. and sometimes not work
here i found this kind of message in 400 bad request.
<?xml version="1.0" encoding="UTF-8"?>
<message to="156#abc.com/Android" id="nXlV6-1144" type="error" from="24#confrence.abc.com/156#abc.com.com">
<received xmlns="urn:xmpp:receipts" id="nXlV6-1142" />
<error code="400" type="modify">
<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
</error>
</message>
if successfully send message it will give this kind of message.
<?xml version="1.0" encoding="UTF-8"?>
<message to="156#abc.com/Android" id="nXlV6-1411" type="groupchat" from="24#conference.abc.com/156#abc.com">
<body>eyu4u4</body>
<chatDetail xmlns="jabber:x:oob">
<UID>156</UID>
<time>04:20 PM</time>
<user_icon>24_group_icon.jpg</user_icon>
<SentTime>1474368652960</SentTime>
<USERName>vasudev89</USERName>
<user_name>cryan</user_name>
<message>eyu4u4</message>
<type>group</type>
<phone_number>24</phone_number>
</chatDetail>
<request xmlns="urn:xmpp:receipts" />
</message>
how i can send message persistently? Any idea?
Thank You in Advance.
here is my code sending muc message:
public boolean sendGroupMessage(Message message, String strGroupID) {
DeliveryReceiptRequest.addTo(message);
try {
Log.i(TAG, "sendGroupMessage");
//Log.i("JOIN MUC","To join group chat: " + groupChat.getClassId());
// Get the MultiUserChatManager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(AbstractXMPPConnection);
// Create a MultiUserChat using an XMPPConnection for a room
MultiUserChat muc = manager.getMultiUserChat(strGroupID + AppWSConstants.XMPP_JID_GROUP_CHAT_SUFFIX);
muc.sendMessage(message);
return true;
} catch (NotConnectedException e) {
e.printStackTrace();
}
return false;
}
#LearnPainLess, follow these steps to solve group chat issue
-when creating groups, save the jid of group in the database, like "somegroup#conference.{domain}.com"
-create background task for creating xmpp connection (this way it will always be connected)
-after logging in to xmpp, get the group names from the database and connect to them
also, in openfire, Group Chat > Group Chat Settings > Edit Icon > Default Room Settings > Check "Make Room Persistant"
also, in other settings > Never kick idle users
I have an XmppBase class where i put all my xmpp code
All listeners in seperate folder
Connection is stored in static variable and i retrive it using
Utils.getConnection()
// this function m calling from background service and everywhere if not connectect to xmpp
public static XMPPConnection CreateXmppConnection() {
if (Utils.getConnection() == null) {
try {
Boolean isConnected = new XmppAsync(mUsername, mPassword,context).execute().get();
if (isConnected && Utils.getConnection() != null) {
RegisterConnListeners(Utils.getConnection());
updateMyProfileImg();
// connect to all groups
DBAdapter adapter = new DBAdapter(context);
adapter.openForRead();
List<UserDetail> groups = new ArrayList<>();
adapter.addAllGroups(groups);
adapter.addPastChatGroups(groups);
adapter.close();
for(UserDetail g : groups)
{
CreateXmppMUCSession(g.getGroupTemp());
}
return Utils.getConnection();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
} else
return Utils.getConnection();
}
// get muc chat manager
public static MultiUserChatManager getMucManager() {
if(mucManager != null)
return mucManager;
if (Utils.getConnection() != null) {
return MultiUserChatManager.getInstanceFor(Utils.getConnection());
} else {
if (CreateXmppConnection() != null)
return MultiUserChatManager.getInstanceFor(Utils.getConnection());
else {
Log.v("error", "Some Error Occured");
Toast.makeText(context, "Cant Connect to Xmpp", Toast.LENGTH_SHORT).show();
return null;
}
}
}
// create muc session and m passing group name - call when you open chat page
public static void CreateXmppMUCSession(String gName)
{
RegisterGroupChatListeners(gName);
}
// connect to muc if not already connected
public static void RegisterGroupChatListeners(String groupName)
{
try {
mStateManager = getChatStateManager();
multiUserChat = getMUC(groupName);
// if(multiUserChat != null) {
multiUserChat.addMessageListener(new MyMUCMessageListener());
try {
if (!multiUserChat.isJoined()) {
DiscussionHistory discussionHistory = new DiscussionHistory();
discussionHistory.setMaxStanzas(0);
multiUserChat.join(new MyPrefrence(context).getUsername().split("#")[0], "123",
discussionHistory, SmackConfiguration.getDefaultPacketReplyTimeout());
}
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
// }
}
catch (Exception ex)
{
//
}
}
// get muc
public static MultiUserChat getMUC(String groupName)
{
// Log.v("nick",multiUserChat.getNickname() + " , g = " + groupName);
// if(multiUserChat != null && multiUserChat.getRoom().contains(groupName))
// {
// return multiUserChat;
// }
if (Utils.getConnection() != null) {
MultiUserChatManager chatManager = getMucManager();
if (chatManager != null) {
return chatManager.getMultiUserChat(groupName);
} else {
Toast.makeText(context, "Cannot create Chat", Toast.LENGTH_SHORT).show();
return null;
}
} else {
if (CreateXmppConnection() != null) {
MultiUserChatManager chatManager = getMucManager();
if (chatManager != null) {
return chatManager.getMultiUserChat(groupName);
} else {
Toast.makeText(context, "Cannot create Chat", Toast.LENGTH_SHORT).show();
return null;
}
}
else {
Toast.makeText(context, "Cannot create Chat", Toast.LENGTH_SHORT).show();
return null;
}
}
}
and whenever i want to send message i just call this
public static Boolean sendMUCChatMsg(Message msg)
{
if(multiUserChat != null)
try {
multiUserChat.sendMessage(msg);
return true;
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
return false;
}
Sorry if it looks clumpsy, if I missed any function there let me know, but this is working code which i am using
try this,
I modified your last function
static MultiUserChat multiUserChat;
// call this function when you open the chat window
private void CreateGroupConnection(String strGroupID ) {
// Get the MultiUserChatManager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(AbstractXMPPConnection);
// Create a MultiUserChat using an XMPPConnection for a room
MultiUserChat multiUserChat = manager.getMultiUserChat(strGroupID + AppWSConstants.XMPP_JID_GROUP_CHAT_SUFFIX);
return multiUserChat;
}
// whenever sending message from chat call this
publilc static void sendMucMessage(Message message){
if(multiUserChat != null)
multiUserChat.sendMessage(message);
}
I am working on "seen and delivered" in MUC and facing with this issue when replying back with the same packet id, still testing but I think in your case you should move your xmpp connection to background service and after connecting to xmpp on device launch up, connect to all the muc in your database. This way you will always be connected to groups.
cause : according to me, when the other user is not connected to the muc and you send a message or when you reply to the group with the same packet id.
Note: I am using multiuserchat.sendmessage to send group message and chat.sendmessage to send message to single user
SMACK 4.1
** update **
I fixed it by creating new packet instead of modifying the one i am receiving
here is the packet
Message msgg = new Message();
msgg.setBody(message.getPacketID());
msgg.setSubject(MessageModel.CHAT_STATUS_SEEN + "");
XmppBase.sendMUCChatMsg(msgg);
in your case, try with simple packet first. if all works well, then add extension one by one and see where you get the error, Thanks
Can someone please point a link where i can easily understand how to use GCM for device to device notification. What is required to make device as server and receiver.
Let me explain my requirement , you guys might have a better solution to my problem
I want to send a notification(pre defined message) to one or group of people on a button click, the other user can do the same.
Thanks
Let me try to explain the basic working
You need- A server and two mobile phones
Step 1 You have a server that both the phones connect to.
Step 2 You go to Google Developers page at this link
Step 3 You create a new project there and then add a GCM API to your project. Save the sender_id of the project. Also check the credentials of the API and add a new browser key and save that key.
Step 4 Add GCM to your project. For that, goto the root directory where your Eclipse is installed. Then navigate to the folder extras/google/google-play-services/libsproject/ and then copy the folder that is there to another location. Then import that folder into your workspace in Eclipse and change its properties to make it a library. Then add this to your app project.
Step 5 You need to register your mobile with GCM. For that you can work with a sample code like this
// to start process
public void registerDevice() {
// TODO Auto-generated method stub
try {
if (checkPlayServices()) {
regid = getRegistrationId();
if (regid.isEmpty()) { // creating a new reg id
registerInBackground();
} else
saveid();
} else{
}
} catch (Exception e) {
}
}
// to create a new id
private void registerInBackground() {
// TODO Auto-generated method stub
try {
AsyncRegister logMeIn = new AsyncRegister("<you project id here>", context);
logMeIn.doneWith = this;
logMeIn.execute();
System.out.println("execute complete");
} catch (Exception e) {
}
}
// to fetch stored registration id
private String getRegistrationId() {
// TODO Auto-generated method stub
try {
int i=myPrefs.getInt("cuid", 0);
if(id!=i){
myPrefs.edit().putInt("cuid", id).commit();
int registeredVersion = myPrefs.getInt("appversion",
Integer.MIN_VALUE); // to check if app is updated
int currentVersion = getAppVersion();
if (registeredVersion != currentVersion) {
myPrefs.edit().putInt("appversion",currentVersion).commit();
}
return "";
}
String registrationId = myPrefs.getString("regid", "");
if (registrationId.isEmpty()) {
return "";
}
int registeredVersion = myPrefs.getInt("appversion",
Integer.MIN_VALUE); // to check if app is updated
int currentVersion = getAppVersion();
if (registeredVersion != currentVersion) {
myPrefs.edit().putInt("appversion", currentVersion).commit();
return "";
}
// when id is stored previously then this is called
return registrationId;
} catch (Exception e) {
}
}
//to fetch the current app version
private int getAppVersion() throws NameNotFoundException {
// TODO Auto-generated method stub
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return packageInfo.versionCode;
}
// to check if play services are there on the device
private boolean checkPlayServices() {
// TODO Auto-generated method stub
try {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
toSend = new Bundle();
//tell user google play needs to be updated
} else {
//tell user their system does not support GCM
}
myPrefs.edit().putBoolean("support", false).commit();
return false;
}
myPrefs.edit().putBoolean("support", true).commit();
return true;
} catch (Exception e) {
}
}
Step 6 Save the registration ID and pass it to your server to save it.
Step 7 When user clicks the send button, pass a message to your server. The server will pull out the list of ids stored with the DB and will then push the message to GCM along with those ids.
Step 8 Now GCM will send that message to all the phones whose ids were given to it.
Step 9 Add a receiver in your app that receives the text from GCM and then displays it to the user.
This is a brief explanation. If you want to understand this in details please read online tutorials. Else you can also text me on my group (link you will find in my profile description) and i will gladly help you out.
String postData = "{ \"registration_ids\": [ \"" + OtherDeviceToken+ "\" ], " +
"\"delay_while_idle\": true, " +
"\"data\": {\"tickerText\":\"Your title\", "+
"\"contentTitle\":\"AppName\", " +
"\"message\": \" " + edtYourMessage.getText().toString() + "\"}}";
MediaType JSON= MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSON, postData);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://android.googleapis.com/gcm/send")
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "key=" + SERVER_API_KEY)
.post(body)
.build();
Execute the okkhttp request.
i have a openfire server running on my localhost and i am successfully able to send and receive messages to registered users. however i am not been able to get all users from server. i am logged in with user that doesn't have a administration access. so do i need to give any permission on server side?
The code i am using for getting all users is..
if ( xmpp.getConnection()== null || !xmpp.getConnection().isConnected())
return;
try {
UserSearchManager usm = new UserSearchManager(xmpp.getConnection());
Form searchForm = usm.getSearchForm("search." + xmpp.getConnection().getServiceName());
Form answerForm = searchForm.createAnswerForm();
UserSearch userSearch = new UserSearch();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", userName);
ReportedData data = userSearch.sendSearchForm(xmpp.getConnection(), answerForm, "search." + xmpp.getConnection().getServiceName());
for (ReportedData.Row row : data.getRows())
{
arrayList.add(row.getValues("Username").toString());
}
} catch (Exception e) {
e.printStackTrace();
}
i tried some solutions that shows to use Roster class, however that is also not helping me. Can anyone show what i am doing wrong or if i need to give any permission as i am not logged in as admin?
The error i am getting is..
org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPPError: remote-server-not-found
Thanks :)
This is how I am getting all users from openfire
You actually have to pass wildcard(*) for the username
Here's the working code
Utils.getConnection() - my xmpp connection
public static void getAllXmppUsers()
{
try {
UserSearchManager manager = new UserSearchManager(Utils.getConnection());
String searchFormString = "search." + Utils.getConnection().getServiceName();
Log.d("***", "SearchForm: " + searchFormString);
Form searchForm = null;
searchForm = manager.getSearchForm(searchFormString);
Form answerForm = searchForm.createAnswerForm();
UserSearch userSearch = new UserSearch();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", "*");
ReportedData results = userSearch.sendSearchForm(Utils.getConnection(), answerForm, searchFormString);
if (results != null) {
List<ReportedData.Row> rows = results.getRows();
for (ReportedData.Row row : rows) {
Log.d("***", "row: " + row.getValues("Username").toString());
}
} else {
Log.d("***", "No result found");
}
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
Try this code. I tweak this code from this answer
UserSearchManager usm= new UserSearchManager(xmpp.getConnection());
Form searchForm = usm.getSearchForm("search." +xmpp.getConnection().getServiceName());
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", userName);
ReportedData data = usm
.getSearchResults(answerForm, "search." + xmpp.getConnection().getServiceName());
if (data.getRows() != null) {
for (ReportedData.Row row: data.getRows()) {
for (String jid:row.getValues("jid")) {
System.out.println(jid);
}
}
}
Smack is used to create a client. A client is used by one user. A user typically does not have access to all users of the server. Users do have contact lists, or rosters though, where you an add other users.
I'm developing chat application, In which I'm using openfire server and asmack library. I want to search users who was registered on that server.
Here is the code which I have written..
UserSearchManager search = new UserSearchManager(connection);
try {
Log.d("JWP", "cc:"+connection.getServiceName());
org.jivesoftware.smackx.Form searchForm = search.getSearchForm("search."+connection.getServiceName());
org.jivesoftware.smackx.Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", editTextSearch.getText().toString());
org.jivesoftware.smackx.ReportedData data;
data = search.getSearchResults(answerForm,"search."+connection.getServiceName());
if(data.getRows() != null){
Iterator<org.jivesoftware.smackx.ReportedData.Row> it = data.getRows();
while(it.hasNext()){
org.jivesoftware.smackx.ReportedData.Row row = it.next();
Iterator iterator = row.getValues("jid");
if(iterator.hasNext()){
String value = iterator.next().toString();
Log.i("Iteartor values......"," "+value);
}
}
Toast.makeText(Welcome.this,"Username Exists",Toast.LENGTH_SHORT).show();
}
}
catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
But here getSerachFrom() method returns null value, have tried various things but don't understand why this is happening.
My openfire server having number of registered users.
I want to get first and last name of a google account using gdata library. I have the auth token(I take it from android device - send it to my java servlet- then should add an insert into a mysql db with first, last, display name and provider_uid(provider_uid is the form of https://www.google.com/accounts/o8/id?id=AItOawmyn...)).
I used Contacts feed like this(without success):
public String tryGoogleAuthentication(String auth_token){
ContactsService contactsService = new ContactsService("...");
contactsService.setUserToken(auth_token);
//contactsService.setAuthSubToken(auth_token);
ContactFeed feed = null;
try {
feed = contactsService.getFeed(new URL("https://www.google.com/m8/feeds/contacts/" + "someEmail#gmail.com" + "/full?max-results=10000"), ContactFeed.class);
} catch (IOException e) {
e.printStackTrace();
return CONST.GOOGLE_AUTH_INVALID_TOKEN;
} catch (ServiceException e) {
e.printStackTrace();
return CONST.GOOGLE_AUTH_INVALID_TOKEN;
} catch (NullPointerException e) {
e.printStackTrace();
return CONST.GOOGLE_AUTH_INVALID_TOKEN;
}
if (feed == null)
return "";
String externalId = feed.getId();
Person person = feed.getAuthors().get(0);
String email = person.getEmail();
String name = person.getName();
String nameLang = person.getNameLang();
String extensionLocalName = person.getExtensionLocalName();
String uri = person.getUri();
System.out.println("externalId: " + externalId);
System.out.println("email: " + email);
System.out.println("name: " + name);
System.out.println("nameLang: " + nameLang);
System.out.println("extension local name: " + extensionLocalName);
System.out.println("URI: " + uri);
System.out.println(feed.getSelf().getEntries().get(0).getTitle().getPlainText());
return CONST.STATUS_OK;
}
Also,
System.out.println("ID: " + feed.getSelf().getEntries().get(0).getId());
will output:
ID: http://www.google.com/m8/feeds/contacts/someEmail%40gmail.com/base/c....
but I want something like this:
https://www.google.com/accounts/o8/id?id=AItOawmyn...
I need this to insert into an existing data base.
Please note that I want the info only for the account, not for it's contacts.
Thanks,
Alex
Please see this answer from google groups for resolution. The problem is that I cannot access user profile with the auth_token taken from the android because it's a Client Login token, and Client Login does not have a scope for accessing user's profile. I integrated OAUTH login in android like this and with the token returned, I can access user's profile.
Alex.