SMACK API In Band registration fails with forbidden error - authentication

I am using SMACK API's AccountManager class but failed to successfully create a new account. supportsAccountCreation() returns true.
The createAccount method fails with the following error.
D/SMACK: SENT (0): <iq to='xmpp.jp' id='e740L-48' type='set'><query xmlns='jabber:iq:register'><username>MY_NEW_USER</username><password>**********************</password></query></iq>
D/SMACK: RECV (0): <iq from='xmpp.jp' id='e740L-48' type='error'><query xmlns='jabber:iq:register'><username>MY_NEW_USER</username><password>*****************</password></query><error code='403' type='auth'><forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>
W/System.err: org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPPError: forbidden - auth
W/System.err: at org.jivesoftware.smack.PacketCollector.nextResultOrThrow(PacketCollector.java:232)
W/System.err: at org.jivesoftware.smack.PacketCollector.nextResultOrThrow(PacketCollector.java:213)
W/System.err: at org.jivesoftware.smackx.iqregister.AccountManager.createAccount(AccountManager.java:272)
W/System.err: at org.jivesoftware.smackx.iqregister.AccountManager.createAccount(AccountManager.java:244)
..
D/SMACK: SENT (0): <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='SCRAM-SHA-1'>*****************************************</auth>
D/SMACK: RECV (0): <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>
UPDATE: Code added here
API v4.1.5
private void initialiseConnection() {
Log.d("xmpp", "Initialising connection");
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder();
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
config.setServiceName(getServer());
config.setHost(getServer());
config.setPort(getPort());
config.setDebuggerEnabled(true);
config.setSendPresence(true);
XMPPTCPConnection.setUseStreamManagementResumptionDefault(true);
XMPPTCPConnection.setUseStreamManagementDefault(true);
connection = new XMPPTCPConnection(config.build());
connection.addConnectionListener(new XMPPConnectionStateHandler(this));
connection.addConnectionListener(new XMPPAccountLoginHandler(this));
connection.addConnectionListener(new XMPPOfflineMessageHandler(this));
connection.addConnectionListener(new XMPPPingMessageHandler(this));
connection.addConnectionListener(new XMPPReconnectionHandler(this));
connection.addConnectionListener(new XMPPPresenceHandler(this));
connection.addConnectionListener(new XMPPDeliveryReceiptHandler(this));
}
public void connect(final String caller) {
if (ConnectionManagerHelper.hasDataConnection(context)){
Log.d(TAG, "Data connection fine");
} else {
Log.d(TAG, "Data connection not avaiable");
}
AsyncTask<Void, Void, Boolean> connectionThread = new AsyncTask<Void, Void, Boolean>() {
#Override
protected synchronized Boolean doInBackground(Void... arg0) {
if (connection.isConnected()) return false;
isconnecting = true;
Log.d("Connect() Function", caller + "=>connecting....");
try {
connection.connect();
connected = true;
notifyConnectionEstablishedEvent();
} catch (IOException e) {
Log.e(TAG, "(" + caller + ")" + " IOException: " + e.getMessage());
notifyConnectionFailureEvent();
} catch (final SmackException e) {
Log.e(TAG, "(" + caller + ")" + " SMACKException: " + e.getMessage());
notifyConnectionFailureEvent();
} catch (final XMPPException e) {
Log.e(TAG, "(" + caller + ")" + " XMPPException: " + e.getMessage());
notifyConnectionFailureEvent();
}
return isconnecting = false;
}
};
connectionThread.execute();
}
public void login() {
try {
connection.addAsyncStanzaListener(new StanzaListener() {
#Override
public void processPacket(Stanza packet) throws NotConnectedException {
Log.d(TAG, packet.toXML().toString());
notifyMessageStatusReceivedEvent(packet);
}
}, new StanzaFilter() {
#Override
public boolean accept(Stanza stanza) {
return true;
}
});
Log.d(TAG, "Attempting to login as " + loginUser);
connection.login(loginUser, passwordUser);
notifyConnectionConnectedEvent();
} catch (SmackException.AlreadyLoggedInException e){
Log.d(TAG, "Already logged on to chat server");
} catch (XMPPException | SmackException | IOException e) {
e.printStackTrace();
//if first login failed, try to create an account and then login
Log.d(TAG, "Login failed. Trying to create a new account.");
register();
}
}
public void register(){
Log.d(TAG, "Attempting to register");
try {
AccountManager accountManager = AccountManager.getInstance(connection);
if (accountManager.supportsAccountCreation()){
Log.d(TAG, "Server supports remote registration");
accountManager.sensitiveOperationOverInsecureConnection(true);
Log.d(TAG, "Sending registration request");
HashMap<String, String> attributes = new HashMap<>();
attributes.put("email", "test#gmail.com");
accountManager.createAccount(loginUser, passwordUser, attributes);
} else {
Log.w(TAG, "Server does not support remote registrations");
}
} catch (XMPPException | SmackException e) {
e.printStackTrace();
}
}
I have spent 3 days already googl-ing and stackoverflow-ing.
Has someone seen and fixed this already?

You have to set access rules for registering new user. I have attached here the complete access rules. You can add this by clicking raw in access rules.
[{access,announce,[{allow,[{acl,admin}]}]},
{access,c2s,[{deny,[{acl,blocked}]},{allow,[all]}]},
{access,c2s_shaper,[{none,[{acl,admin}]},{normal,[all]}]},
{access,configure,[{allow,[{acl,admin}]}]},
{access,local,[{allow,[{acl,local}]}]},
{access,max_user_offline_messages,[{5000,[{acl,admin}]},{100,[all]}]},
{access,max_user_sessions,[{10,[all]}]},
{access,mod_register,[{access_from,register_from},{access,register}]},
{access,register,[{allow,[{acl,local}]}]},
{access,muc_create,[{allow,[{acl,local}]}]},
{access,pubsub_createnode,[{allow,[{acl,local}]}]},
{access,register,[{allow,[all]}]},
{access,register_from,[{allow,[all]}]},
{access,s2s_shaper,[{fast,[all]}]},
{access,trusted_network,[{allow,[{acl,loopback}]}]}]

The below code worked for me,
AccountManager accountManager = AccountManager.getInstance(connection);
try {
if (accountManager.supportsAccountCreation()) {
accountManager.sensitiveOperationOverInsecureConnection(true);
accountManager.createAccount("name", "password");
}
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}

Related

Renci.SshNet : "server response does not contain ssh protocol identification"

I'm working with the Renci SSH.Net library on a WPF application and I'm having an issue with using the SFTP client. When the user tries to connect to download some files from the SFTP server he gets the message shown below:
Server response does not contain ssh protocol identification
It doesn't appear to be something specific with the server as I'm able to connect and download the files just fine on my development desktop and a secondary laptop. The same application is able to connect over SSH and run commands without issue, it's just the SFTP connection that appears to be the problem. I'm looking for a little guidance as to where to begin troubleshooting this.
Code for SFTP shown below:
void DownloadPlogs()
{
try
{
SftpClient SFTP;
if (GV.UseCustomPort && GV.CustomPort > 0 && GV.CustomPort < 65535)
{
SFTP = new SftpClient(GV.IpAddress, GV.CustomPort, GV.Username, GV.Password);
}
else
{
SFTP = new SftpClient(GV.IpAddress, 22, GV.Username, "");
}
SFTP.Connect();
DownloadDirectory(SFTP, "/PLOG", Directory.GetCurrentDirectory() + #"\PLOG");
ZipFile.CreateFromDirectory("PLOG", String.Format("{0} - {1} PLOGS.zip", GV.IpAddress, DateTime.Now.ToString("yyyyMMddHHmmss")));
Directory.Delete(Directory.GetCurrentDirectory() + #"\PLOG", true);
SFTP.Disconnect();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Getting PLOGS");
}
}
void DownloadDirectory(SftpClient Client, string Source, string Destination)
{
var Files = Client.ListDirectory(Source);
foreach (var File in Files)
{
if (!File.IsDirectory && !File.IsSymbolicLink)
{
DownloadFile(Client, File, Destination);
}
else if (File.IsSymbolicLink)
{
//Ignore
}
else if (File.Name != "." && File.Name != "..")
{
var Dir = Directory.CreateDirectory(System.IO.Path.Combine(Destination, File.Name));
DownloadDirectory(Client, File.FullName, Dir.FullName);
}
}
}
void DownloadFile(SftpClient Client, Renci.SshNet.Sftp.SftpFile File, string Directory)
{
using (Stream FileStream = System.IO.File.OpenWrite(System.IO.Path.Combine(Directory, File.Name)))
{
Client.DownloadFile(File.FullName, FileStream);
}
}
Code for SSH below:
public SshConnection(string Host, int Port, string Username, string Password)
{
myClient = new SshClient(Host, Port, Username, Password);
myClient.KeepAliveInterval = new TimeSpan(0, 0, 5);
myClient.HostKeyReceived += myClient_HostKeyReceived;
myClient.ErrorOccurred += myClient_ErrorOccurred;
}
void myClient_ErrorOccurred(object sender, Renci.SshNet.Common.ExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "SSH Error Occurred");
}
void myClient_HostKeyReceived(object sender, Renci.SshNet.Common.HostKeyEventArgs e)
{
e.CanTrust = true;
}
public async void Connect()
{
Task T = new Task(() =>
{
try
{
myClient.Connect();
}
catch (System.Net.Sockets.SocketException)
{
MessageBox.Show("Invalid IP Address or Hostname", "SSH Connection Error");
}
catch (Renci.SshNet.Common.SshAuthenticationException ex)
{
MessageBox.Show(ex.Message, "SSH Authentication Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace, ex.Message);
MessageBox.Show(ex.GetType().ToString());
OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
}
});
T.Start();
await T;
if (T.IsCompleted)
{
OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
}
}
public void Disconnect()
{
try
{
myClient.Disconnect();
OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace, ex.Message);
}
}
public void SendData(string Data)
{
try
{
if (Data.EndsWith("\r\n"))
{
RunCommandAsync(Data, SshCommandRx);
}
else
{
RunCommandAsync(String.Format("{0}\r\n",Data), SshCommandRx);
}
//SshCommand Command = myClient.RunCommand(Data);
//OnDataReceived(this, new DataEventArgs(Command.Result));
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace, ex.Message);
}
}
private async void RunCommandAsync(String Data, SshCommandCallback Callback)
{
Task<SshCommand> T = new Task<SshCommand>(() =>
{
try
{
SshCommand Command = myClient.RunCommand(Data);
return Command;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.GetType().ToString());
return null;
}
});
T.Start();
await T;
if (T.IsCompleted)
{
Callback(this, T.Result);
}
}
private void SshCommandRx(SshConnection C, SshCommand Command)
{
if (Command != null)
{
string Rx = Command.Result;
//if (Rx.StartsWith(Command.CommandText))
//{
// Rx = Rx.Remove(0, Command.CommandText.Length);
//}
while (Rx.EndsWith("\r\n\r\n") == false)
{
Rx += "\r\n";
}
OnDataReceived(this, new DataEventArgs(Rx));
}
}
I solve it for my self only with connections retrying attempts. Didn't find what exactly the issue is, but have this connection issue many times.
Example:
int attempts = 0;
do
{
try
{
client.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
attempts++;
}
} while (attempts < _connectiontRetryAttempts && !client.IsConnected);
I experienced the same odd error message when attempting to connect to a SFTP server while using the SSH.NET library in a program on the server. The problem did not appear while testing from my development machine.
The solution was to have our server team add the IP address of the server into the hosts.allow file on the SFTP Linux server.

IOException Error on Putting Uri Source In Media Player (setDataSource)

Getting an IOException Error While Putting Uri Source Into An Object Of MediaPlayer Using setDataSource. Trying To Get Uri Of A Song From Mobile Using
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 10);
onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK && requestCode == 10){
Uri uriSound=data.getData();
Toast.makeText(getApplicationContext(),"It Came Here",Toast.LENGTH_SHORT).show();
play_sound(uriSound);
}
}
play_sound
private void play_sound( Uri uri) {
Toast.makeText(getApplicationContext(),"It Came Here 2" + uri,Toast.LENGTH_LONG).show();
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(getApplicationContext(), uri);
mp.start();
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(),"Error 1",Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(),"Error 2",Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(),"Error 3",Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
Toast.makeText(getApplicationContext(),"Error 4",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
I Used Toast To Check Where Is Error .
Getting Error In "IOException e" I Dont Know What Is It On Googling It All I Get Is That It Is SOme Kind Of " File Format" Issue Of Selected File.
Solved!! By Just Adding One Line In Play Sound
mP.setAudioStreamType(AudioManager.STREAM_MUSIC);
Play_Sound(Uri uri) :
private void Play_Sound(Uri uri)
{
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mPlayer.setDataSource(getApplicationContext(), uri);
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "You might 1 not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "You might 2 not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "You might 3 not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "You might 4 not set the URI correctly!", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
}
mPlayer.start();
}

Remote Glassfish JMS lookup

I want to connect to my Glassfish Server at XX.XX.XX.XX:XXXX which is running on a ubuntu machine on our Server.
I want to send messages and then receive them.
My Receiver looks like this:
public JMS_Topic_Receiver(){
init();
}
public List<TextMessage> getCurrentMessages() { return _currentMessages; }
private void init(){
env.put("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
env.put("org.omg.CORBA.ORBInitialHost", "10.10.32.14");
env.put("org.omg.CORBA.ORBInitialPort", "8080");
try {
ctx = new InitialContext(env); // NamingException
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void subscribeTopic(String topicName, String userCredentials) {
try {
TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) ctx.lookup("myTopicConnectionFactory");
TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
try {
String temp = InetAddress.getLocalHost().getHostName();
topicConnection.setClientID(temp);
} catch (UnknownHostException e) {
e.printStackTrace();
}
TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) ctx.lookup(topicName);
topicConnection.start();
TopicSubscriber topicSubscriber = topicSession.createDurableSubscriber(topic, userCredentials);
topicSubscriber.setMessageListener(new MyMessageListener());
}
catch(NamingException | JMSException ex)
{
ex.printStackTrace();
}
}
And my Sender looks like this:
public JMS_Topic_Sender(){
init();
}
private void init(){
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("org.omg.CORBA.ORBHost","10.10.32.14");
env.put("org.omg.CORBA.ORBPort","8080");
try {
ctx = new InitialContext(env);
} catch (NamingException e) {
e.printStackTrace();
}
}
public void sendMessage(String message, String topicName) {
try {
TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) ctx.lookup("myTopicConnectionFactory");
if (topicConnectionFactory != null) {
TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) ctx.lookup(topicName);
topicConnection.start();
TopicPublisher topicPublisher = topicSession.createPublisher(topic);
TextMessage tm = topicSession.createTextMessage(message);
topicPublisher.send(tm);
topicSession.close();
topicConnection.stop();
topicConnection.close();
}
} catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
}
}
I got most of this code from various tutorials online.
Now when I want to do the lookup aka. -> ctx.lookup("myTopicConnectionFactory");
I get all sorts of errors thrown:
INFO: HHH000397: Using ASTQueryTranslatorFactory
org.omg.CORBA.COMM_FAILURE: FEIN: 00410008: Connection abort vmcid: OMG minor code: 8 completed: Maybe
javax.naming.NamingException: Lookup failed for 'myTopicConnectionFactory' in SerialContext ........
My question here is, how do I do the lookup correctly?
My guess is that my Propertys (env) are incorrect and I need to change thouse, but I dont know to what?
Also, it works if i run my Glassfish localy on my own Computers localhost.
When im using localhost as adress and 8080 as port.

Writing a mock function for testing a login application

I am making the authentication of my android application, I want to send the entered password & email in json format then my web service is going to test if they are correct then it will return the result in json format also.
But before doing this, I want to make a mock function that replace my webservice and do this just to test before .
Here is the code
After making the validation of interface(Email & password are valid )
mock class
if(fault==false)
//new AttemptLogin().execute();
new GetUser().execute();
My class GetUser is here (the mock class that will replace my web service )
private class GetUser extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Please wait...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
String e2=email.getText().toString();
String p2=password.getText().toString();
if (e2 != null && p2!=null) {
try {
JSONObject jsonObj1 = new JSONObject(e2);
JSONObject jsonObj2 =new JSONObject(p2);
UserEmail=jsonObj1.getJSONObject(TAG_Email);
UserPassword=jsonObj2.getJSONObject(TAG_Password);
Toast.makeText(getApplicationContext(),"hi",
Toast.LENGTH_LONG).show();
String c=checkLogin(UserEmail, UserPassword);
Toast.makeText(getApplicationContext(),c,
Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
protected void onPostExecute(String result) {
// dismiss the dialog once product deleted
if (pDialog.isShowing())
pDialog.dismiss();
if (result != null){
Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
}
And this is the method checkLogin that check if the user has logged with the right email & password .
protected String checkLogin(JSONObject UserEmail,JSONObject UserPassword) {
String e ;
String p;
String r="";
try {
e= UserEmail.getString(TAG_Email);
p = UserPassword.getString(TAG_Password);
if (e.equals("exemple.android#yahoo.fr") &&
p.equals("123456")) {
Toast.makeText(getApplicationContext(), "Hello imene!",
Toast.LENGTH_SHORT).show();
r="ok";
} else {
Toast.makeText(getApplicationContext(), "Seems like you 're not imene!",
Toast.LENGTH_LONG).show();
numberOfRemainingLoginAttempts--;
Toast.makeText(getApplicationContext(), "number of Remaining login Attemts ="+numberOfRemainingLoginAttempts,
Toast.LENGTH_LONG).show();
if (numberOfRemainingLoginAttempts == 0) {
validate.setEnabled(false);
Toast.makeText(getApplicationContext(), "Login Locked!",
Toast.LENGTH_LONG).show();
r="ko";
}
}
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return r;
}`
But ,i don't have any result .Can any one tell me where is the problem in my code .

com.google.android.voicesearch.speechservice.ConnectionException: Failed to establish connection

I am testing an app that makes voice recognition, but now I am getting this error:
11-04 16:25:58.249: E/ServerConnectorImpl(13716): Failed to create TCP connection
11-04 16:25:58.249: E/ServerConnectorImpl(13716): com.google.android.voicesearch.speechservice.ConnectionException: Failed to establish connection
11-04 16:25:58.249: E/ServerConnectorImpl(13716): at com.google.android.voicesearch.tcp.TcpConnectionImpl.<init>(TcpConnectionImpl.java:87)
....
Here is my code:
sr = SpeechRecognizer.createSpeechRecognizer(getApplicationContext());
MyRecognition listener = new MyRecognition();
sr.setRecognitionListener(listener);
Class MyRecognition that implements the methods from RecognitionListener
class MyRecognition implements RecognitionListener{
public void onBeginningOfSpeech() {
}
public void onBufferReceived(byte[] buffer) {
}
public void onEndOfSpeech() {
}
public void onError(int error) {
MediaPlayer mp = new MediaPlayer();
AssetFileDescriptor asset;
try {
asset = getAssets().openFd("error.mp3");
mp.setDataSource(asset.getFileDescriptor(), asset.getStartOffset(), asset.getLength());
asset.close();
mp.prepare();
mp.start();
mp.setOnCompletionListener(AddActivity.this);
} catch (IOException e) {
e.printStackTrace();
}
}
....
public void onResults(Bundle results) {
....
}
....
}
The method that makes the voice recognition
private void reconheceVoz(final MediaPlayer mp){
try{
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "com.br.test");
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
sr.startListening(intent);
mp.release();
}
catch(Exception e){
Toast.makeText(AdicaoActivity.this, "Erro: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
This error occurs often? How can I treat it?
Thanks.