001/** 002 * 003 * Copyright 2017-2024 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.text.ParseException; 021import java.util.ArrayList; 022import java.util.Date; 023import java.util.HashSet; 024import java.util.List; 025import java.util.Set; 026import java.util.logging.Level; 027import java.util.logging.Logger; 028 029import org.jivesoftware.smack.packet.ExtensionElement; 030import org.jivesoftware.smack.packet.XmlEnvironment; 031import org.jivesoftware.smack.parsing.SmackParsingException; 032import org.jivesoftware.smack.provider.ExtensionElementProvider; 033import org.jivesoftware.smack.provider.ProviderManager; 034import org.jivesoftware.smack.util.PacketParserUtils; 035import org.jivesoftware.smack.util.ParserUtils; 036import org.jivesoftware.smack.xml.XmlPullParser; 037import org.jivesoftware.smack.xml.XmlPullParserException; 038 039import org.jivesoftware.smackx.ox.element.CryptElement; 040import org.jivesoftware.smackx.ox.element.EncryptedOpenPgpContentElement; 041import org.jivesoftware.smackx.ox.element.OpenPgpContentElement; 042import org.jivesoftware.smackx.ox.element.SignElement; 043import org.jivesoftware.smackx.ox.element.SigncryptElement; 044 045import org.jxmpp.jid.Jid; 046import org.jxmpp.jid.impl.JidCreate; 047 048/** 049 * Abstract {@link ExtensionElementProvider} implementation for the also abstract {@link OpenPgpContentElement}. 050 * 051 * @param <O> Specialized subclass of {@link OpenPgpContentElement}. 052 */ 053public abstract class OpenPgpContentElementProvider<O extends OpenPgpContentElement> extends ExtensionElementProvider<O> { 054 055 private static final Logger LOGGER = Logger.getLogger(OpenPgpContentElementProvider.class.getName()); 056 057 public static OpenPgpContentElement parseOpenPgpContentElement(String element) 058 throws XmlPullParserException, IOException { 059 XmlPullParser parser = PacketParserUtils.getParserFor(element); 060 return parseOpenPgpContentElement(parser); 061 } 062 063 public static OpenPgpContentElement parseOpenPgpContentElement(XmlPullParser parser) 064 throws XmlPullParserException { 065 try { 066 switch (parser.getName()) { 067 case SigncryptElement.ELEMENT: 068 return SigncryptElementProvider.INSTANCE.parse(parser); 069 case SignElement.ELEMENT: 070 return SignElementProvider.INSTANCE.parse(parser); 071 case CryptElement.ELEMENT: 072 return CryptElementProvider.INSTANCE.parse(parser); 073 default: throw new XmlPullParserException("Expected <crypt/>, <sign/> or <signcrypt/> element, " + 074 "but got neither of them."); 075 } 076 } catch (Exception e) { 077 throw new XmlPullParserException(e.getMessage()); 078 } 079 } 080 081 @Override 082 public abstract O parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) 083 throws XmlPullParserException, IOException, SmackParsingException, ParseException; 084 085 protected static OpenPgpContentElementData parseOpenPgpContentElementData(XmlPullParser parser, int initialDepth) 086 throws XmlPullParserException, IOException, SmackParsingException, ParseException { 087 Set<Jid> to = new HashSet<>(); 088 Date timestamp = null; 089 String rpad = null; 090 List<ExtensionElement> payload = new ArrayList<>(); 091 092 outerloop: while (true) { 093 XmlPullParser.Event tag = parser.next(); 094 String name = parser.getName(); 095 switch (tag) { 096 case START_ELEMENT: 097 switch (name) { 098 099 case OpenPgpContentElement.ELEM_TIME: 100 String stamp = parser.getAttributeValue("", OpenPgpContentElement.ATTR_STAMP); 101 timestamp = ParserUtils.getDateFromXep82String(stamp); 102 break; 103 104 case OpenPgpContentElement.ELEM_TO: 105 String jid = parser.getAttributeValue("", OpenPgpContentElement.ATTR_JID); 106 to.add(JidCreate.bareFrom(jid)); 107 break; 108 109 case EncryptedOpenPgpContentElement.ELEM_RPAD: 110 rpad = parser.nextText(); 111 break; 112 113 case OpenPgpContentElement.ELEM_PAYLOAD: 114 innerloop: while (true) { 115 XmlPullParser.Event ptag = parser.next(); 116 String pname = parser.getName(); 117 String pns = parser.getNamespace(); 118 switch (ptag) { 119 case START_ELEMENT: 120 ExtensionElementProvider<ExtensionElement> provider = 121 ProviderManager.getExtensionProvider(pname, pns); 122 if (provider == null) { 123 LOGGER.log(Level.INFO, "No provider found for " + pname + " " + pns); 124 continue innerloop; 125 } 126 payload.add(provider.parse(parser)); 127 break; 128 129 case END_ELEMENT: 130 break innerloop; 131 132 default: 133 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 134 break; 135 } 136 } 137 break; 138 } 139 break; 140 141 case END_ELEMENT: 142 switch (name) { 143 case CryptElement.ELEMENT: 144 case SigncryptElement.ELEMENT: 145 case SignElement.ELEMENT: 146 break outerloop; 147 } 148 break; 149 150 default: 151 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 152 break; 153 } 154 } 155 156 return new OpenPgpContentElementData(to, timestamp, rpad, payload); 157 } 158 159 protected static final class OpenPgpContentElementData { 160 final Set<Jid> to; 161 final Date timestamp; 162 final String rpad; 163 final List<ExtensionElement> payload; 164 165 private OpenPgpContentElementData(Set<Jid> to, Date timestamp, String rpad, List<ExtensionElement> payload) { 166 this.to = to; 167 this.timestamp = timestamp; 168 this.rpad = rpad; 169 this.payload = payload; 170 } 171 } 172}