AnsweredAssumed Answered

Smack 4.2.0 Account Manager enhancement request to support inBand catpcha registration with Bob XEP-0231 implementation source attached.

Question asked by cmeng on Jan 2, 2017
Latest reply on Jan 8, 2017 by cmeng


Updated and to store the bob data in Base64 to be consistent with smack library and XEP document.

and pass DataForm to onCaptchaRequested instead of Form for better backend processing


Below is an extraction of the implementation for aTalk to support server inBand registration with catpcha protection. The implementation requires access to method AccountManager#getRegistrationInfo(); however it is currently implemented as "private" not accessible to outside. Because of this, I have to duplicate the getRegistrationInfo() function in AccountManager in my shown below.


Appreciate the Smack development team would consider to expose the method public and make info as returned object.

I have implemented the "XEP-0231: Bits of Binary" and attached the source with this message. The smack development team is welcome to include them in the standard smack library release.



* Perform the InBand Registration for the accountId on the defined XMPP connection by pps.
* Registration can either be:
* - simple username and password or
* - With catpcha protection using form with embedded catpcha image if available, else the
* image is retrieved from the given url in the form.
* @param pps
* The protocolServiceProvider.
* @param accountId
* The username accountID for registration.
* @throws XMPPException,
* SmackException
public boolean registerAccount(ProtocolProviderServiceJabberImpl pps, AccountID accountId)
   throws XMPPException, SmackException
   XMPPTCPConnection connection = pps.getConnection();
   try {
   if (!connection.isConnected())

   AccountManager accountManager = AccountManager.getInstance(connection);
   if (accountManager.isSupported()) {
   Registration info = getRegistrationInfo(connection);
   if (info != null) {
   Form form = null;
   DataForm dataFrom = info.getExtension(DataForm.ELEMENT, DataForm.NAMESPACE);


   Bitmap captcha = null;
   Bob bob = info.getExtension(Bob.ELEMENT, Bob.NAMESPACE);
   if (bob != null) {
   byte[] bytData = Base64.decode(bob.getData());
   InputStream stream = new ByteArrayInputStream(bytData);
   captcha = BitmapFactory.decodeStream(stream);
   else {
   FormField urlField = (FormField) dataFrom.getField("url");
   if (urlField != null) {
   String urlString = urlField.getValues().get(0);
   URL uri = new URL(urlString);
   captcha = BitmapFactory.decodeStream(uri.openConnection().getInputStream());
   if ((captcha != null) && (dataFrom != null)) {
   pps.mOnCaptchaRequested.onCaptchaRequested(connection, accountId, dataFrom , captcha);
   return false;
   else {
   String userName = accountId.getUserID();
   Localpart username = JidCreate.bareFrom(userName).getLocalpartOrNull();
   accountManager.createAccount(username, password);
   return false;
   catch (IOException | InterruptedException ex) {
   // No response received within reply timeout. Timeout was 5000ms (~5s).
  // Rethrow XMPPException will trigger a re-login / registration dialog
   String exMsg = ex.getMessage();
   XMPPError.Builder xmppErrorBuilder
   = XMPPError.from(XMPPError.Condition.not_authorized, exMsg);
   throw new XMPPException.XMPPErrorException(null,;
   return true;

private synchronized Registration getRegistrationInfo(XMPPTCPConnection connection)
   throws SmackException.NoResponseException, XMPPException.XMPPErrorException,
   SmackException.NotConnectedException, InterruptedException
   Registration reg = new Registration();
   return createPacketCollectorAndSend(connection, reg).nextResultOrThrow();

private PacketCollector createPacketCollectorAndSend(XMPPTCPConnection connection, IQ req)
   throws SmackException.NotConnectedException, InterruptedException
   PacketCollector collector = connection.createPacketCollectorAndSend(new StanzaIdFilter(req.getStanzaId()), req);
   return collector;