OpenPgpContentElementProvider.java

  1. /**
  2.  *
  3.  * Copyright 2017-2021 Florian Schmaus, 2018 Paul Schaub.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.ox.provider;

  18. import java.io.IOException;
  19. import java.text.ParseException;
  20. import java.util.Date;
  21. import java.util.HashSet;
  22. import java.util.LinkedList;
  23. import java.util.List;
  24. import java.util.Set;
  25. import java.util.logging.Level;
  26. import java.util.logging.Logger;

  27. import org.jivesoftware.smack.packet.ExtensionElement;
  28. import org.jivesoftware.smack.packet.XmlEnvironment;
  29. import org.jivesoftware.smack.parsing.SmackParsingException;
  30. import org.jivesoftware.smack.provider.ExtensionElementProvider;
  31. import org.jivesoftware.smack.provider.ProviderManager;
  32. import org.jivesoftware.smack.util.PacketParserUtils;
  33. import org.jivesoftware.smack.util.ParserUtils;
  34. import org.jivesoftware.smack.xml.XmlPullParser;
  35. import org.jivesoftware.smack.xml.XmlPullParserException;

  36. import org.jivesoftware.smackx.ox.element.CryptElement;
  37. import org.jivesoftware.smackx.ox.element.EncryptedOpenPgpContentElement;
  38. import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
  39. import org.jivesoftware.smackx.ox.element.SignElement;
  40. import org.jivesoftware.smackx.ox.element.SigncryptElement;

  41. import org.jxmpp.jid.Jid;
  42. import org.jxmpp.jid.impl.JidCreate;

  43. /**
  44.  * Abstract {@link ExtensionElementProvider} implementation for the also abstract {@link OpenPgpContentElement}.
  45.  *
  46.  * @param <O> Specialized subclass of {@link OpenPgpContentElement}.
  47.  */
  48. public abstract class OpenPgpContentElementProvider<O extends OpenPgpContentElement> extends ExtensionElementProvider<O> {

  49.     private static final Logger LOGGER = Logger.getLogger(OpenPgpContentElementProvider.class.getName());

  50.     public static OpenPgpContentElement parseOpenPgpContentElement(String element)
  51.             throws XmlPullParserException, IOException {
  52.         XmlPullParser parser = PacketParserUtils.getParserFor(element);
  53.         return parseOpenPgpContentElement(parser);
  54.     }

  55.     public static OpenPgpContentElement parseOpenPgpContentElement(XmlPullParser parser)
  56.             throws  XmlPullParserException {
  57.         try {
  58.             switch (parser.getName()) {
  59.                 case SigncryptElement.ELEMENT:
  60.                     return SigncryptElementProvider.INSTANCE.parse(parser);
  61.                 case SignElement.ELEMENT:
  62.                     return SignElementProvider.INSTANCE.parse(parser);
  63.                 case CryptElement.ELEMENT:
  64.                     return CryptElementProvider.INSTANCE.parse(parser);
  65.                 default: throw new XmlPullParserException("Expected <crypt/>, <sign/> or <signcrypt/> element, " +
  66.                         "but got neither of them.");
  67.             }
  68.         } catch (Exception e) {
  69.             throw new XmlPullParserException(e.getMessage());
  70.         }
  71.     }

  72.     @Override
  73.     public abstract O parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
  74.                     throws XmlPullParserException, IOException, SmackParsingException, ParseException;

  75.     protected static OpenPgpContentElementData parseOpenPgpContentElementData(XmlPullParser parser, int initialDepth)
  76.             throws XmlPullParserException, IOException, SmackParsingException, ParseException {
  77.         Set<Jid> to = new HashSet<>();
  78.         Date timestamp = null;
  79.         String rpad = null;
  80.         List<ExtensionElement> payload = new LinkedList<>();

  81.         outerloop: while (true) {
  82.             XmlPullParser.Event tag = parser.next();
  83.             String name = parser.getName();
  84.             switch (tag) {
  85.                 case START_ELEMENT:
  86.                     switch (name) {

  87.                         case OpenPgpContentElement.ELEM_TIME:
  88.                             String stamp = parser.getAttributeValue("", OpenPgpContentElement.ATTR_STAMP);
  89.                             timestamp = ParserUtils.getDateFromXep82String(stamp);
  90.                             break;

  91.                         case OpenPgpContentElement.ELEM_TO:
  92.                             String jid = parser.getAttributeValue("", OpenPgpContentElement.ATTR_JID);
  93.                             to.add(JidCreate.bareFrom(jid));
  94.                             break;

  95.                         case EncryptedOpenPgpContentElement.ELEM_RPAD:
  96.                             rpad = parser.nextText();
  97.                             break;

  98.                         case OpenPgpContentElement.ELEM_PAYLOAD:
  99.                             innerloop: while (true) {
  100.                                 XmlPullParser.Event ptag = parser.next();
  101.                                 String pname = parser.getName();
  102.                                 String pns = parser.getNamespace();
  103.                                 switch (ptag) {
  104.                                     case START_ELEMENT:
  105.                                         ExtensionElementProvider<ExtensionElement> provider =
  106.                                                 ProviderManager.getExtensionProvider(pname, pns);
  107.                                         if (provider == null) {
  108.                                             LOGGER.log(Level.INFO, "No provider found for " + pname + " " + pns);
  109.                                             continue innerloop;
  110.                                         }
  111.                                         payload.add(provider.parse(parser));
  112.                                         break;

  113.                                     case END_ELEMENT:
  114.                                         break innerloop;

  115.                                     default:
  116.                                         // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
  117.                                         break;
  118.                                 }
  119.                             }
  120.                             break;
  121.                     }
  122.                     break;

  123.                 case END_ELEMENT:
  124.                     switch (name) {
  125.                         case CryptElement.ELEMENT:
  126.                         case SigncryptElement.ELEMENT:
  127.                         case SignElement.ELEMENT:
  128.                             break outerloop;
  129.                     }
  130.                     break;

  131.                 default:
  132.                     // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
  133.                     break;
  134.             }
  135.         }

  136.         return new OpenPgpContentElementData(to, timestamp, rpad, payload);
  137.     }

  138.     protected static final class OpenPgpContentElementData {
  139.         final Set<Jid> to;
  140.         final Date timestamp;
  141.         final String rpad;
  142.         final List<ExtensionElement> payload;

  143.         private OpenPgpContentElementData(Set<Jid> to, Date timestamp, String rpad, List<ExtensionElement> payload) {
  144.             this.to = to;
  145.             this.timestamp = timestamp;
  146.             this.rpad = rpad;
  147.             this.payload = payload;
  148.         }
  149.     }
  150. }