001/** 002 * 003 * Copyright 2017-2019 Florian Schmaus, 2018 Paul Schaub. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.ox.provider; 018 019import java.io.IOException; 020import java.util.Date; 021import java.util.HashSet; 022import java.util.LinkedList; 023import java.util.List; 024import java.util.Set; 025import java.util.logging.Level; 026import java.util.logging.Logger; 027 028import org.jivesoftware.smack.packet.ExtensionElement; 029import org.jivesoftware.smack.packet.XmlEnvironment; 030import org.jivesoftware.smack.parsing.SmackParsingException; 031import org.jivesoftware.smack.provider.ExtensionElementProvider; 032import org.jivesoftware.smack.provider.ProviderManager; 033import org.jivesoftware.smack.util.PacketParserUtils; 034import org.jivesoftware.smack.util.ParserUtils; 035import org.jivesoftware.smack.xml.XmlPullParser; 036import org.jivesoftware.smack.xml.XmlPullParserException; 037 038import org.jivesoftware.smackx.ox.element.CryptElement; 039import org.jivesoftware.smackx.ox.element.EncryptedOpenPgpContentElement; 040import org.jivesoftware.smackx.ox.element.OpenPgpContentElement; 041import org.jivesoftware.smackx.ox.element.SignElement; 042import org.jivesoftware.smackx.ox.element.SigncryptElement; 043 044import org.jxmpp.jid.Jid; 045import org.jxmpp.jid.impl.JidCreate; 046 047/** 048 * Abstract {@link ExtensionElementProvider} implementation for the also abstract {@link OpenPgpContentElement}. 049 * 050 * @param <O> Specialized subclass of {@link OpenPgpContentElement}. 051 */ 052public abstract class OpenPgpContentElementProvider<O extends OpenPgpContentElement> extends ExtensionElementProvider<O> { 053 054 private static final Logger LOGGER = Logger.getLogger(OpenPgpContentElementProvider.class.getName()); 055 056 public static OpenPgpContentElement parseOpenPgpContentElement(String element) 057 throws XmlPullParserException, IOException { 058 XmlPullParser parser = PacketParserUtils.getParserFor(element); 059 return parseOpenPgpContentElement(parser); 060 } 061 062 public static OpenPgpContentElement parseOpenPgpContentElement(XmlPullParser parser) 063 throws XmlPullParserException { 064 try { 065 switch (parser.getName()) { 066 case SigncryptElement.ELEMENT: 067 return SigncryptElementProvider.INSTANCE.parse(parser); 068 case SignElement.ELEMENT: 069 return SignElementProvider.INSTANCE.parse(parser); 070 case CryptElement.ELEMENT: 071 return CryptElementProvider.INSTANCE.parse(parser); 072 default: throw new XmlPullParserException("Expected <crypt/>, <sign/> or <signcrypt/> element, " + 073 "but got neither of them."); 074 } 075 } catch (Exception e) { 076 throw new XmlPullParserException(e.getMessage()); 077 } 078 } 079 080 @Override 081 public abstract O parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException; 082 083 protected static OpenPgpContentElementData parseOpenPgpContentElementData(XmlPullParser parser, int initialDepth) 084 throws XmlPullParserException, IOException, SmackParsingException { 085 Set<Jid> to = new HashSet<>(); 086 Date timestamp = null; 087 String rpad = null; 088 List<ExtensionElement> payload = new LinkedList<>(); 089 090 outerloop: while (true) { 091 XmlPullParser.Event tag = parser.next(); 092 String name = parser.getName(); 093 switch (tag) { 094 case START_ELEMENT: 095 switch (name) { 096 097 case OpenPgpContentElement.ELEM_TIME: 098 String stamp = parser.getAttributeValue("", OpenPgpContentElement.ATTR_STAMP); 099 timestamp = ParserUtils.getDateFromXep82String(stamp); 100 break; 101 102 case OpenPgpContentElement.ELEM_TO: 103 String jid = parser.getAttributeValue("", OpenPgpContentElement.ATTR_JID); 104 to.add(JidCreate.bareFrom(jid)); 105 break; 106 107 case EncryptedOpenPgpContentElement.ELEM_RPAD: 108 rpad = parser.nextText(); 109 break; 110 111 case OpenPgpContentElement.ELEM_PAYLOAD: 112 innerloop: while (true) { 113 XmlPullParser.Event ptag = parser.next(); 114 String pname = parser.getName(); 115 String pns = parser.getNamespace(); 116 switch (ptag) { 117 case START_ELEMENT: 118 ExtensionElementProvider<ExtensionElement> provider = 119 ProviderManager.getExtensionProvider(pname, pns); 120 if (provider == null) { 121 LOGGER.log(Level.INFO, "No provider found for " + pname + " " + pns); 122 continue innerloop; 123 } 124 payload.add(provider.parse(parser)); 125 break; 126 127 case END_ELEMENT: 128 break innerloop; 129 130 default: 131 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 132 break; 133 } 134 } 135 break; 136 } 137 break; 138 139 case END_ELEMENT: 140 switch (name) { 141 case CryptElement.ELEMENT: 142 case SigncryptElement.ELEMENT: 143 case SignElement.ELEMENT: 144 break outerloop; 145 } 146 break; 147 148 default: 149 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 150 break; 151 } 152 } 153 154 return new OpenPgpContentElementData(to, timestamp, rpad, payload); 155 } 156 157 protected static final class OpenPgpContentElementData { 158 protected final Set<Jid> to; 159 protected final Date timestamp; 160 protected final String rpad; 161 protected final List<ExtensionElement> payload; 162 163 private OpenPgpContentElementData(Set<Jid> to, Date timestamp, String rpad, List<ExtensionElement> payload) { 164 this.to = to; 165 this.timestamp = timestamp; 166 this.rpad = rpad; 167 this.payload = payload; 168 } 169 } 170}