diff --git a/src/eu/siacs/conversations/crypto/OtrEngine.java b/src/eu/siacs/conversations/crypto/OtrEngine.java
index 23af94e79..300de7350 100644
--- a/src/eu/siacs/conversations/crypto/OtrEngine.java
+++ b/src/eu/siacs/conversations/crypto/OtrEngine.java
@@ -20,7 +20,7 @@ import android.util.Log;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.persistance.DatabaseBackend;
 import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 
 import net.java.otr4j.OtrEngineHost;
 import net.java.otr4j.OtrException;
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index d04fea160..9bc6fb210 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -5,7 +5,7 @@ import java.util.List;
 
 import eu.siacs.conversations.entities.MucOptions.User;
 import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.PresencePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
 import android.annotation.SuppressLint;
 import android.util.Log;
 
@@ -144,7 +144,11 @@ public class MucOptions {
 		if (split.length == 2) {
 			return split[1];
 		} else {
-			return conversation.getAccount().getUsername();
+			if (conversation.getAccount()!=null) {
+				return conversation.getAccount().getUsername();
+			} else {
+				return null;
+			}
 		}
 	}
 	
diff --git a/src/eu/siacs/conversations/services/EventReceiver.java b/src/eu/siacs/conversations/services/EventReceiver.java
index 99b9f3c76..a13d51f2b 100644
--- a/src/eu/siacs/conversations/services/EventReceiver.java
+++ b/src/eu/siacs/conversations/services/EventReceiver.java
@@ -8,11 +8,10 @@ public class EventReceiver extends BroadcastReceiver {
 	public void onReceive(Context context, Intent intent) {
 		Intent mIntentForService = new Intent(context,
 				XmppConnectionService.class);
-		mIntentForService.putExtra("ping", intent.getBooleanExtra("ping",false));
-		if ((intent.getAction() != null)
-				&& (intent.getAction()
-						.equals("android.intent.action.BOOT_COMPLETED"))) {
-
+		if (intent.getAction() != null) {
+			mIntentForService.setAction(intent.getAction());
+		} else {
+			mIntentForService.setAction("other");
 		}
 		context.startService(mIntentForService);
 	}
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index 5adfa981d..5fa0c8506 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -7,7 +7,6 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Random;
 
-import org.json.JSONException;
 import org.openintents.openpgp.util.OpenPgpApi;
 import org.openintents.openpgp.util.OpenPgpServiceConnection;
 
@@ -35,15 +34,15 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
 import eu.siacs.conversations.utils.PhoneHelper;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.IqPacket;
-import eu.siacs.conversations.xmpp.MessagePacket;
 import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
 import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
 import eu.siacs.conversations.xmpp.OnStatusChanged;
 import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
-import eu.siacs.conversations.xmpp.PresencePacket;
 import eu.siacs.conversations.xmpp.XmppConnection;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -70,9 +69,10 @@ public class XmppConnectionService extends Service {
 
 	public long startDate;
 
-	private static final int PING_INTERVAL = 300;
+	private static final int PING_MAX_INTERVAL = 300;
+	private static final int PING_MIN_INTERVAL = 10;
 	private static final int PING_TIMEOUT = 2;
-	
+
 	private List<Account> accounts;
 	private List<Conversation> conversations = null;
 
@@ -80,10 +80,11 @@ public class XmppConnectionService extends Service {
 	private OnAccountListChangedListener accountChangedListener = null;
 	private OnTLSExceptionReceived tlsException = null;
 	
-	public void setOnTLSExceptionReceivedListener(OnTLSExceptionReceived listener) {
+	public void setOnTLSExceptionReceivedListener(
+			OnTLSExceptionReceived listener) {
 		tlsException = listener;
 	}
-	
+
 	private Random mRandom = new Random(System.currentTimeMillis());
 
 	private ContentObserver contactObserver = new ContentObserver(null) {
@@ -115,7 +116,7 @@ public class XmppConnectionService extends Service {
 						&& (packet.getBody().startsWith("?OTR"))) {
 					message = MessageParser.parseOtrChat(packet, account,
 							service);
-					if (message!=null) {
+					if (message != null) {
 						message.markUnread();
 					}
 				} else if (packet.hasChild("body")) {
@@ -126,7 +127,9 @@ public class XmppConnectionService extends Service {
 						|| (packet.hasChild("sent"))) {
 					message = MessageParser.parseCarbonMessage(packet, account,
 							service);
-					message.getConversation().markRead();
+					if (message != null) {
+						message.getConversation().markRead();
+					}
 					notify = false;
 				}
 
@@ -144,7 +147,7 @@ public class XmppConnectionService extends Service {
 			} else if (packet.getType() == MessagePacket.TYPE_ERROR) {
 				message = MessageParser.parseError(packet, account, service);
 			} else {
-				//Log.d(LOGTAG, "unparsed message " + packet.toString());
+				// Log.d(LOGTAG, "unparsed message " + packet.toString());
 			}
 			if (message == null) {
 				return;
@@ -169,7 +172,8 @@ public class XmppConnectionService extends Service {
 			if (convChangedListener != null) {
 				convChangedListener.onConversationListChanged();
 			} else {
-					UIHelper.updateNotification(getApplicationContext(), getConversations(), notify);
+				UIHelper.updateNotification(getApplicationContext(),
+						getConversations(), notify);
 			}
 		}
 	};
@@ -195,20 +199,12 @@ public class XmppConnectionService extends Service {
 				if (convChangedListener != null) {
 					convChangedListener.onConversationListChanged();
 				}
-				if (account.getKeys().has("pgp_signature")) {
-					try {
-						sendPgpPresence(account, account.getKeys().getString("pgp_signature"));
-					} catch (JSONException e) {
-						//
-					}
-				}
-				scheduleWakeupCall(PING_INTERVAL, true);
+				scheduleWakeupCall(PING_MAX_INTERVAL, true);
 			} else if (account.getStatus() == Account.STATUS_OFFLINE) {
-				Log.d(LOGTAG,"onStatusChanged offline");
 				databaseBackend.clearPresences(account);
 				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
-					int timeToReconnect = mRandom.nextInt(50)+10;
-					scheduleWakeupCall(timeToReconnect,false);
+					int timeToReconnect = mRandom.nextInt(50) + 10;
+					scheduleWakeupCall(timeToReconnect, false);
 				}
 
 			}
@@ -220,13 +216,17 @@ public class XmppConnectionService extends Service {
 		@Override
 		public void onPresencePacketReceived(Account account,
 				PresencePacket packet) {
-			if (packet.hasChild("x")&&(packet.findChild("x").getAttribute("xmlns").startsWith("http://jabber.org/protocol/muc"))) {
-				Conversation muc = findMuc(packet.getAttribute("from").split("/")[0]);
-				if (muc!=null) {
+			if (packet.hasChild("x")
+					&& (packet.findChild("x").getAttribute("xmlns")
+							.startsWith("http://jabber.org/protocol/muc"))) {
+				Conversation muc = findMuc(packet.getAttribute("from").split(
+						"/")[0]);
+				if (muc != null) {
 					int error = muc.getMucOptions().getError();
 					muc.getMucOptions().processPacket(packet);
-					if ((muc.getMucOptions().getError()!=error)&&(convChangedListener!=null)) {
-						Log.d(LOGTAG,"muc error status changed");
+					if ((muc.getMucOptions().getError() != error)
+							&& (convChangedListener != null)) {
+						Log.d(LOGTAG, "muc error status changed");
 						convChangedListener.onConversationListChanged();
 					}
 				}
@@ -252,15 +252,17 @@ public class XmppConnectionService extends Service {
 						contact.updatePresence(fromParts[1], Presences.DND);
 					}
 					PgpEngine pgp = getPgpEngine();
-					if (pgp!=null) {
+					if (pgp != null) {
 						Element x = packet.findChild("x");
 						if ((x != null)
-								&& (x.getAttribute("xmlns").equals("jabber:x:signed"))) {
+								&& (x.getAttribute("xmlns")
+										.equals("jabber:x:signed"))) {
 							try {
-								contact.setPgpKeyId(pgp.fetchKeyId(packet.findChild("status")
-										.getContent(), x.getContent()));
+								contact.setPgpKeyId(pgp.fetchKeyId(packet
+										.findChild("status").getContent(), x
+										.getContent()));
 							} catch (OpenPgpException e) {
-								Log.d(LOGTAG,"faulty pgp. just ignore");
+								Log.d(LOGTAG, "faulty pgp. just ignore");
 							}
 						}
 					}
@@ -290,7 +292,7 @@ public class XmppConnectionService extends Service {
 						// TODO: ask user to handle it maybe
 					}
 				} else {
-					Log.d(LOGTAG, packet.toString());
+					//Log.d(LOGTAG, packet.toString());
 				}
 				replaceContactInConversation(contact.getJid(), contact);
 			}
@@ -314,6 +316,8 @@ public class XmppConnectionService extends Service {
 
 	private OpenPgpServiceConnection pgpServiceConnection;
 	private PgpEngine mPgpEngine = null;
+	private Intent pingIntent;
+	private PendingIntent pendingPingIntent = null;
 
 	public PgpEngine getPgpEngine() {
 		if (pgpServiceConnection.isBound()) {
@@ -330,7 +334,7 @@ public class XmppConnectionService extends Service {
 	}
 
 	protected Conversation findMuc(String name) {
-		for(Conversation conversation : this.conversations) {
+		for (Conversation conversation : this.conversations) {
 			if (conversation.getContactJid().split("/")[0].equals(name)) {
 				return conversation;
 			}
@@ -391,34 +395,64 @@ public class XmppConnectionService extends Service {
 
 	@Override
 	public int onStartCommand(Intent intent, int flags, int startId) {
-		ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+		Log.d(LOGTAG,"calling start service. caller was:"+intent.getAction());
+		
+		// internet and online last_received - list_ping >= max_ping : ping
+		// internet and online last_ping - last_received >= ping_timeout :
+		// reconnect
+		// internet and offline and enabled : connect (Threat start)
 
+		// no internet - set no internet
+
+		ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
+				.getSystemService(Context.CONNECTIVITY_SERVICE);
 		NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
 		boolean isConnected = activeNetwork != null
 				&& activeNetwork.isConnected();
+
 		for (Account account : accounts) {
-			if (!isConnected) {
-				account.setStatus(Account.STATUS_NO_INTERNET);
-			} else {
-				if (account.getStatus() == Account.STATUS_NO_INTERNET) {
-					account.setStatus(Account.STATUS_OFFLINE);
-				}
-			}
-			if (accountChangedListener!=null) {
-				accountChangedListener.onAccountListChangedListener();
-			}
-			if ((!account.isOptionSet(Account.OPTION_DISABLED))&&(isConnected)) {
-				if (account.getXmppConnection() == null) {
-					account.setXmppConnection(this.createConnection(account));
-				}
-				if (account.getStatus()==Account.STATUS_OFFLINE) {
-					Thread thread = new Thread(account.getXmppConnection());
-					thread.start();
-				} else {
-					if (intent.getBooleanExtra("ping", false)) {
-						Log.d(LOGTAG,"start service ping");
-						ping(account,PING_TIMEOUT);
+			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+				if (!isConnected) {
+					account.setStatus(Account.STATUS_NO_INTERNET);
+					if (statusListener!=null) {
+						statusListener.onStatusChanged(account);
 					}
+				} else {
+					if (account.getStatus() == Account.STATUS_NO_INTERNET) {
+						account.setStatus(Account.STATUS_OFFLINE);
+						if (statusListener!=null) {
+							statusListener.onStatusChanged(account);
+						}
+					}
+
+					// TODO 3 remaining cases
+					if (account.getStatus() == Account.STATUS_ONLINE) {
+						long lastReceived = account.getXmppConnection().lastPaketReceived;
+						long lastSent = account.getXmppConnection().lastPingSent;
+						if (lastSent - lastReceived >= PING_TIMEOUT * 1000) {
+							Log.d(LOGTAG, account.getJid() + ": ping timeout");
+							this.reconnectAccount(account);
+						} else if (SystemClock.elapsedRealtime() - lastReceived >= PING_MIN_INTERVAL * 1000) {
+							account.getXmppConnection().sendPing();
+							account.getXmppConnection().lastPingSent = SystemClock.elapsedRealtime();
+							this.scheduleWakeupCall(2, false);
+						}
+					} else if (account.getStatus() == Account.STATUS_OFFLINE) {
+						if (account.getXmppConnection() == null) {
+							account.setXmppConnection(this
+									.createConnection(account));
+						}
+						account.getXmppConnection().lastPingSent = SystemClock.elapsedRealtime();
+						new Thread(account.getXmppConnection()).start();
+					} else {
+						Log.d(LOGTAG,account.getJid()+": status="+account.getStatus());
+						// TODO notify user of ssl cert problem or auth problem or what ever
+					}
+					//in any case. reschedule wakup call
+					this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
+				}
+				if (accountChangedListener != null) {
+					accountChangedListener.onAccountListChangedListener();
 				}
 			}
 		}
@@ -436,8 +470,7 @@ public class XmppConnectionService extends Service {
 		this.pgpServiceConnection = new OpenPgpServiceConnection(
 				getApplicationContext(), "org.sufficientlysecure.keychain");
 		this.pgpServiceConnection.bindToService();
-		
-		
+
 	}
 
 	@Override
@@ -445,26 +478,47 @@ public class XmppConnectionService extends Service {
 		super.onDestroy();
 		for (Account account : accounts) {
 			if (account.getXmppConnection() != null) {
-				disconnect(account);
+				disconnect(account, true);
 			}
 		}
 	}
-	
-	protected void scheduleWakeupCall(int seconds,boolean ping) {
+
+	protected void scheduleWakeupCall(int seconds, boolean ping) {
+		long timeToWake = SystemClock.elapsedRealtime() + seconds * 1000;
 		Context context = getApplicationContext();
-		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-		Intent intent = new Intent(context, EventReceiver.class);
-		intent.putExtra("ping", ping);
-		PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
-		alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-		        SystemClock.elapsedRealtime() +
-		        seconds * 1000, alarmIntent);
-		if (ping) {
-			Log.d(LOGTAG,"schedule ping in "+seconds+" seconds");
-		} else {
-			Log.d(LOGTAG,"schedule reconnect in "+seconds+" seconds");
-		}
+		AlarmManager alarmManager = (AlarmManager) context
+				.getSystemService(Context.ALARM_SERVICE);
 		
+		
+		
+		if (ping) {
+			if (this.pingIntent==null) {
+				this.pingIntent = new Intent(context, EventReceiver.class);
+				this.pingIntent.setAction("ping");
+				this.pingIntent.putExtra("time", timeToWake);
+				this.pendingPingIntent = PendingIntent.getBroadcast(context, 0,
+						this.pingIntent, 0);
+				alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, pendingPingIntent);
+				//Log.d(LOGTAG,"schedule ping in "+seconds+" seconds");
+			} else {
+				long scheduledTime = this.pingIntent.getLongExtra("time", 0);
+				if (scheduledTime<SystemClock.elapsedRealtime() || (scheduledTime > timeToWake)) {
+					this.pingIntent.putExtra("time", timeToWake);
+					alarmManager.cancel(this.pendingPingIntent);
+					this.pendingPingIntent = PendingIntent.getBroadcast(context, 0,
+							this.pingIntent, 0);
+					alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, pendingPingIntent);
+					//Log.d(LOGTAG,"reschedule old ping to ping in "+seconds+" seconds");
+				}
+			}
+		} else {
+			Intent intent = new Intent(context, EventReceiver.class);
+			intent.setAction("ping_check");
+			PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0,
+					intent, 0);
+			alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,timeToWake, alarmIntent);
+		}
+
 	}
 
 	public XmppConnection createConnection(Account account) {
@@ -475,16 +529,19 @@ public class XmppConnectionService extends Service {
 		connection.setOnPresencePacketReceivedListener(this.presenceListener);
 		connection
 				.setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
-		connection.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
-			
-			@Override
-			public void onTLSExceptionReceived(String fingerprint, Account account) {
-				Log.d(LOGTAG,"tls exception arrived in service");
-				if (tlsException!=null) {
-					tlsException.onTLSExceptionReceived(fingerprint,account);
-				}
-			}
-		});
+		connection
+				.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
+
+					@Override
+					public void onTLSExceptionReceived(String fingerprint,
+							Account account) {
+						Log.d(LOGTAG, "tls exception arrived in service");
+						if (tlsException != null) {
+							tlsException.onTLSExceptionReceived(fingerprint,
+									account);
+						}
+					}
+				});
 		return connection;
 	}
 
@@ -629,9 +686,10 @@ public class XmppConnectionService extends Service {
 		Element query = new Element("query");
 		query.setAttribute("xmlns", "jabber:iq:roster");
 		if (!"".equals(account.getRosterVersion())) {
-			Log.d(LOGTAG,account.getJid()+ ": fetching roster version "+account.getRosterVersion());
+			Log.d(LOGTAG, account.getJid() + ": fetching roster version "
+					+ account.getRosterVersion());
 		} else {
-			Log.d(LOGTAG,account.getJid()+": fetching roster");
+			Log.d(LOGTAG, account.getJid() + ": fetching roster");
 		}
 		query.setAttribute("ver", account.getRosterVersion());
 		iqPacket.addChild(query);
@@ -643,7 +701,8 @@ public class XmppConnectionService extends Service {
 							IqPacket packet) {
 						Element roster = packet.findChild("query");
 						if (roster != null) {
-							Log.d(LOGTAG,account.getJid()+": processing roster");
+							Log.d(LOGTAG, account.getJid()
+									+ ": processing roster");
 							processRosterItems(account, roster);
 							StringBuilder mWhere = new StringBuilder();
 							mWhere.append("jid NOT IN(");
@@ -668,7 +727,8 @@ public class XmppConnectionService extends Service {
 							}
 
 						} else {
-							Log.d(LOGTAG,account.getJid()+": empty roster returend");
+							Log.d(LOGTAG, account.getJid()
+									+ ": empty roster returend");
 						}
 						mergePhoneContactsWithRoster(new OnPhoneContactsMerged() {
 
@@ -864,7 +924,7 @@ public class XmppConnectionService extends Service {
 	public void deleteAccount(Account account) {
 		Log.d(LOGTAG, "called delete account");
 		if (account.getXmppConnection() != null) {
-			this.disconnect(account);
+			this.disconnect(account, false);
 		}
 		databaseBackend.deleteAccount(account);
 		this.accounts.remove(account);
@@ -913,8 +973,7 @@ public class XmppConnectionService extends Service {
 			nick = conversation.getAccount().getUsername();
 		}
 		PresencePacket packet = new PresencePacket();
-		packet.setAttribute("to", muc + "/"
-				+ nick);
+		packet.setAttribute("to", muc + "/" + nick);
 		Element x = new Element("x");
 		x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
 		if (conversation.getMessages().size() != 0) {
@@ -928,21 +987,22 @@ public class XmppConnectionService extends Service {
 		conversation.getAccount().getXmppConnection()
 				.sendPresencePacket(packet);
 	}
-	
+
 	private OnRenameListener renameListener = null;
 	private boolean pongReceived;
+
 	public void setOnRenameListener(OnRenameListener listener) {
 		this.renameListener = listener;
 	}
-	
+
 	public void renameInMuc(final Conversation conversation, final String nick) {
 		final MucOptions options = conversation.getMucOptions();
 		if (options.online()) {
 			options.setOnRenameListener(new OnRenameListener() {
-				
+
 				@Override
 				public void onRename(boolean success) {
-					if (renameListener!=null) {
+					if (renameListener != null) {
 						renameListener.onRename(success);
 					}
 					if (success) {
@@ -951,30 +1011,36 @@ public class XmppConnectionService extends Service {
 				}
 			});
 			PresencePacket packet = new PresencePacket();
-			packet.setAttribute("to", conversation.getContactJid().split("/")[0]+"/"+nick);
+			packet.setAttribute("to",
+					conversation.getContactJid().split("/")[0] + "/" + nick);
 			packet.setAttribute("from", conversation.getAccount().getFullJid());
-			
-			packet = conversation.getAccount().getXmppConnection().sendPresencePacket(packet, new OnPresencePacketReceived() {
-				
-				@Override
-				public void onPresencePacketReceived(Account account, PresencePacket packet) {
-					final boolean changed;
-					String type = packet.getAttribute("type");
-					changed = (!"error".equals(type));
-					if (!changed) {
-						options.getOnRenameListener().onRename(false);
-					} else {
-						if (type==null) {
-							options.getOnRenameListener().onRename(true);
-							options.setNick(packet.getAttribute("from").split("/")[1]);
-						} else {
-							options.processPacket(packet);
+
+			conversation.getAccount().getXmppConnection()
+					.sendPresencePacket(packet, new OnPresencePacketReceived() {
+
+						@Override
+						public void onPresencePacketReceived(Account account,
+								PresencePacket packet) {
+							final boolean changed;
+							String type = packet.getAttribute("type");
+							changed = (!"error".equals(type));
+							if (!changed) {
+								options.getOnRenameListener().onRename(false);
+							} else {
+								if (type == null) {
+									options.getOnRenameListener()
+											.onRename(true);
+									options.setNick(packet.getAttribute("from")
+											.split("/")[1]);
+								} else {
+									options.processPacket(packet);
+								}
+							}
 						}
-					}
-				}
-			});
+					});
 		} else {
-			String jid = conversation.getContactJid().split("/")[0]+"/"+nick;
+			String jid = conversation.getContactJid().split("/")[0] + "/"
+					+ nick;
 			conversation.setContactJid(jid);
 			databaseBackend.updateConversation(conversation);
 			if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
@@ -987,31 +1053,46 @@ public class XmppConnectionService extends Service {
 		PresencePacket packet = new PresencePacket();
 		packet.setAttribute("to", conversation.getContactJid());
 		packet.setAttribute("from", conversation.getAccount().getFullJid());
-		packet.setAttribute("type","unavailable");
-		conversation.getAccount().getXmppConnection().sendPresencePacket(packet);
+		packet.setAttribute("type", "unavailable");
+		conversation.getAccount().getXmppConnection()
+				.sendPresencePacket(packet);
 		conversation.getMucOptions().setOffline();
 	}
 
-	public void disconnect(Account account) {
-		List<Conversation> conversations = getConversations();
-		for (int i = 0; i < conversations.size(); i++) {
-			Conversation conversation = conversations.get(i);
-			if (conversation.getAccount() == account) {
-				if (conversation.getMode() == Conversation.MODE_MULTI) {
-					leaveMuc(conversation);
-				} else {
-					try {
-						conversation.endOtrIfNeeded();
-					} catch (OtrException e) {
-						Log.d(LOGTAG, "error ending otr session for "
-								+ conversation.getName());
+	public void disconnect(final Account account, boolean blocking) {
+		if ((account.getStatus() == Account.STATUS_ONLINE)||(account.getStatus() == Account.STATUS_DISABLED)) {
+			List<Conversation> conversations = getConversations();
+			for (int i = 0; i < conversations.size(); i++) {
+				Conversation conversation = conversations.get(i);
+				if (conversation.getAccount() == account) {
+					if (conversation.getMode() == Conversation.MODE_MULTI) {
+						leaveMuc(conversation);
+					} else {
+						try {
+							conversation.endOtrIfNeeded();
+						} catch (OtrException e) {
+							Log.d(LOGTAG, "error ending otr session for "
+									+ conversation.getName());
+						}
 					}
 				}
 			}
+			if (!blocking) {
+				new Thread(new Runnable() {
+	
+					@Override
+					public void run() {
+						account.getXmppConnection().disconnect(false);
+						Log.d(LOGTAG, "disconnected account: " + account.getJid());
+						//account.setXmppConnection(null);
+					}
+				}).start();
+			} else {
+				account.getXmppConnection().disconnect(false);
+				Log.d(LOGTAG, "disconnected account: " + account.getJid());
+				//account.setXmppConnection(null);
+			}
 		}
-		account.getXmppConnection().disconnect();
-		Log.d(LOGTAG, "disconnected account: " + account.getJid());
-		account.setXmppConnection(null);
 	}
 
 	@Override
@@ -1092,7 +1173,7 @@ public class XmppConnectionService extends Service {
 		Log.d(LOGTAG, packet.toString());
 		contact.getAccount().getXmppConnection().sendPresencePacket(packet);
 	}
-	
+
 	public void sendPgpPresence(Account account, String signature) {
 		PresencePacket packet = new PresencePacket();
 		packet.setAttribute("from", account.getFullJid());
@@ -1122,7 +1203,7 @@ public class XmppConnectionService extends Service {
 
 	public Contact findContact(String uuid) {
 		Contact contact = this.databaseBackend.getContact(uuid);
-		for(Account account : getAccounts()) {
+		for (Account account : getAccounts()) {
 			if (contact.getAccountUuid().equals(account.getUuid())) {
 				contact.setAccount(account);
 			}
@@ -1134,56 +1215,22 @@ public class XmppConnectionService extends Service {
 		this.tlsException = null;
 	}
 
-	public void reconnectAccount(Account account) {
-		if (account.getXmppConnection() != null) {
-			disconnect(account);
-		}
-		if (!account.isOptionSet(Account.OPTION_DISABLED)) {
-			if (account.getXmppConnection()==null) {
-				account.setXmppConnection(this.createConnection(account));
-			}
-			Thread thread = new Thread(account.getXmppConnection());
-			thread.start();
-		}
-	}
-	
-	public void ping(final Account account,final int timeout) {
-		Log.d(LOGTAG,account.getJid()+": sending ping");
-		IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
-		Element ping = new Element("ping");
-		iq.setAttribute("from",account.getFullJid());
-		ping.setAttribute("xmlns", "urn:xmpp:ping");
-		iq.addChild(ping);
-		pongReceived = false;
-		account.getXmppConnection().sendIqPacket(iq, new OnIqPacketReceived() {
-			
-			@Override
-			public void onIqPacketReceived(Account account, IqPacket packet) {
-				pongReceived = true;
-			}
-		});
+	//TODO dont let thread sleep but schedule wake up
+	public void reconnectAccount(final Account account) {
 		new Thread(new Runnable() {
-			
+
 			@Override
 			public void run() {
-				int i = 0;
-				while(i <= (5 * timeout)) {
-					if (pongReceived) {
-						scheduleWakeupCall(PING_INTERVAL,true);
-						break;
-					}
-					try {
-						Thread.sleep(200);
-					} catch (InterruptedException e) {
-						
-					}
-					++i;
+				if (account.getXmppConnection() != null) {
+					disconnect(account, true);
 				}
-				if (!pongReceived) {
-					Log.d("xmppService",account.getJid()+" no pong after "+timeout+" seconds");
-					reconnectAccount(account);
+				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+					if (account.getXmppConnection() == null) {
+						account.setXmppConnection(createConnection(account));
+					}
+					Thread thread = new Thread(account.getXmppConnection());
+					thread.start();
 				}
-				
 			}
 		}).start();
 	}
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index b49106f15..3373479a9 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -332,6 +332,9 @@ public class ConversationFragment extends Fragment {
 		final ConversationActivity activity = (ConversationActivity) getActivity();
 		activity.registerListener();
 		this.conversation = activity.getSelectedConversation();
+		if (this.conversation==null) {
+			return;
+		}
 		this.selfBitmap = findSelfPicture();
 		updateMessages();
 		// rendering complete. now go tell activity to close pane
@@ -374,7 +377,6 @@ public class ConversationFragment extends Fragment {
 	public void updateMessages() {
 		ConversationActivity activity = (ConversationActivity) getActivity();
 		List<Message> encryptedMessages = new LinkedList<Message>();
-		// TODO this.conversation could be null?!
 		for(Message message : this.conversation.getMessages()) {
 			if (message.getEncryption() == Message.ENCRYPTION_PGP) {
 				encryptedMessages.add(message);
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index 2af69867a..859981317 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -48,7 +48,6 @@ public class ManageAccountActivity extends XmppActivity {
 
 		@Override
 		public void onAccountListChangedListener() {
-			Log.d("xmppService", "ui on account list changed listener");
 			accountList.clear();
 			accountList.addAll(xmppConnectionService.getAccounts());
 			runOnUiThread(new Runnable() {
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 2f1b1d502..1596a53a6 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -42,8 +42,9 @@ public abstract class XmppActivity extends Activity {
 	protected void onStart() {
 		super.onStart();
 		if (!xmppConnectionServiceBound) {
-			startService(new Intent(this, XmppConnectionService.class));
 			Intent intent = new Intent(this, XmppConnectionService.class);
+			intent.setAction("ui");
+			startService(intent);
 			bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 		}
 	}
diff --git a/src/eu/siacs/conversations/utils/MessageParser.java b/src/eu/siacs/conversations/utils/MessageParser.java
index 614683a2c..2da0459e5 100644
--- a/src/eu/siacs/conversations/utils/MessageParser.java
+++ b/src/eu/siacs/conversations/utils/MessageParser.java
@@ -11,7 +11,7 @@ import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 
 public class MessageParser {
 	
diff --git a/src/eu/siacs/conversations/xml/TagWriter.java b/src/eu/siacs/conversations/xml/TagWriter.java
index 109078ca1..15ad385f6 100644
--- a/src/eu/siacs/conversations/xml/TagWriter.java
+++ b/src/eu/siacs/conversations/xml/TagWriter.java
@@ -5,25 +5,29 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.util.concurrent.LinkedBlockingQueue;
 
-import android.util.Log;
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
 
 public class TagWriter {
 	
 	private OutputStreamWriter outputStream;
-	private LinkedBlockingQueue<String> writeQueue = new LinkedBlockingQueue<String>();
-	private Thread writer = new Thread() {
-		public boolean shouldStop = false;
+	private boolean finshed = false;
+	private LinkedBlockingQueue<AbstractStanza> writeQueue = new LinkedBlockingQueue<AbstractStanza>();
+	private Thread asyncStanzaWriter = new Thread() {
+		private boolean shouldStop = false;
 		@Override
 		public void run() {
 			while(!shouldStop) {
+				if ((finshed)&&(writeQueue.size() == 0)) {
+					return;
+				}
 				try {
-					String output = writeQueue.take();
-					outputStream.write(output);
+					AbstractStanza output = writeQueue.take();
+					outputStream.write(output.toString());
 					outputStream.flush();
 				} catch (IOException e) {
-					Log.d("xmppService", "error writing to stream");
+					shouldStop = true;
 				} catch (InterruptedException e) {
-					
+					shouldStop = true;
 				}
 			}
 		}
@@ -31,34 +35,49 @@ public class TagWriter {
 	
 	
 	public TagWriter() {
-		
 	}
 	
 	public TagWriter(OutputStream out) {
 		this.setOutputStream(out);
-		writer.start();
 	}
 	
 	public void setOutputStream(OutputStream out) {
 		this.outputStream = new OutputStreamWriter(out);
-		if (!writer.isAlive()) writer.start();
 	}
 	
-	public TagWriter beginDocument() {
-		writeQueue.add("<?xml version='1.0'?>");
+	public TagWriter beginDocument() throws IOException {
+		outputStream.write("<?xml version='1.0'?>");
+		outputStream.flush();
 		return this;
 	}
 	
-	public TagWriter writeTag(Tag tag) {
-		writeQueue.add(tag.toString());
+	public TagWriter writeTag(Tag tag) throws IOException {
+		outputStream.write(tag.toString());
+		outputStream.flush();
 		return this;
 	}
 
-	public void writeString(String string) {
-		writeQueue.add(string);
+	public TagWriter writeElement(Element element) throws IOException {
+		outputStream.write(element.toString());
+		outputStream.flush();
+		return this;
 	}
-
-	public void writeElement(Element element) {
-		writeQueue.add(element.toString());
+	
+	public TagWriter writeStanzaAsync(AbstractStanza stanza) {
+		if (finshed) {
+			return this;
+		} else {
+			if (!asyncStanzaWriter.isAlive()) asyncStanzaWriter.start();
+			writeQueue.add(stanza);
+			return this;
+		}
+	}
+	
+	public void finish() {
+		this.finshed = true;
+	}
+	
+	public boolean finished() {
+		return (this.writeQueue.size() == 0);
 	}
 }
diff --git a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
index 54909f88c..a4cff9863 100644
--- a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java
@@ -1,6 +1,7 @@
 package eu.siacs.conversations.xmpp;
 
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 
 public interface OnIqPacketReceived extends PacketReceived {
 	public void onIqPacketReceived(Account account, IqPacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
index 6f0b387dc..325e945f0 100644
--- a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java
@@ -1,6 +1,7 @@
 package eu.siacs.conversations.xmpp;
 
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 
 public interface OnMessagePacketReceived extends PacketReceived {
 	public void onMessagePacketReceived(Account account, MessagePacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
index 55672fff2..95c1acfcc 100644
--- a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
+++ b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java
@@ -1,6 +1,7 @@
 package eu.siacs.conversations.xmpp;
 
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
 
 public interface OnPresencePacketReceived extends PacketReceived {
 	public void onPresencePacketReceived(Account account, PresencePacket packet);
diff --git a/src/eu/siacs/conversations/xmpp/PresencePacket.java b/src/eu/siacs/conversations/xmpp/PresencePacket.java
deleted file mode 100644
index 3d77ce151..000000000
--- a/src/eu/siacs/conversations/xmpp/PresencePacket.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-import eu.siacs.conversations.xml.Element;
-
-public class PresencePacket extends Element {
-	private PresencePacket(String name) {
-		super("presence");
-	}
-	
-	public PresencePacket() {
-		super("presence");
-	}
-}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index 53f9b85a7..b11f2016f 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -26,10 +26,12 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import org.json.JSONException;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.os.Bundle;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.util.Log;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.utils.CryptoHelper;
@@ -38,6 +40,14 @@ import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Tag;
 import eu.siacs.conversations.xml.TagWriter;
 import eu.siacs.conversations.xml.XmlReader;
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
+import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
 
 public class XmppConnection implements Runnable {
 
@@ -56,6 +66,14 @@ public class XmppConnection implements Runnable {
 	private boolean shouldAuthenticate = true;
 	private Element streamFeatures;
 	private HashSet<String> discoFeatures = new HashSet<String>();
+	
+	private String streamId = null;
+	
+	private int stanzasReceived = 0;
+	private int stanzasSent = 0;
+	
+	public long lastPaketReceived = 0;
+	public long lastPingSent = 0;
 
 	private static final int PACKET_IQ = 0;
 	private static final int PACKET_MESSAGE = 1;
@@ -77,14 +95,16 @@ public class XmppConnection implements Runnable {
 	}
 
 	protected void changeStatus(int nextStatus) {
-		account.setStatus(nextStatus);
-		if (statusListener != null) {
-			statusListener.onStatusChanged(account);
+		if (account.getStatus() != nextStatus) {
+			account.setStatus(nextStatus);
+			if (statusListener != null) {
+				statusListener.onStatusChanged(account);
+			}
 		}
 	}
 
 	protected void connect() {
-		Log.d(LOGTAG, "connecting");
+		Log.d(LOGTAG,account.getJid()+ ": connecting");
 		try {
 			tagReader = new XmlReader(wakeLock);
 			tagWriter = new TagWriter();
@@ -147,7 +167,6 @@ public class XmppConnection implements Runnable {
 	@Override
 	public void run() {
 		connect();
-		Log.d(LOGTAG, "end run");
 	}
 
 	private void processStream(Tag currentTag) throws XmlPullParserException,
@@ -176,6 +195,35 @@ public class XmppConnection implements Runnable {
 			} else if (nextTag.isStart("failure")) {
 				Element failure = tagReader.readElement(nextTag);
 				changeStatus(Account.STATUS_UNAUTHORIZED);
+			} else if (nextTag.isStart("enabled")) {
+				this.stanzasSent = 0;
+				Element enabled = tagReader.readElement(nextTag);
+				if ("true".equals(enabled.getAttribute("resume"))) {
+					this.streamId = enabled.getAttribute("id");
+					Log.d(LOGTAG,account.getJid()+": stream managment enabled (resumable)");
+				} else {
+					Log.d(LOGTAG,account.getJid()+": stream managment enabled");
+				}
+				this.stanzasReceived = 0;
+				RequestPacket r = new RequestPacket();
+				tagWriter.writeStanzaAsync(r);
+			} else if (nextTag.isStart("resumed")) {
+				tagReader.readElement(nextTag);
+				changeStatus(Account.STATUS_ONLINE);
+				Log.d(LOGTAG,account.getJid()+": session resumed");
+			} else if (nextTag.isStart("r")) {
+				tagReader.readElement(nextTag);
+				AckPacket ack = new AckPacket(this.stanzasReceived);
+				//Log.d(LOGTAG,ack.toString());
+				tagWriter.writeStanzaAsync(ack);
+			} else if (nextTag.isStart("a")) {
+				Element ack = tagReader.readElement(nextTag);
+				lastPaketReceived = SystemClock.elapsedRealtime();
+				int serverSequence = Integer.parseInt(ack.getAttribute("h"));
+				if (serverSequence>this.stanzasSent) {
+					this.stanzasSent = serverSequence;
+				}
+				//Log.d(LOGTAG,"server ack"+ack.toString()+" ("+this.stanzasSent+")");
 			} else if (nextTag.isStart("iq")) {
 				processIq(nextTag);
 			} else if (nextTag.isStart("message")) {
@@ -221,6 +269,8 @@ public class XmppConnection implements Runnable {
 			}
 			nextTag = tagReader.readTag();
 		}
+		++stanzasReceived;
+		lastPaketReceived = SystemClock.elapsedRealtime();
 		return element;
 	}
 
@@ -271,7 +321,7 @@ public class XmppConnection implements Runnable {
 		}
 	}
 
-	private void sendStartTLS() {
+	private void sendStartTLS() throws IOException {
 		Tag startTLS = Tag.empty("starttls");
 		startTLS.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls");
 		tagWriter.writeTag(startTLS);
@@ -378,25 +428,45 @@ public class XmppConnection implements Runnable {
 		} else if (this.streamFeatures.hasChild("mechanisms")
 				&& shouldAuthenticate) {
 			sendSaslAuth();
-		}
-		if (this.streamFeatures.hasChild("bind") && shouldBind) {
+		} else if (this.streamFeatures.hasChild("sm") && streamId != null) {
+			Log.d(LOGTAG,"found old stream id. trying to remuse");
+			ResumePacket resume = new ResumePacket(this.streamId,stanzasReceived);
+			this.tagWriter.writeStanzaAsync(resume);
+		} else if (this.streamFeatures.hasChild("bind") && shouldBind) {
 			sendBindRequest();
 			if (this.streamFeatures.hasChild("session")) {
+				Log.d(LOGTAG,"sending session");
 				IqPacket startSession = new IqPacket(IqPacket.TYPE_SET);
 				Element session = new Element("session");
 				session.setAttribute("xmlns",
 						"urn:ietf:params:xml:ns:xmpp-session");
 				session.setContent("");
 				startSession.addChild(session);
-				sendIqPacket(startSession, null);
-				tagWriter.writeElement(startSession);
+				this.sendIqPacket(startSession, null);
 			}
-			Element presence = new Element("presence");
-
-			tagWriter.writeElement(presence);
 		}
 	}
 
+	private void sendInitialPresence() {
+		PresencePacket packet = new PresencePacket();
+		packet.setAttribute("from", account.getFullJid());
+		if (account.getKeys().has("pgp_signature")) {
+			try {
+				String signature = account.getKeys().getString("pgp_signature");	
+				Element status = new Element("status");
+				status.setContent("online");
+				packet.addChild(status);
+				Element x = new Element("x");
+				x.setAttribute("xmlns", "jabber:x:signed");
+				x.setContent(signature);
+				packet.addChild(x);
+			} catch (JSONException e) {
+				//
+			}
+		}
+		this.sendPresencePacket(packet);
+	}
+
 	private void sendBindRequest() throws IOException {
 		IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
 		Element bind = new Element("bind");
@@ -412,10 +482,15 @@ public class XmppConnection implements Runnable {
 						.getContent().split("/")[1];
 				account.setResource(resource);
 				account.setStatus(Account.STATUS_ONLINE);
+				if (streamFeatures.hasChild("sm")) {
+					EnablePacket enable = new EnablePacket();
+					tagWriter.writeStanzaAsync(enable);
+				}
+				sendInitialPresence();
+				sendServiceDiscovery();
 				if (statusListener != null) {
 					statusListener.onStatusChanged(account);
 				}
-				sendServiceDiscovery();
 			}
 		});
 	}
@@ -471,7 +546,7 @@ public class XmppConnection implements Runnable {
 		Log.d(LOGTAG, "processStreamError");
 	}
 
-	private void sendStartStream() {
+	private void sendStartStream() throws IOException {
 		Tag stream = Tag.start("stream:stream");
 		stream.setAttribute("from", account.getJid());
 		stream.setAttribute("to", account.getServer());
@@ -489,39 +564,52 @@ public class XmppConnection implements Runnable {
 	public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) {
 		String id = nextRandomId();
 		packet.setAttribute("id", id);
-		tagWriter.writeElement(packet);
-		if (callback != null) {
-			packetCallbacks.put(id, callback);
-		}
+		this.sendPacket(packet, callback);
 	}
 
 	public void sendMessagePacket(MessagePacket packet) {
-		this.sendMessagePacket(packet, null);
+		this.sendPacket(packet, null);
 	}
 
 	public void sendMessagePacket(MessagePacket packet,
 			OnMessagePacketReceived callback) {
-		String id = nextRandomId();
-		packet.setAttribute("id", id);
-		tagWriter.writeElement(packet);
-		if (callback != null) {
-			packetCallbacks.put(id, callback);
-		}
+		this.sendPacket(packet, callback);
 	}
 
 	public void sendPresencePacket(PresencePacket packet) {
-		this.sendPresencePacket(packet, null);
+		this.sendPacket(packet, null);
 	}
 
-	public PresencePacket sendPresencePacket(PresencePacket packet,
+	public void sendPresencePacket(PresencePacket packet,
 			OnPresencePacketReceived callback) {
-		String id = nextRandomId();
-		packet.setAttribute("id", id);
-		tagWriter.writeElement(packet);
+		this.sendPacket(packet, callback);
+	}
+	
+	private synchronized void sendPacket(final AbstractStanza packet, PacketReceived callback) {
+		// TODO dont increment stanza count if packet = request packet or ack;
+		++stanzasSent;
+		tagWriter.writeStanzaAsync(packet);
 		if (callback != null) {
-			packetCallbacks.put(id, callback);
+			if (packet.getId()==null) {
+				packet.setId(nextRandomId());
+			}
+			packetCallbacks.put(packet.getId(), callback);
+		}
+	}
+	
+	public void sendPing() {
+		if (streamFeatures.hasChild("sm")) {
+			Log.d(LOGTAG,account.getJid()+": sending r as ping");
+			tagWriter.writeStanzaAsync(new RequestPacket());
+		} else {
+			Log.d(LOGTAG,account.getJid()+": sending iq as ping");
+			IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+			Element ping = new Element("ping");
+			iq.setAttribute("from",account.getFullJid());
+			ping.setAttribute("xmlns", "urn:xmpp:ping");
+			iq.addChild(ping);
+			this.sendIqPacket(iq, null);
 		}
-		return packet;
 	}
 
 	public void setOnMessagePacketReceivedListener(
@@ -547,8 +635,23 @@ public class XmppConnection implements Runnable {
 		this.tlsListener = listener;
 	}
 
-	public void disconnect() {
+	public void disconnect(boolean force) {
+		Log.d(LOGTAG,"disconnecting");
+		try {
+		if (force) {
+				socket.close();
+		}
+		tagWriter.finish();
+		while(!tagWriter.finished()) {
+			Log.d(LOGTAG,"not yet finished");
+			Thread.sleep(100);
+		}
 		tagWriter.writeTag(Tag.end("stream:stream"));
+		} catch (IOException e) {
+			Log.d(LOGTAG,"io exception during disconnect");
+		} catch (InterruptedException e) {
+			Log.d(LOGTAG,"interupted while waiting for disconnect");
+		}
 	}
 	
 	public boolean hasFeatureRosterManagment() {
@@ -558,4 +661,8 @@ public class XmppConnection implements Runnable {
 			return this.streamFeatures.hasChild("ver");
 		}
 	}
+
+	public void r() {
+		this.tagWriter.writeStanzaAsync(new RequestPacket());
+	}
 }
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
new file mode 100644
index 000000000..204a6bec7
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java
@@ -0,0 +1,34 @@
+package eu.siacs.conversations.xmpp.stanzas;
+
+import eu.siacs.conversations.xml.Element;
+
+public class AbstractStanza extends Element {
+
+	protected AbstractStanza(String name) {
+		super(name);
+	}
+
+	public String getTo() {
+		return getAttribute("to");
+	}
+
+	public String getFrom() {
+		return getAttribute("from");
+	}
+	
+	public String getId() {
+		return this.getAttribute("id");
+	}
+	
+	public void setTo(String to) {
+		setAttribute("to", to);
+	}
+	
+	public void setFrom(String from) {
+		setAttribute("from",from);
+	}
+	
+	public void setId(String id) {
+		setAttribute("id",id);
+	}
+}
diff --git a/src/eu/siacs/conversations/xmpp/IqPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
similarity index 73%
rename from src/eu/siacs/conversations/xmpp/IqPacket.java
rename to src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
index 2319fd28b..1675d19d6 100644
--- a/src/eu/siacs/conversations/xmpp/IqPacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/IqPacket.java
@@ -1,8 +1,7 @@
-package eu.siacs.conversations.xmpp;
+package eu.siacs.conversations.xmpp.stanzas;
 
-import eu.siacs.conversations.xml.Element;
 
-public class IqPacket extends Element {
+public class IqPacket extends AbstractStanza {
 	
 	public static final int TYPE_SET = 0;
 	public static final int TYPE_RESULT = 1;
@@ -33,8 +32,4 @@ public class IqPacket extends Element {
 		super("iq");
 	}
 
-	public String getId() {
-		return this.getAttribute("id");
-	}
-
 }
diff --git a/src/eu/siacs/conversations/xmpp/MessagePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
similarity index 75%
rename from src/eu/siacs/conversations/xmpp/MessagePacket.java
rename to src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
index a014155fc..f31a78e64 100644
--- a/src/eu/siacs/conversations/xmpp/MessagePacket.java
+++ b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
@@ -1,30 +1,18 @@
-package eu.siacs.conversations.xmpp;
+package eu.siacs.conversations.xmpp.stanzas;
 
 import eu.siacs.conversations.xml.Element;
 
-public class MessagePacket extends Element {
+public class MessagePacket extends AbstractStanza {
 	public static final int TYPE_CHAT = 0;
 	public static final int TYPE_UNKNOWN = 1;
 	public static final int TYPE_NO = 2;
 	public static final int TYPE_GROUPCHAT = 3;
 	public static final int TYPE_ERROR = 4;
-
-	private MessagePacket(String name) {
-		super(name);
-	}
 	
 	public MessagePacket() {
 		super("message");
 	}
 	
-	public String getTo() {
-		return getAttribute("to");
-	}
-
-	public String getFrom() {
-		return getAttribute("from");
-	}
-	
 	public String getBody() {
 		Element body = this.findChild("body");
 		if (body!=null) {
@@ -34,14 +22,6 @@ public class MessagePacket extends Element {
 		}
 	}
 	
-	public void setTo(String to) {
-		setAttribute("to", to);
-	}
-	
-	public void setFrom(String from) {
-		setAttribute("from",from);
-	}
-	
 	public void setBody(String text) {
 		this.children.remove(findChild("body"));
 		Element body = new Element("body");
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
new file mode 100644
index 000000000..dfbab78ca
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java
@@ -0,0 +1,9 @@
+package eu.siacs.conversations.xmpp.stanzas;
+
+
+public class PresencePacket extends AbstractStanza {
+	
+	public PresencePacket() {
+		super("presence");
+	}
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
new file mode 100644
index 000000000..7bc66e9b9
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java
@@ -0,0 +1,13 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class AckPacket extends AbstractStanza {
+
+	public AckPacket(int sequence) {
+		super("a");
+		this.setAttribute("xmlns","urn:xmpp:sm:3");
+		this.setAttribute("h", ""+sequence);
+	}
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
new file mode 100644
index 000000000..ae6a513aa
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java
@@ -0,0 +1,13 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class EnablePacket extends AbstractStanza {
+
+	public EnablePacket() {
+		super("enable");
+		this.setAttribute("xmlns","urn:xmpp:sm:3");
+		this.setAttribute("resume", "true");
+	}
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
new file mode 100644
index 000000000..4d409fd28
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java
@@ -0,0 +1,12 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class RequestPacket extends AbstractStanza {
+
+	public RequestPacket() {
+		super("r");
+		this.setAttribute("xmlns","urn:xmpp:sm:3");
+	}
+
+}
diff --git a/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
new file mode 100644
index 000000000..bebfa1a2c
--- /dev/null
+++ b/src/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java
@@ -0,0 +1,14 @@
+package eu.siacs.conversations.xmpp.stanzas.streammgmt;
+
+import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
+
+public class ResumePacket extends AbstractStanza {
+
+	public ResumePacket(String id, int sequence) {
+		super("resume");
+		this.setAttribute("xmlns","urn:xmpp:sm:3");
+		this.setAttribute("previd", id);
+		this.setAttribute("h", ""+sequence);
+	}
+
+}