コード例 #1
0
ファイル: AbstractParser.java プロジェクト: rizvan/Chat
 protected long getTimestamp(Element packet) {
   long now = System.currentTimeMillis();
   ArrayList<String> stamps = new ArrayList<>();
   for (Element child : packet.getChildren()) {
     if (child.getName().equals("delay")) {
       stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
     }
   }
   Collections.sort(stamps);
   if (stamps.size() >= 1) {
     try {
       String stamp = stamps.get(stamps.size() - 1);
       if (stamp.contains(".")) {
         Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US).parse(stamp);
         if (now < date.getTime()) {
           return now;
         } else {
           return date.getTime();
         }
       } else {
         Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(stamp);
         if (now < date.getTime()) {
           return now;
         } else {
           return date.getTime();
         }
       }
     } catch (ParseException e) {
       return now;
     }
   } else {
     return now;
   }
 }
コード例 #2
0
 private static String extractStanzaId(Element packet, Jid by) {
   for (Element child : packet.getChildren()) {
     if (child.getName().equals("stanza-id")
         && "urn:xmpp:sid:0".equals(child.getNamespace())
         && by.equals(child.getAttributeAsJid("by"))) {
       return child.getAttribute("id");
     }
   }
   return null;
 }
コード例 #3
0
 private void parseEvent(final Element event, final Jid from, final Account account) {
   Element items = event.findChild("items");
   String node = items == null ? null : items.getAttribute("node");
   if ("urn:xmpp:avatar:metadata".equals(node)) {
     Avatar avatar = Avatar.parseMetadata(items);
     if (avatar != null) {
       avatar.owner = from.toBareJid();
       if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) {
         if (account.getJid().toBareJid().equals(from)) {
           if (account.setAvatar(avatar.getFilename())) {
             mXmppConnectionService.databaseBackend.updateAccount(account);
           }
           mXmppConnectionService.getAvatarService().clear(account);
           mXmppConnectionService.updateConversationUi();
           mXmppConnectionService.updateAccountUi();
         } else {
           Contact contact = account.getRoster().getContact(from);
           contact.setAvatar(avatar);
           mXmppConnectionService.getAvatarService().clear(contact);
           mXmppConnectionService.updateConversationUi();
           mXmppConnectionService.updateRosterUi();
         }
       } else {
         mXmppConnectionService.fetchAvatar(account, avatar);
       }
     }
   } else if ("http://jabber.org/protocol/nick".equals(node)) {
     Element i = items.findChild("item");
     Element nick = i == null ? null : i.findChild("nick", "http://jabber.org/protocol/nick");
     if (nick != null && nick.getContent() != null) {
       Contact contact = account.getRoster().getContact(from);
       contact.setPresenceName(nick.getContent());
       mXmppConnectionService.getAvatarService().clear(account);
       mXmppConnectionService.updateConversationUi();
       mXmppConnectionService.updateAccountUi();
     }
   } else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) {
     Log.d(
         Config.LOGTAG,
         AxolotlService.getLogprefix(account)
             + "Received PEP device list update from "
             + from
             + ", processing...");
     Element item = items.findChild("item");
     Set<Integer> deviceIds = mXmppConnectionService.getIqParser().deviceIds(item);
     AxolotlService axolotlService = account.getAxolotlService();
     axolotlService.registerDevices(from, deviceIds);
     mXmppConnectionService.updateAccountUi();
   }
 }
コード例 #4
0
 private static List<String> getStatusCodes(Element x) {
   List<String> codes = new ArrayList<>();
   if (x != null) {
     for (Element child : x.getChildren()) {
       if (child.getName().equals("status")) {
         String code = child.getAttribute("code");
         if (code != null) {
           codes.add(code);
         }
       }
     }
   }
   return codes;
 }
コード例 #5
0
  public void parseSubscriptionFromElement(Element item) {
    String ask = item.getAttribute("ask");
    String subscription = item.getAttribute("subscription");

    if (subscription != null) {
      switch (subscription) {
        case "to":
          this.resetOption(Options.FROM);
          this.setOption(Options.TO);
          break;
        case "from":
          this.resetOption(Options.TO);
          this.setOption(Options.FROM);
          this.resetOption(Options.PREEMPTIVE_GRANT);
          break;
        case "both":
          this.setOption(Options.TO);
          this.setOption(Options.FROM);
          this.resetOption(Options.PREEMPTIVE_GRANT);
          break;
        case "none":
          this.resetOption(Options.FROM);
          this.resetOption(Options.TO);
          break;
      }
    }

    // do NOT override asking if pending push request
    if (!this.getOption(Contact.Options.DIRTY_PUSH)) {
      if ((ask != null) && (ask.equals("subscribe"))) {
        this.setOption(Contact.Options.ASKING);
      } else {
        this.resetOption(Contact.Options.ASKING);
      }
    }
  }
コード例 #6
0
 private Invite extractInvite(Element message) {
   Element x = message.findChild("x", "http://jabber.org/protocol/muc#user");
   if (x != null) {
     Element invite = x.findChild("invite");
     if (invite != null) {
       Element pw = x.findChild("password");
       return new Invite(message.getAttributeAsJid("from"), pw != null ? pw.getContent() : null);
     }
   } else {
     x = message.findChild("x", "jabber:x:conference");
     if (x != null) {
       return new Invite(x.getAttributeAsJid("jid"), x.getAttribute("password"));
     }
   }
   return null;
 }
コード例 #7
0
ファイル: AbstractParser.java プロジェクト: rizvan/Chat
 protected void updateLastseen(
     final Element packet, final Account account, final boolean presenceOverwrite) {
   Jid from;
   try {
     from = Jid.fromString(packet.getAttribute("from")).toBareJid();
   } catch (final InvalidJidException e) {
     // TODO: Handle this?
     from = null;
   }
   String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
   Contact contact = account.getRoster().getContact(from);
   long timestamp = getTimestamp(packet);
   if (timestamp >= contact.lastseen.time) {
     contact.lastseen.time = timestamp;
     if (!presence.isEmpty() && presenceOverwrite) {
       contact.lastseen.presence = presence;
     }
   }
 }
コード例 #8
0
  @Override
  public void onMessagePacketReceived(Account account, MessagePacket original) {
    if (handleErrorMessage(account, original)) {
      return;
    }
    final MessagePacket packet;
    Long timestamp = null;
    final boolean isForwarded;
    boolean isCarbon = false;
    String serverMsgId = null;
    final Element fin = original.findChild("fin", "urn:xmpp:mam:0");
    if (fin != null) {
      mXmppConnectionService.getMessageArchiveService().processFin(fin, original.getFrom());
      return;
    }
    final Element result = original.findChild("result", "urn:xmpp:mam:0");
    final MessageArchiveService.Query query =
        result == null
            ? null
            : mXmppConnectionService
                .getMessageArchiveService()
                .findQuery(result.getAttribute("queryid"));
    if (query != null && query.validFrom(original.getFrom())) {
      Pair<MessagePacket, Long> f = original.getForwardedMessagePacket("result", "urn:xmpp:mam:0");
      if (f == null) {
        return;
      }
      timestamp = f.second;
      packet = f.first;
      isForwarded = true;
      serverMsgId = result.getAttribute("id");
      query.incrementTotalCount();
    } else if (query != null) {
      Log.d(
          Config.LOGTAG,
          account.getJid().toBareJid() + ": received mam result from invalid sender");
      return;
    } else if (original.fromServer(account)) {
      Pair<MessagePacket, Long> f;
      f = original.getForwardedMessagePacket("received", "urn:xmpp:carbons:2");
      f = f == null ? original.getForwardedMessagePacket("sent", "urn:xmpp:carbons:2") : f;
      packet = f != null ? f.first : original;
      if (handleErrorMessage(account, packet)) {
        return;
      }
      timestamp = f != null ? f.second : null;
      isCarbon = f != null;
      isForwarded = isCarbon;
    } else {
      packet = original;
      isForwarded = false;
    }

    if (timestamp == null) {
      timestamp = AbstractParser.getTimestamp(packet, System.currentTimeMillis());
    }
    final String body = packet.getBody();
    final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
    final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
    final Element axolotlEncrypted =
        packet.findChild(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
    int status;
    final Jid counterpart;
    final Jid to = packet.getTo();
    final Jid from = packet.getFrom();
    final String remoteMsgId = packet.getId();

    if (from == null || to == null) {
      Log.d(Config.LOGTAG, "no to or from in: " + packet.toString());
      return;
    }

    boolean isTypeGroupChat = packet.getType() == MessagePacket.TYPE_GROUPCHAT;
    boolean isProperlyAddressed = !to.isBareJid() || account.countPresences() == 1;
    boolean isMucStatusMessage =
        from.isBareJid() && mucUserElement != null && mucUserElement.hasChild("status");
    if (packet.fromAccount(account)) {
      status = Message.STATUS_SEND;
      counterpart = to;
    } else {
      status = Message.STATUS_RECEIVED;
      counterpart = from;
    }

    Invite invite = extractInvite(packet);
    if (invite != null && invite.execute(account)) {
      return;
    }

    if (extractChatState(mXmppConnectionService.find(account, counterpart.toBareJid()), packet)) {
      mXmppConnectionService.updateConversationUi();
    }

    if ((body != null || pgpEncrypted != null || axolotlEncrypted != null) && !isMucStatusMessage) {
      Conversation conversation =
          mXmppConnectionService.findOrCreateConversation(
              account, counterpart.toBareJid(), isTypeGroupChat, query);
      if (isTypeGroupChat) {
        if (counterpart.getResourcepart().equals(conversation.getMucOptions().getActualNick())) {
          status = Message.STATUS_SEND_RECEIVED;
          if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status)) {
            return;
          } else if (remoteMsgId == null || Config.IGNORE_ID_REWRITE_IN_MUC) {
            Message message = conversation.findSentMessageWithBody(packet.getBody());
            if (message != null) {
              mXmppConnectionService.markMessage(message, status);
              return;
            }
          }
        } else {
          status = Message.STATUS_RECEIVED;
        }
      }
      Message message;
      if (body != null && body.startsWith("?OTR")) {
        if (!isForwarded && !isTypeGroupChat && isProperlyAddressed) {
          message = parseOtrChat(body, from, remoteMsgId, conversation);
          if (message == null) {
            return;
          }
        } else {
          message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
        }
      } else if (pgpEncrypted != null) {
        message = parsePGPChat(conversation, pgpEncrypted, status);
      } else if (axolotlEncrypted != null) {
        message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
        if (message == null) {
          return;
        }
      } else {
        message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
      }

      if (serverMsgId == null) {
        serverMsgId =
            extractStanzaId(
                packet, isTypeGroupChat ? conversation.getJid().toBareJid() : account.getServer());
      }

      message.setCounterpart(counterpart);
      message.setRemoteMsgId(remoteMsgId);
      message.setServerMsgId(serverMsgId);
      message.setCarbon(isCarbon);
      message.setTime(timestamp);
      message.markable = packet.hasChild("markable", "urn:xmpp:chat-markers:0");
      if (conversation.getMode() == Conversation.MODE_MULTI) {
        Jid trueCounterpart =
            conversation.getMucOptions().getTrueCounterpart(counterpart.getResourcepart());
        message.setTrueCounterpart(trueCounterpart);
        if (trueCounterpart != null) {
          updateLastseen(packet, account, trueCounterpart, false);
        }
        if (!isTypeGroupChat) {
          message.setType(Message.TYPE_PRIVATE);
        }
      }
      updateLastseen(packet, account, true);
      boolean checkForDuplicates =
          query != null
              || (isTypeGroupChat && packet.hasChild("delay", "urn:xmpp:delay"))
              || message.getType() == Message.TYPE_PRIVATE;
      if (checkForDuplicates && conversation.hasDuplicateMessage(message)) {
        Log.d(
            Config.LOGTAG,
            "skipping duplicate message from "
                + message.getCounterpart().toString()
                + " "
                + message.getBody());
        return;
      }

      conversation.add(message);

      if (query == null || query.getWith() == null) { // either no mam or catchup
        if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) {
          mXmppConnectionService.markRead(conversation);
          if (query == null) {
            account.activateGracePeriod();
          }
        } else {
          message.markUnread();
        }
      }

      if (query != null) {
        query.incrementMessageCount();
      } else {
        mXmppConnectionService.updateConversationUi();
      }

      if (mXmppConnectionService.confirmMessages()
          && remoteMsgId != null
          && !isForwarded
          && !isTypeGroupChat) {
        ArrayList<String> receiptsNamespaces = new ArrayList<>();
        if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
          receiptsNamespaces.add("urn:xmpp:chat-markers:0");
        }
        if (packet.hasChild("request", "urn:xmpp:receipts")) {
          receiptsNamespaces.add("urn:xmpp:receipts");
        }
        if (receiptsNamespaces.size() > 0) {
          MessagePacket receipt =
              mXmppConnectionService
                  .getMessageGenerator()
                  .received(account, packet, receiptsNamespaces, packet.getType());
          mXmppConnectionService.sendMessagePacket(account, receipt);
        }
      }

      if (message.getStatus() == Message.STATUS_RECEIVED
          && conversation.getOtrSession() != null
          && !conversation
              .getOtrSession()
              .getSessionID()
              .getUserID()
              .equals(message.getCounterpart().getResourcepart())) {
        conversation.endOtrIfNeeded();
      }

      if (message.getEncryption() == Message.ENCRYPTION_NONE
          || mXmppConnectionService.saveEncryptedMessages()) {
        mXmppConnectionService.databaseBackend.createMessage(message);
      }
      final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
      if (message.trusted()
          && message.treatAsDownloadable() != Message.Decision.NEVER
          && manager.getAutoAcceptFileSize() > 0) {
        manager.createNewDownloadConnection(message);
      } else if (!message.isRead()) {
        if (query == null) {
          mXmppConnectionService.getNotificationService().push(message);
        } else if (query.getWith() == null) { // mam catchup
          mXmppConnectionService.getNotificationService().pushFromBacklog(message);
        }
      }
    } else { // no body
      if (isTypeGroupChat) {
        Conversation conversation = mXmppConnectionService.find(account, from.toBareJid());
        if (packet.hasChild("subject")) {
          if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
            conversation.setHasMessagesLeftOnServer(conversation.countMessages() > 0);
            String subject = packet.findChildContent("subject");
            conversation.getMucOptions().setSubject(subject);
            final Bookmark bookmark = conversation.getBookmark();
            if (bookmark != null && bookmark.getBookmarkName() == null) {
              if (bookmark.setBookmarkName(subject)) {
                mXmppConnectionService.pushBookmarks(account);
              }
            }
            mXmppConnectionService.updateConversationUi();
            return;
          }
        }

        if (conversation != null && isMucStatusMessage) {
          for (Element child : mucUserElement.getChildren()) {
            if (child.getName().equals("status")
                && MucOptions.STATUS_CODE_ROOM_CONFIG_CHANGED.equals(child.getAttribute("code"))) {
              mXmppConnectionService.fetchConferenceConfiguration(conversation);
            }
          }
        }
      }
    }

    Element received = packet.findChild("received", "urn:xmpp:chat-markers:0");
    if (received == null) {
      received = packet.findChild("received", "urn:xmpp:receipts");
    }
    if (received != null && !packet.fromAccount(account)) {
      mXmppConnectionService.markMessage(
          account, from.toBareJid(), received.getAttribute("id"), Message.STATUS_SEND_RECEIVED);
    }
    Element displayed = packet.findChild("displayed", "urn:xmpp:chat-markers:0");
    if (displayed != null) {
      if (packet.fromAccount(account)) {
        Conversation conversation = mXmppConnectionService.find(account, counterpart.toBareJid());
        if (conversation != null) {
          mXmppConnectionService.markRead(conversation);
        }
      } else {
        updateLastseen(packet, account, true);
        final Message displayedMessage =
            mXmppConnectionService.markMessage(
                account,
                from.toBareJid(),
                displayed.getAttribute("id"),
                Message.STATUS_SEND_DISPLAYED);
        Message message = displayedMessage == null ? null : displayedMessage.prev();
        while (message != null
            && message.getStatus() == Message.STATUS_SEND_RECEIVED
            && message.getTimeSent() < displayedMessage.getTimeSent()) {
          mXmppConnectionService.markMessage(message, Message.STATUS_SEND_DISPLAYED);
          message = message.prev();
        }
      }
    }

    Element event = packet.findChild("event", "http://jabber.org/protocol/pubsub#event");
    if (event != null) {
      parseEvent(event, from, account);
    }

    String nick = packet.findChildContent("nick", "http://jabber.org/protocol/nick");
    if (nick != null) {
      Contact contact = account.getRoster().getContact(from);
      contact.setPresenceName(nick);
    }
  }
コード例 #9
0
 private void processStream(Tag currentTag)
     throws XmlPullParserException, IOException, NoSuchAlgorithmException {
   Tag nextTag = tagReader.readTag();
   while ((nextTag != null) && (!nextTag.isEnd("stream"))) {
     if (nextTag.isStart("error")) {
       processStreamError(nextTag);
     } else if (nextTag.isStart("features")) {
       processStreamFeatures(nextTag);
       if ((streamFeatures.getChildren().size() == 1)
           && (streamFeatures.hasChild("starttls"))
           && (!account.isOptionSet(Account.OPTION_USETLS))) {
         changeStatus(Account.STATUS_SERVER_REQUIRES_TLS);
       }
     } else if (nextTag.isStart("proceed")) {
       switchOverToTls(nextTag);
     } else if (nextTag.isStart("compressed")) {
       switchOverToZLib(nextTag);
     } else if (nextTag.isStart("success")) {
       Log.d(LOGTAG, account.getJid() + ": logged in");
       tagReader.readTag();
       tagReader.reset();
       sendStartStream();
       processStream(tagReader.readTag());
       break;
     } else if (nextTag.isStart("failure")) {
       Element failure = tagReader.readElement(nextTag);
       changeStatus(Account.STATUS_UNAUTHORIZED);
     } else if (nextTag.isStart("challenge")) {
       String challange = tagReader.readElement(nextTag).getContent();
       Element response = new Element("response");
       response.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
       response.setContent(CryptoHelper.saslDigestMd5(account, challange));
       tagWriter.writeElement(response);
     } 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(" + smVersion + ") enabled (resumable)");
       } else {
         Log.d(LOGTAG, account.getJid() + ": stream managment(" + smVersion + ") enabled");
       }
       this.lastSessionStarted = SystemClock.elapsedRealtime();
       this.stanzasReceived = 0;
       RequestPacket r = new RequestPacket(smVersion);
       tagWriter.writeStanzaAsync(r);
     } else if (nextTag.isStart("resumed")) {
       tagReader.readElement(nextTag);
       sendPing();
       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, smVersion);
       // 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("failed")) {
       tagReader.readElement(nextTag);
       Log.d(LOGTAG, account.getJid() + ": resumption failed");
       streamId = null;
       if (account.getStatus() != Account.STATUS_ONLINE) {
         sendBindRequest();
       }
     } else if (nextTag.isStart("iq")) {
       processIq(nextTag);
     } else if (nextTag.isStart("message")) {
       processMessage(nextTag);
     } else if (nextTag.isStart("presence")) {
       processPresence(nextTag);
     } else {
       Log.d(
           LOGTAG,
           "found unexpected tag: " + nextTag.getName() + " as child of " + currentTag.getName());
     }
     nextTag = tagReader.readTag();
   }
   if (account.getStatus() == Account.STATUS_ONLINE) {
     account.setStatus(Account.STATUS_OFFLINE);
     if (statusListener != null) {
       statusListener.onStatusChanged(account);
     }
   }
 }
コード例 #10
0
ファイル: MucOptions.java プロジェクト: rizvan/Chat
 public void processPacket(PresencePacket packet, PgpEngine pgp) {
   final Jid from = packet.getFrom();
   if (!from.isBareJid()) {
     final String name = from.getResourcepart();
     String type = packet.getAttribute("type");
     if (type == null) {
       User user = new User();
       Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
       if (x != null) {
         Element item = x.findChild("item");
         if (item != null) {
           user.setName(name);
           user.setAffiliation(item.getAttribute("affiliation"));
           user.setRole(item.getAttribute("role"));
           user.setJid(item.getAttributeAsJid("jid"));
           user.setName(name);
           if (name.equals(this.joinnick)) {
             this.isOnline = true;
             this.error = ERROR_NO_ERROR;
             self = user;
             if (aboutToRename) {
               if (renameListener != null) {
                 renameListener.onRename(true);
               }
               aboutToRename = false;
             }
           } else {
             addUser(user);
           }
           if (pgp != null) {
             Element signed = packet.findChild("x", "jabber:x:signed");
             if (signed != null) {
               Element status = packet.findChild("status");
               String msg;
               if (status != null) {
                 msg = status.getContent();
               } else {
                 msg = "";
               }
               user.setPgpKeyId(pgp.fetchKeyId(account, msg, signed.getContent()));
             }
           }
         }
       }
     } else if (type.equals("unavailable") && name.equals(this.joinnick)) {
       Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
       if (x != null) {
         Element status = x.findChild("status");
         if (status != null) {
           String code = status.getAttribute("code");
           if (STATUS_CODE_KICKED.equals(code)) {
             this.isOnline = false;
             this.error = KICKED_FROM_ROOM;
           } else if (STATUS_CODE_BANNED.equals(code)) {
             this.isOnline = false;
             this.error = ERROR_BANNED;
           }
         }
       }
     } else if (type.equals("unavailable")) {
       deleteUser(packet.getAttribute("from").split("/", 2)[1]);
     } else if (type.equals("error")) {
       Element error = packet.findChild("error");
       if (error != null && error.hasChild("conflict")) {
         if (aboutToRename) {
           if (renameListener != null) {
             renameListener.onRename(false);
           }
           aboutToRename = false;
           this.setJoinNick(getActualNick());
         } else {
           this.error = ERROR_NICK_IN_USE;
         }
       } else if (error != null && error.hasChild("not-authorized")) {
         this.error = ERROR_PASSWORD_REQUIRED;
       } else if (error != null && error.hasChild("forbidden")) {
         this.error = ERROR_BANNED;
       } else if (error != null && error.hasChild("registration-required")) {
         this.error = ERROR_MEMBERS_ONLY;
       }
     }
   }
 }
コード例 #11
0
 private void processConferencePresence(PresencePacket packet, MucOptions mucOptions) {
   final Jid from = packet.getFrom();
   if (!from.isBareJid()) {
     final String type = packet.getAttribute("type");
     final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
     Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
     final List<String> codes = getStatusCodes(x);
     if (type == null) {
       if (x != null) {
         Element item = x.findChild("item");
         if (item != null && !from.isBareJid()) {
           mucOptions.setError(MucOptions.ERROR_NO_ERROR);
           MucOptions.User user = new MucOptions.User(mucOptions, from);
           user.setAffiliation(item.getAttribute("affiliation"));
           user.setRole(item.getAttribute("role"));
           user.setJid(item.getAttributeAsJid("jid"));
           if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE)
               || packet.getFrom().equals(mucOptions.getConversation().getJid())) {
             mucOptions.setOnline();
             mucOptions.setSelf(user);
             if (mucOptions.mNickChangingInProgress) {
               if (mucOptions.onRenameListener != null) {
                 mucOptions.onRenameListener.onSuccess();
               }
               mucOptions.mNickChangingInProgress = false;
             }
           } else {
             mucOptions.addUser(user);
           }
           if (mXmppConnectionService.getPgpEngine() != null) {
             Element signed = packet.findChild("x", "jabber:x:signed");
             if (signed != null) {
               Element status = packet.findChild("status");
               String msg = status == null ? "" : status.getContent();
               long keyId =
                   mXmppConnectionService
                       .getPgpEngine()
                       .fetchKeyId(mucOptions.getAccount(), msg, signed.getContent());
               if (keyId != 0) {
                 user.setPgpKeyId(keyId);
               }
             }
           }
           if (avatar != null) {
             avatar.owner = from;
             if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) {
               if (user.setAvatar(avatar)) {
                 mXmppConnectionService.getAvatarService().clear(user);
               }
             } else {
               mXmppConnectionService.fetchAvatar(mucOptions.getAccount(), avatar);
             }
           }
         }
       }
     } else if (type.equals("unavailable")) {
       if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE)
           || packet.getFrom().equals(mucOptions.getConversation().getJid())) {
         if (codes.contains(MucOptions.STATUS_CODE_CHANGED_NICK)) {
           mucOptions.mNickChangingInProgress = true;
         } else if (codes.contains(MucOptions.STATUS_CODE_KICKED)) {
           mucOptions.setError(MucOptions.KICKED_FROM_ROOM);
         } else if (codes.contains(MucOptions.STATUS_CODE_BANNED)) {
           mucOptions.setError(MucOptions.ERROR_BANNED);
         } else if (codes.contains(MucOptions.STATUS_CODE_LOST_MEMBERSHIP)) {
           mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY);
         } else {
           mucOptions.setError(MucOptions.ERROR_UNKNOWN);
           Log.d(Config.LOGTAG, "unknown error in conference: " + packet);
         }
       } else if (!from.isBareJid()) {
         MucOptions.User user = mucOptions.deleteUser(from.getResourcepart());
         if (user != null) {
           mXmppConnectionService.getAvatarService().clear(user);
         }
       }
     } else if (type.equals("error")) {
       Element error = packet.findChild("error");
       if (error != null && error.hasChild("conflict")) {
         if (mucOptions.online()) {
           if (mucOptions.onRenameListener != null) {
             mucOptions.onRenameListener.onFailure();
           }
         } else {
           mucOptions.setError(MucOptions.ERROR_NICK_IN_USE);
         }
       } else if (error != null && error.hasChild("not-authorized")) {
         mucOptions.setError(MucOptions.ERROR_PASSWORD_REQUIRED);
       } else if (error != null && error.hasChild("forbidden")) {
         mucOptions.setError(MucOptions.ERROR_BANNED);
       } else if (error != null && error.hasChild("registration-required")) {
         mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY);
       }
     }
   }
 }