001/** 002 * 003 * Copyright 2017 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 static org.xmlpull.v1.XmlPullParser.END_TAG; 020import static org.xmlpull.v1.XmlPullParser.START_TAG; 021 022import java.io.IOException; 023import java.util.Date; 024import java.util.HashSet; 025import java.util.LinkedList; 026import java.util.List; 027import java.util.Set; 028import java.util.logging.Level; 029import java.util.logging.Logger; 030 031import org.jivesoftware.smack.packet.ExtensionElement; 032import org.jivesoftware.smack.provider.ExtensionElementProvider; 033import org.jivesoftware.smack.provider.ProviderManager; 034import org.jivesoftware.smack.util.PacketParserUtils; 035import org.jivesoftware.smackx.ox.element.CryptElement; 036import org.jivesoftware.smackx.ox.element.EncryptedOpenPgpContentElement; 037import org.jivesoftware.smackx.ox.element.OpenPgpContentElement; 038import org.jivesoftware.smackx.ox.element.SignElement; 039import org.jivesoftware.smackx.ox.element.SigncryptElement; 040 041import org.jxmpp.jid.Jid; 042import org.jxmpp.jid.impl.JidCreate; 043import org.jxmpp.util.XmppDateTime; 044import org.xmlpull.v1.XmlPullParser; 045import org.xmlpull.v1.XmlPullParserException; 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) throws Exception; 082 083 protected static OpenPgpContentElementData parseOpenPgpContentElementData(XmlPullParser parser, int initialDepth) 084 throws Exception { 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 int tag = parser.next(); 092 String name = parser.getName(); 093 switch (tag) { 094 case START_TAG: 095 switch (name) { 096 097 case OpenPgpContentElement.ELEM_TIME: 098 String stamp = parser.getAttributeValue("", OpenPgpContentElement.ATTR_STAMP); 099 timestamp = XmppDateTime.parseDate(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 int ptag = parser.next(); 114 String pname = parser.getName(); 115 String pns = parser.getNamespace(); 116 switch (ptag) { 117 118 case START_TAG: 119 ExtensionElementProvider<ExtensionElement> provider = 120 ProviderManager.getExtensionProvider(pname, pns); 121 if (provider == null) { 122 LOGGER.log(Level.INFO, "No provider found for " + pname + " " + pns); 123 continue innerloop; 124 } 125 payload.add(provider.parse(parser)); 126 break; 127 128 case END_TAG: 129 break innerloop; 130 } 131 } 132 break; 133 } 134 break; 135 136 case END_TAG: 137 switch (name) { 138 case CryptElement.ELEMENT: 139 case SigncryptElement.ELEMENT: 140 case SignElement.ELEMENT: 141 break outerloop; 142 } 143 break; 144 } 145 } 146 147 return new OpenPgpContentElementData(to, timestamp, rpad, payload); 148 } 149 150 protected static final class OpenPgpContentElementData { 151 protected final Set<Jid> to; 152 protected final Date timestamp; 153 protected final String rpad; 154 protected final List<ExtensionElement> payload; 155 156 private OpenPgpContentElementData(Set<Jid> to, Date timestamp, String rpad, List<ExtensionElement> payload) { 157 this.to = to; 158 this.timestamp = timestamp; 159 this.rpad = rpad; 160 this.payload = payload; 161 } 162 } 163}