Android JavaMail Detect If Server Goes Offline - java

I'm currently developing an email application with a background service used in conjunction with the JavaMail Idle functionality. The background service keeps the idle functionality working by issuing a check every 29 minutes (as the server being used (Exchange server)) can sometimes drop the connection after 30 minutes of being connected.
Whilst this works perfectly, if the Exchange server is offline, then the application will continue to attempt to reconnect to the IMAP folder indefinately. I have noticed spikes in data usage between the hours of 3AM & 6AM (a typical Exchange update time).
To avoid the increased data usage, I am looking to implement functionality where the app should attempt to reconnect to the IMAP folder three times and then display a warning to the user that the server is offline and a new connection attempt will be retried in 30 minutes.
In order to achieve this, how would I be able to detect if the Exchange server is actually offline/updating & would any exceptions be thrown, if the app cannot connect to the IMAP folder? As if an exception would be thrown, then I could save a local int variable and increment it by one every time the exception is thrown and then show the alert to the user on the third time.
My current code implementation can be seen below:
public void checkInboxEmail(final String host, final String user, final String password) {
Log.d(TAG, "checkEmail");
this.host = host;
this.user = user;
this.password = password;
new Thread(new Runnable() {
#Override
public void run() {
try {
Log.d(TAG, "checkEmail - run()");
long databaseRecords;
//create properties field
Properties properties = new Properties();
properties.put("mail.store.protocol", "imaps");
properties.put("mail.imaps.ssl.trust", "*");
properties.put("mail.debug", "true");
emailSession = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password);
}
});
IMAPStore imapStore = (IMAPStore) emailSession.getStore("imaps");
// imapStore.connect();
imapStore.connect(host, user, password);
if (imapStore.isConnected()) {
Log.d("MailPush", "Successfully connected to IMAP");
} else {
Log.d("MailPush", "Not connected to IMAP");
}
final IMAPFolder folder = (IMAPFolder) imapStore.getFolder("Inbox");
folder.open(IMAPFolder.READ_WRITE);
databaseRecords = dbManager.getReceivedEmailRecordsCount();
if (databaseRecords < folder.getMessageCount()) {
Log.d(TAG, "Receiving Mail...");
receiveMail(folder.getMessages());
} else {
Log.d(TAG, "Records match.");
}
Folder[] fdr = imapStore.getDefaultFolder().list();
for (Folder fd : fdr)
System.out.println(">> " + fd.getName());
folder.addMessageCountListener(new MessageCountListener() {
public void messagesAdded(MessageCountEvent e) {
System.out.println("Message Added Event Fired");
Log.d(TAG, "MESSAGE TYPE: " + e.getType());
//ADDED = 1 & REMOVED = 2
try {
Message[] messages = e.getMessages();
System.out.println("messages.length---" + messages.length);
for (Message message : messages) {
if (!message.getFlags().contains(Flags.Flag.SEEN)) {
//Message is new (hasn't been seen) > Message Details
System.out.println("---------------------------------");
System.out.println("Email Number " + (message.getMessageNumber()));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
String from = message.getFrom()[0].toString();
String cc = InternetAddress.toString(message.getRecipients(Message.RecipientType.CC));
Log.d(TAG, "CC 1: " + cc);
Address[] recipients = message.getRecipients(Message.RecipientType.CC);
cc = InternetAddress.toString(recipients);
Log.d(TAG, "CC 2: " + cc);
//Check Encryption Details > Add SEEN Flag > Add to database
checkEncryption((MimeMessage) message, from, cc);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void messagesRemoved(MessageCountEvent e) {
System.out.println("Message Removed Event fired");
}
});
folder.addMessageChangedListener(new MessageChangedListener() {
public void messageChanged(MessageChangedEvent e) {
System.out.println("Message Changed Event fired");
}
});
startListening(folder);
//close the store and folder objects
// emailFolder.close(false);
// store.close();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void startListening(IMAPFolder imapFolder) {
Log.d(TAG, "startListening");
// We need to create a new thread to keep alive the connection
Thread t = new Thread(
new KeepAliveRunnable(imapFolder), "IdleConnectionKeepAlive"
);
t.start();
while (!Thread.interrupted()) {
Log.d(TAG, "Starting IDLE");
try {
Log.d(TAG, "Setting IDLE");
imapFolder.idle();
} catch (FolderClosedException fex) {
//Server closes connection.
Log.d(TAG, "FolderClosedException. Server potentially dropped connection. Retrying connection...");
fex.printStackTrace();
if (!isServiceRunning(MyService.class)) {
Log.d(TAG, "Service isn't running. Starting service...");
//Start service
Intent intent = new Intent(context, MyService.class);
intent.putExtra("host", host);
intent.putExtra("email", user);
intent.putExtra("password", password);
context.startService(intent);
} else {
Log.d(TAG, "Service is already running. Checking email...");
checkInboxEmail(host, user, password);
}
} catch (MessagingException e) {
//Idle isn't supported by server.
Log.d(TAG, "Messaging exception during IDLE: ");
e.printStackTrace();
}
}
// Shutdown keep alive thread
if (t.isAlive()) {
Log.d(TAG, "Interrupting thread");
t.interrupt();
}
}
private static class KeepAliveRunnable implements Runnable {
private final String TAG = getClass().getName();
private static final long KEEP_ALIVE_FREQ = 60000 * 29; // 29 minutes (Exchange connection drops after 20-30 minutes)
private IMAPFolder folder;
KeepAliveRunnable(IMAPFolder folder) {
this.folder = folder;
}
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(KEEP_ALIVE_FREQ);
// Perform a messageCount check just to keep alive the connection
Log.d(TAG, "Performing a messageCount check to keep the connection alive");
folder.getMessageCount();
} catch (InterruptedException e) {
// Ignore, just aborting the thread...
Log.d(TAG, "Interrupted...");
e.printStackTrace();
} catch (MessagingException e) {
// Shouldn't really happen...
Log.d(TAG, "Unexpected exception while keeping alive the IDLE connection");
e.printStackTrace();
}
}
}
}
private void receiveMail(Message[] messages) {
try {
System.out.println("messages.length---" + messages.length);
for (Message message : messages) {
if (!message.getFlags().contains(Flags.Flag.SEEN)) {
//Message is new (hasn't been seen) > Message Details
System.out.println("---------------------------------");
System.out.println("Email Number " + (message.getMessageNumber()));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
String from = message.getFrom()[0].toString();
String cc = InternetAddress.toString(message.getRecipients(Message.RecipientType.CC));
//Check Encryption Details > Add SEEN Flag > Add to database
checkEncryption((MimeMessage) message, from, cc);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}

If the server is up but not accepting connections, the connect will fail immediately (with an exception). If the server is down, and you've set a connect timeout, the connect will fail after the timeout (with an exception).

To clarify #BillShannon's answer, if the server host is up but Exchange is not accepting connections, the connect will fail immediately with a ConnectException: connection refused. If the server host is down, the connect will fail after the timeout with a ConnectException: connect timeout (or possibly a SocketTimeoutException), regardless of whether you've set a connect timeout, as the platform always has one.

Related

smack cannot retrieve offline messages via OfflineMessageManager

I have a problem with while getting offline messages from ejabberd server 18.01 via smack library.
I have a connector method
private static AbstractXMPPConnection connectToServer(String serverHost, Integer port, String userName, String userPassword) {
DomainBareJid xmppDomain = null;
try {
xmppDomain = JidCreate.domainBareFrom(serverHost);
} catch (XmppStringprepException e) {
System.out.println("XMPP Domain initialization exception " + e.getMessage());
return null;
}
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setXmppDomain(xmppDomain)
.setHost(serverHost)
.setPort(port)
.setDebuggerEnabled(true)
.setSendPresence(false)
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
.build();
AbstractXMPPConnection connection = new XMPPTCPConnection(config);
try {
connection.connect().login(userName, userPassword);
return connection;
} catch (XMPPException | SmackException | IOException | InterruptedException e) {
System.out.println("Something went wrong while connection to server: " + e.getMessage());
connection.disconnect();
return null;
}
}
and offline messages receiver
private XMPPConnection connection;
#Override
public void run() {
connection = Connector.getInstance();
if (connection != null) {
System.out.println("Start listening messages in the background");
String offlineMessageOffline = "Offline message is %s from %s";
OfflineMessageManager offlineMessageManager = new OfflineMessageManager(connection);
try {
if (offlineMessageManager.supportsFlexibleRetrieval()) {
offlineMessageManager.getMessages()
.forEach(message -> {
System.out.println(String.format(offlineMessageOffline, message.getBody(), message.getFrom()));
});
// offlineMessageManager.deleteMessages();
}
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException |
SmackException.NotConnectedException | InterruptedException e) {
System.out.println(String.format("Error while getting offline messages from server: by the reason %s", e.getMessage()));
}
try {
connection.sendStanza(new Presence(Presence.Type.available));
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
ChatManager chatManager = ChatManager.getInstanceFor(connection);
IncomingChatMessageListener listener = (entityBareJid, message, chat) -> {
System.out.println(String.format("Incoming message is %s from %s", message.getBody(), message.getFrom()));
};
chatManager.addIncomingListener(listener);
} else {
System.out.println("Connection has not been established. Please try to choose option 1");
}
}
I start running message listener at the background. I see that database has an offline message and in the dubug node I see that offlineMessageManager.getMessageCount() returns the proper number of offline messages but method offlineMessageManager.getMessages() returns noting. The smack version is 4.2.3 but earlier version has the same problem
UPDATED
I found a workaround because it doesn't look like a obvious solution
public class ListenMessagesFromServerCommand implements Runnable {
private XMPPConnection connection;
#Override
public void run() {
connection = Connector.getInstance();
if (connection != null) {
System.out.println("Start listening messages in the background");
String offlineMessageOffline = "Offline message is %s from %s";
OfflineMessageManager offlineMessageManager = new OfflineMessageManager(connection);
try {
if (offlineMessageManager.supportsFlexibleRetrieval() && offlineMessageManager.getMessageCount() > 0) {
List<String> messagesNodes = offlineMessageManager.getHeaders().stream()
.map(OfflineMessageHeader::getStamp)
.collect(Collectors.toList());
offlineMessageManager.getMessages(messagesNodes)
.forEach(message -> {
System.out.println(String.format(offlineMessageOffline, message.getBody(), message.getFrom()));
});
offlineMessageManager.deleteMessages();
}
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException |
SmackException.NotConnectedException | InterruptedException e) {
System.out.println(String.format("Error while getting offline messages from server: by the reason %s", e.getMessage()));
}
try {
connection.sendStanza(new Presence(Presence.Type.available));
} catch (SmackException.NotConnectedException | InterruptedException e) {
System.out.println("Error sending presence available type " + e.getMessage());
}
ChatManager chatManager = ChatManager.getInstanceFor(connection);
IncomingChatMessageListener listener = (entityBareJid, message, chat) -> {
System.out.println(String.format("Incoming message is %s from %s", message.getBody(), message.getFrom()));
};
chatManager.addIncomingListener(listener);
} else {
System.out.println("Connection has not been established. Please try to choose option 1");
}
}
}

ClassNotFoundException across different machines

I am trying to write a messaging application in java, but keep getting an error. When I run the client on server on the same device, I get the same message. However, when I run the client and server on the same device, the client can receive messages from the server, but is unable to send a message. If I do try to send a message from the separate machine, I get the following errors:
Server has close the connection: java.io.EOFException
java.lang.ClassNotFoundException: ChatMessage
I do not know what this error means, and do not know how to fix it. I would very much appreciate some help and precise instructions on how to fix this error, and prevent it in the future.
Server Class:
public class Server {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the Client
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUI sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the server
private boolean keepGoing;
private Socket socket;
/*
* server constructor that receive the port to listen to for connection as parameter
* in console
*/
public Server(int port) {
this(port, null);
}
public Server(int port, ServerGUI sg) {
// GUI or not
this.sg = sg;
// the port
this.port = port;
// to display hh:mm:ss
sdf = new SimpleDateFormat("HH:mm:ss");
// ArrayList for the Client list
al = new ArrayList<ClientThread>();
}
public void start() {
keepGoing = true;
/* create socket server and wait for connection requests */
try
{
// the socket used by the server
ServerSocket serverSocket = new ServerSocket(port);
// infinite loop to wait for connections
while(keepGoing)
{
// format message saying we are waiting
display("Server waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); // accept connection
// if I was asked to stop
if(!keepGoing)
break;
ClientThread t = new ClientThread(socket); // make a thread of it
al.add(t); // save it in the ArrayList
t.start();
}
// I was asked to stop
try {
serverSocket.close();
for(int i = 0; i < al.size(); ++i) {
ClientThread tc = al.get(i);
try {
tc.sInput.close();
tc.sOutput.close();
tc.socket.close();
}
catch(IOException ioE) {
// not much I can do
}
}
}
catch(Exception e) {
display("Exception closing the server and clients: " + e);
}
}
// something went bad
catch (IOException e) {
String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
display(msg);
}
}
/*
* For the GUI to stop the server
*/
protected void stop() {
keepGoing = false;
// connect to myself as Client to exit statement
// Socket socket = serverSocket.accept();
try {
new Socket("localhost", port);
}
catch(Exception e) {
// nothing I can really do
}
}
/*
* Display an event (not a message) to the console or the GUI
*/
private void display(String msg) {
String time = sdf.format(new Date()) + " " + msg;
if(sg == null)
System.out.println(time);
else
sg.appendEvent(time + "\n");
}
/*
* to broadcast a message to all Clients
*/
private synchronized void broadcast(String message) {
// add HH:mm:ss and \n to the message
String time = sdf.format(new Date());
String messageLf = time + " " + message + "\n";
// display message on console or GUI
if(sg == null)
System.out.print(messageLf);
else
sg.appendRoom(messageLf); // append in the room window
// we loop in reverse order in case we would have to remove a Client
// because it has disconnected
for(int i = al.size(); --i >= 0;) {
ClientThread ct = al.get(i);
// try to write to the Client if it fails remove it from the list
if(!ct.writeMsg(messageLf)) {
al.remove(i);
display("Disconnected Client " + ct.username + " removed from list.");
}
}
}
// for a client who logoff using the LOGOUT message
synchronized void remove(int id) {
// scan the array list until we found the Id
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
// found it
if(ct.id == id) {
al.remove(i);
return;
}
}
}
/*
* To run as a console application just open a console window and:
* > java Server
* > java Server portNumber
* If the port number is not specified 1500 is used
*/
public static void main(String[] args) {
// start server on port 1500 unless a PortNumber is specified
int portNumber = 1500;
switch(args.length) {
case 1:
try {
portNumber = Integer.parseInt(args[0]);
}
catch(Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Server [portNumber]");
return;
}
case 0:
break;
default:
System.out.println("Usage is: > java Server [portNumber]");
return;
}
// create a server object and start it
Server server = new Server(portNumber);
server.start();
}
/** One instance of this thread will run for each client */
class ClientThread extends Thread {
// the socket where to listen/talk
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
// my unique id (easier for deconnection)
int id;
// the Username of the Client
String username;
// the only type of message a will receive
ChatMessage cm;
// the date I connect
String date;
// Constructore
ClientThread(Socket socket) {
// a unique id
id = ++uniqueId;
this.socket = socket;
/* Creating both Data Stream */
System.out.println("Thread trying to create Object Input/Output Streams");
try
{
// create output first
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read the username
username = (String) sInput.readObject();
display(username + " just connected.");
}
catch (IOException e) {
display("Exception creating new Input/output Streams: " + e);
return;
}
// have to catch ClassNotFoundException
// but I read a String, I am sure it will work
catch (ClassNotFoundException e) {
}
date = new Date().toString() + "\n";
}
// what will run forever
public void run() {
// to loop until LOGOUT
boolean keepGoing = true;
while(keepGoing) {
// read a String (which is an object)
try {
cm = (ChatMessage) sInput.readObject();
}
catch (IOException e) {
display(username + " Exception reading Streams: " + e);
break;
}
catch(ClassNotFoundException e2) {
display(e2.toString());
break;
}
// the messaage part of the ChatMessage
String message = cm.getMessage();
// Switch on the type of message receive
switch(cm.getType()) {
case ChatMessage.MESSAGE:
broadcast(username + ": " + message);
break;
case ChatMessage.LOGOUT:
display(username + " disconnected with a LOGOUT message.");
keepGoing = false;
break;
case ChatMessage.WHOISIN:
writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
// scan al the users connected
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
}
break;
}
}
// remove myself from the arrayList containing the list of the
// connected Clients
remove(id);
close();
}
// try to close everything
private void close() {
// try to close the connection
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {}
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {};
try {
if(socket != null) socket.close();
}
catch (Exception e) {}
}
/*
* Write a String to the Client output stream
*/
private boolean writeMsg(String msg) {
// if Client is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(msg);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending message to " + username);
display(e.toString());
}
return true;
}
}
}
Client Class:
public class Client {
// for I/O
private ObjectInputStream sInput; // to read from the socket
private ObjectOutputStream sOutput; // to write on the socket
private Socket socket;
// if I use a GUI or not
private ClientGUI cg;
// the server, the port and the username
private String server, username;
private int port;
/*
* Constructor called by console mode
* server: the server address
* port: the port number
* username: the username
*/
Client(String server, int port, String username) {
// which calls the common constructor with the GUI set to null
this(server, port, username, null);
}
/*
* Constructor call when used from a GUI
* in console mode the ClienGUI parameter is null
*/
Client(String server, int port, String username, ClientGUI cg) {
this.server = server;
this.port = port;
this.username = username;
// save if we are in GUI mode or not
this.cg = cg;
}
/*
* To start the dialog
*/
public boolean start() {
// try to connect to the server
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch(Exception ec) {
display("Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
display(msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
display("Exception creating new Input/output Streams: " + eIO);
return false;
}
// creates the Thread to listen from the server
new ListenFromServer().start();
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try
{
sOutput.writeObject(username);
}
catch (IOException eIO) {
display("Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
/*
* To send a message to the console or the GUI
*/
private void display(String msg) {
if(cg == null)
System.out.println(msg); // println in console mode
else
cg.append(msg + "\n"); // append to the ClientGUI JTextArea (or whatever)
}
/*
* To send a message to the server
*/
void sendMessage(ChatMessage msg) {
try {
sOutput.writeObject(msg);
}
catch(IOException e) {
display("Exception writing to server: " + e);
}
}
/*
* When something goes wrong
* Close the Input/Output streams and disconnect not much to do in the catch clause
*/
private void disconnect() {
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
// inform the GUI
if(cg != null)
cg.connectionFailed();
}
/*
* To start the Client in console mode use one of the following command
* > java Client
* > java Client username
* > java Client username portNumber
* > java Client username portNumber serverAddress
* at the console prompt
* If the portNumber is not specified 1500 is used
* If the serverAddress is not specified "localHost" is used
* If the username is not specified "Anonymous" is used
* > java Client
* is equivalent to
* > java Client Anonymous 1500 localhost
* are eqquivalent
*
* In console mode, if an error occurs the program simply stops
* when a GUI id used, the GUI is informed of the disconnection
*/
public static void main(String[] args) {
// default values
int portNumber = 1500;
String serverAddress = "localHost";
String userName = "Anonymous";
// depending of the number of arguments provided we fall through
switch(args.length) {
// > javac Client username portNumber serverAddr
case 3:
serverAddress = args[2];
// > javac Client username portNumber
case 2:
try {
portNumber = Integer.parseInt(args[1]);
}
catch(Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
return;
}
// > javac Client username
case 1:
userName = args[0];
// > java Client
case 0:
break;
// invalid number of arguments
default:
System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
return;
}
// create the Client object
Client client = new Client(serverAddress, portNumber, userName);
// test if we can start the connection to the Server
// if it failed nothing we can do
if(!client.start())
return;
// wait for messages from user
Scanner scan = new Scanner(System.in);
// loop forever for message from the user
while(true) {
System.out.print("> ");
// read message from user
String msg = scan.nextLine();
// logout if message is LOGOUT
if(msg.equalsIgnoreCase("LOGOUT")) {
client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, ""));
// break to do the disconnect
break;
}
// message WhoIsIn
else if(msg.equalsIgnoreCase("WHOISIN")) {
client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));
}
else { // default to ordinary message
client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, msg));
}
}
// done disconnect
client.disconnect();
}
/*
* a class that waits for the message from the server and append them to the JTextArea
* if we have a GUI or simply System.out.println() it in console mode
*/
class ListenFromServer extends Thread {
public void run() {
while(true) {
try {
String msg = (String) sInput.readObject();
// if console mode print the message and add back the prompt
if(cg == null) {
System.out.println(msg);
System.out.print("> ");
}
else {
cg.append(msg);
}
}
catch(IOException e) {
display("Server has close the connection: " + e);
if(cg != null)
cg.connectionFailed();
break;
}
// can't happen with a String object but need the catch anyhow
catch(ClassNotFoundException e2) {
}
}
}
}
}
ChatMessage Class:
public class ChatMessage implements Serializable {
protected static final long serialVersionUID = 1112122200L;
// The different types of message sent by the Client
// WHOISIN to receive the list of the users connected
// MESSAGE an ordinary message
// LOGOUT to disconnect from the Server
static final int WHOISIN = 0, MESSAGE = 1, LOGOUT = 2;
private int type;
private String message;
// constructor
ChatMessage(int type, String message) {
this.type = type;
this.message = message;
}
// getters
int getType() {
return type;
}
String getMessage() {
return message;
}
}
Note that I am able to send messages just fine if I load both the server and client on the same machine. If I load the server on one machine, and the client on another, however, the client can receive messages from the server, but the server cannot receive messages from the client. If I attempt to send a message from the client to the Server, it gives me the errors shown above.

Switching between 2 Wifi networks, connecting fails

I'm having trouble switching between 2 networks programmatically on a Raspberry Pi 3 running Android things (but it should be the same as running normal Android).
The first network is coming from a device server as an access point. It runs an FTP server which I need to access through its network. It has a static IP-address in the 192.168.xxx.xxx network that I know, and is secured by WPA2-PSK. I have the SSID and passphrase which I know to be correct. This device is in it's own private network that it makes itself and isn't reachable an external address. The only way to connect to it is by connecting to it's network and FTP'ing to it's static address.
The second network is an open network of which I also know the SSID. This one is preconfigured by another application, so my application can't update the configuration.
The code below is what I have at the moment. The DownloadFilesTask is called in the onCreate of my startscreen.
The configuration of the first network seems to fail, as adding the configuration to the WifiManager returns -1 as networkId as I can see in the log in the last 2 lines before disconnecting and loosing all logging. The 2 lines are:
04-11 11:10:51.258 1332-1349/rocks.androidthings.hellothings D/connecting: SSID1 passphase
04-11 11:10:51.259 411-740/system_process I/addOrUpdateNetwork: uid = 10026 SSID SSID1 nid=-1
After this I get a java.net.socketException: invalid argument or cannot connect assign requested address.
I have been struggling with this for the past few days, so any help would be appreciated.
public String connectToNetwork1() {
try {
WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + SSID1 + "\"")) {
WifiConfiguration conf = new WifiConfiguration();
conf.SSID = "\"" + SSID1 + "\"";
conf.preSharedKey = "\"" + passphrase + "\"";
conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // For WPA2
conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
Log.d("connecting", conf.SSID + " " + conf.preSharedKey);
int networkId = wifiManager.addNetwork(conf);
Log.d("after connecting", conf.SSID + " " + conf.preSharedKey);
wifiManager.disconnect();
Thread t = new Thread(() -> {
wifiManager.enableNetwork(networkId, true);
});
t.start();
t.join();
wifiManager.reconnect();
Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
return wifiManager.getConnectionInfo().toString();
} else {
Log.d("WIFI", "already connected to network1");
return "already connected to network1";
}
} catch (Exception ex) {
Log.d("ERROR", ex.toString());
}
return "nougabollen";
}
public String connectToNetwork2() {
try {
WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + SSID2 + "\"")) {
/*WifiConfiguration conf = new WifiConfiguration(); //
conf.SSID = "\"" + SSID2 + "\""; //
//
conf.status = WifiConfiguration.Status.ENABLED; //
conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); // this block is useless since my application can't update this network
// since network 2 is configured elsewhere
Log.d("connecting", conf.SSID); //
//
int networkId = wifiManager.addNetwork(conf);*/ //
int networkId = -2;
List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
for(WifiConfiguration wc : configs){
if(wc.SSID.equals("\"" + SSID2 + "\"")){
networkId = wc.networkId;
}
}
int finalNetworkId = networkId;
wifiManager.disconnect();
Thread t = new Thread(() -> {
wifiManager.enableNetwork(finalNetworkId, true);
});
t.start();
t.join();
wifiManager.reconnect();
Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
return "tried networkId: " + networkId + " " + wifiManager.getConnectionInfo().toString();
} else {
Log.d("WIFI", "already connected to network2");
return "already connected to network2";
}
} catch (Exception ex) {
Log.d("ERROR", ex.toString());
}
return "smoutebollen";
}
private class DownloadFilesTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String text = "";
text += " " + connectToNetwork1();
text += " " + retrieveFile();
text += " " + connectToNetwork2();
Log.d("text", text);
return text;
}
protected void onPostExecute(String text) {
test.setText(text);
}
}
The code that I use to retrieve the file is (using apache.commons.net):
public static String getDummyFile(){
FTPClient client = new FTPClient();
Log.d("ftp","client created");
InetAddress ip = null;
try {
ip = InetAddress.getByName("192.168.242.129"); // this is the address of the device creating the first network
}
catch (Exception e){
Log.d("inetaddres",e.toString());
}
try {
Log.d("inet", ip.getHostAddress());
int reply = -1; //response
client.connect(ip);
Log.d("ftp","client connected");
reply = client.getReplyCode();
Log.d("ftp",""+reply);
client.enterLocalPassiveMode();
Log.d("ftp","passive mode");
//check if login is accepted
/*if (!client.login("anonymous", "")) {
Log.d("FTP", "error logging in");
}*/
//check if bad reponse code
/*if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
Log.d("FTP", "connection refused");
}*/
//set file type to binary and enter passive mode, active not supported on android
client.setFileType(FTP.BINARY_FILE_TYPE);
Log.d("ftp", "set type to binary");
client.changeWorkingDirectory("/files");
Log.d("ftp","changed dir");
String[] names = client.listNames();
Log.d("FTP", names[1].toString());
Log.d("FTP", client.printWorkingDirectory() + "/" + names[1].toString());
mapFiles(client,"/files","",0);
return client.printWorkingDirectory() + "/" + names[1].toString();
} catch (Exception e) {
Log.d("ftp",e.toString());
text = e.toString();
}
finally {
try {
client.disconnect();
}
catch (Exception e){
}
}
return text;
}
which gives the exception when trying to connect, since I'm not connected to the network.
So I managed to get it working, the following is my working code. Main differences are setting WPA as protocol, and letting the thread were I connect sleep for 3 seconds after enabling the network.
public String connectToXs() {
try {
WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.getConnectionInfo().getSSID().equals("\"ssid\"")) {
WifiConfiguration wc = new WifiConfiguration();
wc.SSID = "\"ssid\"";
wc.preSharedKey = "\"key\"";
wc.status = WifiConfiguration.Status.ENABLED;
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
int res = wifiManager.addNetwork(wc);
Log.d("WifiPreference", "add Network returned " + res );
final boolean[] b = new boolean[1];
Thread t = new Thread(() -> {
b[0] = wifiManager.enableNetwork(res, true);
wifiManager.setWifiEnabled(true);
try {
Thread.sleep(3000);
}
catch (Exception e){
Log.d("ERROR",e.toString());
}
});
t.start();
t.join();
Log.d("WifiPreference", "enableNetwork returned " + b[0]);
return wifiManager.getConnectionInfo().toString();
} else {
Log.d("WIFI", "already connected");
return "already connected";
}
} catch (Exception ex) {
Log.d("ERROR", ex.toString());
}
return "nougabollen";
}
public String connectToGuest() {
try {
WifiManager wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.getConnectionInfo().getSSID().equals("\"" + "ssid2" + "\"")) {
//int networkId = wifiManager.addNetwork(conf);
int networkId = -2;
List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
for(WifiConfiguration wc : configs){
if(wc.SSID.equals("\"SSID2\"")){
networkId = wc.networkId;
}
}
int finalNetworkId = networkId;
wifiManager.disconnect();
Thread t = new Thread(() -> {
wifiManager.enableNetwork(finalNetworkId, true);
try {
Thread.sleep(3000);
}
catch (Exception e){
Log.d("ERROR",e.toString());
}
});
t.start();
t.join();
wifiManager.reconnect();
Log.d("re connecting", wifiManager.getConnectionInfo().getSSID());
return "tried networkId: " + networkId + " " + wifiManager.getConnectionInfo().toString();
} else {
Log.d("WIFI", "already connected");
return "already connected";
}
} catch (Exception ex) {
Log.d("ERROR", ex.toString());
}
return "smoutebollen";
}

New email Server push Notification

I am using javax.mail API to connect to gmail inbox. What i am looking basically to create a program to listen for new emails notification in java. I find a code which adding listener in message count. Unfortunately it is not working and nothing has been updating in application if new email arrive at my gmail account. here is a code:
public class CheckingMails {
public static void check(String host, String storeType, String user,
String password) {
try {
//create properties field
Properties properties = new Properties();
properties.put("mail.pop3.host", host);
properties.put("mail.pop3.port", "995");
properties.put("mail.pop3.starttls.enable", "true");
Session emailSession = Session.getDefaultInstance(properties);
IMAPStore imapStore = (IMAPStore) emailSession.getStore("imaps");
// imapStore.connect();
imapStore.connect(host, user, password);
final IMAPFolder folder = (IMAPFolder) imapStore.getFolder("Inbox");
folder.open(IMAPFolder.READ_WRITE);
folder.addMessageCountListener(new MessageCountListener() {
public void messagesAdded(MessageCountEvent e) {
System.out.println("Message Count Event Fired");
}
public void messagesRemoved(MessageCountEvent e) {
System.out.println("Message Removed Event fired");
}
});
folder.addMessageChangedListener(new MessageChangedListener() {
public void messageChanged(MessageChangedEvent e) {
System.out.println("Message Changed Event fired");
}
});
// Check mail once in "freq" MILLIseconds
int freq = 2000;
boolean supportsIdle = false;
try {
if (emailFolder instanceof IMAPFolder) {
IMAPFolder f = (IMAPFolder) emailFolder;
f.idle();
supportsIdle = true;
}
} catch (FolderClosedException fex) {
throw fex;
} catch (MessagingException mex) {
supportsIdle = false;
}
for (; ; ) {
if (supportsIdle && emailFolder instanceof IMAPFolder) {
IMAPFolder f = (IMAPFolder) emailFolder;
f.idle();
System.out.println("IDLE done");
} else {
Thread.sleep(freq); // sleep for freq milliseconds
// This is to force the IMAP server to send us
// EXISTS notifications.
emailFolder.getMessageCount();
}
}
/*
// retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
System.out.println("messages.length---" + messages.length);
for (int i = 0, n = messages.length; i < n; i++) {
Message message = messages[i];
System.out.println("---------------------------------");
System.out.println("Email Number " + (i + 1));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
}
*/
//close the store and folder objects
// emailFolder.close(false);
// store.close();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String host = "pop.gmail.com";
String mailStoreType = "pop3";
String username = "EmailAddress#gmail.com";
String password = "****";
check(host, mailStoreType, username, password);
}
}
I also added a commented code to read all emails from folder and it is working but what i am looking some kind of push notification from server.
Can someone give me idea how i can implement this.

Facebook messenger app using asmack android xmpp

I was trying to fetch facebook friends and send message using asmack library over XMPP.I took reference from this site for facebook messaging.But after executing the code below i got exception.
public class MyActivity extends Activity {
public int state = 0;
private static final String TAG = "MyActivity";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
public void run() {
//XMPPConnection xmpp = new XMPPConnection("jabber.iitsp.com");
XMPPConnection xmpp = new XMPPConnection("chat.facebook.com");
try {
xmpp.connect();
// for other jabber accounts, truncate after the #
//xmpp.login("username", "password");
// for gtalk / gmail, include the #
xmpp.login("fb-username#chat.facebook.com", "your-fb-password");
} catch (XMPPException e) {
Log.v(TAG, "Failed to connect to " + xmpp.getHost());
e.printStackTrace();
}
ChatManager chatmanager = xmpp.getChatManager();
Chat newChat = chatmanager.createChat("friend#chat.facebook.com", new MessageListener() {
// THIS CODE NEVER GETS CALLED FOR SOME REASON
public void processMessage(Chat chat, Message message) {
try {
Log.v(TAG, "Got:" + message.getBody());
chat.sendMessage(message.getBody());
} catch (XMPPException e) {
Log.v(TAG, "Couldn't respond:" + e);
}
Log.v(TAG, message.toString());
}
});
// Send something to friend#chat.facebook.com
try {
newChat.sendMessage("my message");
} catch (XMPPException e) {
Log.v(TAG, "couldn't send:" + e.toString());
}
// Accept only messages from friend#chat.facebook.com
PacketFilter filter
= new AndFilter(new PacketTypeFilter(Message.class),
new FromContainsFilter("friend#chat.facebook.com"));
// Collect these messages
PacketCollector collector = xmpp.createPacketCollector(filter);
while(true) {
Packet packet = collector.nextResult();
if (packet instanceof Message) {
Message msg = (Message) packet;
// Process message
Log.v(TAG, "Got message:" + msg.getBody());
}
}
}
}).start();
//setContentView(this);
}}
I got following errors during execution of the code:-
1) java.security.KeyStoreException: java.security.NoSuchAlgorithmException: KeyStore jks implementation not found
2) SASL authentication failed using mechanism PLAIN:
Then my program crashed
java.lang.IllegalStateException: Not connected to server.
Any help would be appreciated.

Categories

Resources