1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.omadm;
2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Base64;
4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Log;
5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.eap.EAP;
7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.eap.EAPMethod;
8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.eap.ExpandedEAPMethod;
9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.eap.InnerAuthEAP;
10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.anqp.eap.NonEAPInnerAuth;
11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.IMSIParameter;
12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.Utils;
13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.osu.OSUManager;
14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.osu.commands.MOData;
15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.Credential;
16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.HomeSP;
17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.Policy;
18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.SubscriptionParameters;
19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.UpdateInfo;
20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport org.xml.sax.SAXException;
22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.BufferedInputStream;
24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.BufferedOutputStream;
25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.File;
26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.FileInputStream;
27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.FileNotFoundException;
28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.FileOutputStream;
29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.IOException;
30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.nio.charset.StandardCharsets;
31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.text.DateFormat;
32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.text.ParseException;
33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.text.SimpleDateFormat;
34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList;
35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Arrays;
36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collection;
37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections;
38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Date;
39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap;
40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashSet;
41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.LinkedList;
42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List;
43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map;
44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Set;
45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.TimeZone;
46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist/**
48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist * Handles provisioning of PerProviderSubscription data.
49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist */
50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class MOManager {
51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_AAAServerTrustRoot = "AAAServerTrustRoot";
53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_AbleToShare = "AbleToShare";
54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CertificateType = "CertificateType";
55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CertSHA256Fingerprint = "CertSHA256Fingerprint";
56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CertURL = "CertURL";
57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CheckAAAServerCertStatus = "CheckAAAServerCertStatus";
58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Country = "Country";
59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CreationDate = "CreationDate";
60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Credential = "Credential";
61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_CredentialPriority = "CredentialPriority";
62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_DataLimit = "DataLimit";
63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_DigitalCertificate = "DigitalCertificate";
64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_DLBandwidth = "DLBandwidth";
65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_EAPMethod = "EAPMethod";
66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_EAPType = "EAPType";
67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_ExpirationDate = "ExpirationDate";
68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Extension = "Extension";
69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_FQDN = "FQDN";
70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_FQDN_Match = "FQDN_Match";
71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_FriendlyName = "FriendlyName";
72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_HESSID = "HESSID";
73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_HomeOI = "HomeOI";
74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_HomeOIList = "HomeOIList";
75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_HomeOIRequired = "HomeOIRequired";
76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_HomeSP = "HomeSP";
77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_IconURL = "IconURL";
78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_IMSI = "IMSI";
79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_InnerEAPType = "InnerEAPType";
80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_InnerMethod = "InnerMethod";
81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_InnerVendorID = "InnerVendorID";
82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_InnerVendorType = "InnerVendorType";
83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_IPProtocol = "IPProtocol";
84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_MachineManaged = "MachineManaged";
85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_MaximumBSSLoadValue = "MaximumBSSLoadValue";
86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_MinBackhaulThreshold = "MinBackhaulThreshold";
87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_NetworkID = "NetworkID";
88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_NetworkType = "NetworkType";
89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Other = "Other";
90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_OtherHomePartners = "OtherHomePartners";
91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Password = "Password";
92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_PerProviderSubscription = "PerProviderSubscription";
93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Policy = "Policy";
94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_PolicyUpdate = "PolicyUpdate";
95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_PortNumber = "PortNumber";
96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_PreferredRoamingPartnerList = "PreferredRoamingPartnerList";
97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Priority = "Priority";
98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Realm = "Realm";
99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_RequiredProtoPortTuple = "RequiredProtoPortTuple";
100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Restriction = "Restriction";
101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_RoamingConsortiumOI = "RoamingConsortiumOI";
102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SIM = "SIM";
103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SoftTokenApp = "SoftTokenApp";
104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SPExclusionList = "SPExclusionList";
105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SSID = "SSID";
106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_StartDate = "StartDate";
107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SubscriptionParameters = "SubscriptionParameters";
108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_SubscriptionUpdate = "SubscriptionUpdate";
109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_TimeLimit = "TimeLimit";
110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_TrustRoot = "TrustRoot";
111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_TypeOfSubscription = "TypeOfSubscription";
112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_ULBandwidth = "ULBandwidth";
113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UpdateIdentifier = "UpdateIdentifier";
114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UpdateInterval = "UpdateInterval";
115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UpdateMethod = "UpdateMethod";
116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_URI = "URI";
117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UsageLimits = "UsageLimits";
118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UsageTimePeriod = "UsageTimePeriod";
119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_Username = "Username";
120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_UsernamePassword = "UsernamePassword";
121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_VendorId = "VendorId";
122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final String TAG_VendorType = "VendorType";
123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static final long IntervalFactor = 60000L;  // All MO intervals are in minutes
125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static final DateFormat DTFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static final Map<String, Map<String, Object>> sSelectionMap;
129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    static {
131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        DTFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        sSelectionMap = new HashMap<>();
134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        setSelections(TAG_FQDN_Match,
136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "exactmatch", Boolean.FALSE,
137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "includesubdomains", Boolean.TRUE);
138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        setSelections(TAG_UpdateMethod,
139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "oma-dm-clientinitiated", Boolean.FALSE,
140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "spp-clientinitiated", Boolean.TRUE);
141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        setSelections(TAG_Restriction,
142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "homesp", UpdateInfo.UpdateRestriction.HomeSP,
143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "roamingpartner", UpdateInfo.UpdateRestriction.RoamingPartner,
144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                "unrestricted", UpdateInfo.UpdateRestriction.Unrestricted);
145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static void setSelections(String key, Object... pairs) {
148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Map<String, Object> kvp = new HashMap<>();
149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        sSelectionMap.put(key, kvp);
150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (int n = 0; n < pairs.length; n += 2) {
151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            kvp.put(pairs[n].toString(), pairs[n + 1]);
152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final File mPpsFile;
156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final boolean mEnabled;
157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final Map<String, HomeSP> mSPs;
158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public MOManager(File ppsFile, boolean hs2enabled) {
160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mPpsFile = ppsFile;
161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mEnabled = hs2enabled;
162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mSPs = new HashMap<>();
163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public File getPpsFile() {
166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mPpsFile;
167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public boolean isEnabled() {
170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mEnabled;
171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public boolean isConfigured() {
174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mEnabled && !mSPs.isEmpty();
175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public Map<String, HomeSP> getLoadedSPs() {
178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return Collections.unmodifiableMap(mSPs);
179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public List<HomeSP> loadAllSPs() throws IOException {
182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!mEnabled || !mPpsFile.exists()) {
184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return Collections.emptyList();
185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
186ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
187ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
188ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            MOTree moTree = MOTree.unmarshal(in);
189ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mSPs.clear();
190ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (moTree == null) {
191ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return Collections.emptyList();     // Empty file
192ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
193ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
194ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            List<HomeSP> sps = buildSPs(moTree);
195ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (sps != null) {
196ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                for (HomeSP sp : sps) {
197ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (mSPs.put(sp.getFQDN(), sp) != null) {
198ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        throw new OMAException("Multiple SPs for FQDN '" + sp.getFQDN() + "'");
199ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    } else {
200ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        Log.d(OSUManager.TAG, "retrieved " + sp.getFQDN() + " from PPS");
201ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
202ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
203ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return sps;
204ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
205ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
206ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Failed to build HomeSP");
207ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
208ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
209ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
210ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
211ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static HomeSP buildSP(String xml) throws IOException, SAXException {
212ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMAParser omaParser = new OMAParser();
213ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        MOTree tree = omaParser.parse(xml, OMAConstants.PPS_URN);
214ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<HomeSP> spList = buildSPs(tree);
215ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (spList.size() != 1) {
216ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
217ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
218ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return spList.iterator().next();
219ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
220ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
221ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public HomeSP addSP(String xml, OSUManager osuManager) throws IOException, SAXException {
222ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMAParser omaParser = new OMAParser();
223ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return addSP(omaParser.parse(xml, OMAConstants.PPS_URN), osuManager);
224ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
225ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
226ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static final List<String> FQDNPath = Arrays.asList(TAG_HomeSP, TAG_FQDN);
227ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
228ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    /**
229ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * R1 *only* addSP method.
230ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     *
231ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @param homeSP
232ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @throws IOException
233ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     */
234ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public void addSP(HomeSP homeSP, OSUManager osuManager) throws IOException {
235ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!mEnabled) {
236ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new IOException("HS2.0 not enabled on this device");
237ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
238ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mSPs.containsKey(homeSP.getFQDN())) {
239ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Log.d(OSUManager.TAG, "HS20 profile for " +
240ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    homeSP.getFQDN() + " already exists");
241ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return;
242ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
243ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Log.d(OSUManager.TAG, "Adding new HS20 profile for " + homeSP.getFQDN());
244ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
245ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMAConstructed dummyRoot = new OMAConstructed(null, TAG_PerProviderSubscription, null);
246ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        buildHomeSPTree(homeSP, dummyRoot, mSPs.size() + 1);
247ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
248ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            addSP(dummyRoot, osuManager);
249ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (FileNotFoundException fnfe) {
250ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            MOTree tree =
251ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, dummyRoot);
252ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            // No file to load a pre-build MO tree from, create a new one and save it.
253ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            //MOTree tree = new MOTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, dummyRoot);
254ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            writeMO(tree, mPpsFile, osuManager);
255ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
256ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mSPs.put(homeSP.getFQDN(), homeSP);
257ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
258ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
259ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public HomeSP addSP(MOTree instanceTree, OSUManager osuManager) throws IOException {
260ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<HomeSP> spList = buildSPs(instanceTree);
261ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (spList.size() != 1) {
262ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
263ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
264ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
265ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        HomeSP sp = spList.iterator().next();
266ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String fqdn = sp.getFQDN();
267ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mSPs.put(fqdn, sp) != null) {
268ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("SP " + fqdn + " already exists");
269ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
270ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
271ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMAConstructed pps = (OMAConstructed) instanceTree.getRoot().
272ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                getChild(TAG_PerProviderSubscription);
273ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
274ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
275ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            addSP(pps, osuManager);
276ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (FileNotFoundException fnfe) {
277ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            MOTree tree = new MOTree(instanceTree.getUrn(), instanceTree.getDtdRev(),
278ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    instanceTree.getRoot());
279ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            writeMO(tree, mPpsFile, osuManager);
280ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
281ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
282ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return sp;
283ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
284ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
285ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    /**
286ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * Add an SP sub-tree. mo must be PPS with an immediate instance child (e.g. Cred01) and an
287ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * optional UpdateIdentifier,
288ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     *
289ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @param mo The new MO
290ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @throws IOException
291ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     */
292ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private void addSP(OMANode mo, OSUManager osuManager) throws IOException {
293ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        MOTree moTree;
294ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
295ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            moTree = MOTree.unmarshal(in);
296ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            moTree.getRoot().addChild(mo);
297ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
298ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                /*
299ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed ppsRoot = (OMAConstructed)
300ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    moTree.getRoot().addChild(TAG_PerProviderSubscription, "", null, null);
301ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode child : mo.getChildren()) {
302ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                ppsRoot.addChild(child);
303ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (!child.isLeaf()) {
304ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    moTree.getRoot().addChild(child);
305ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
306ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                else if (child.getName().equals(TAG_UpdateIdentifier)) {
307ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    OMANode currentUD = moTree.getRoot().getChild(TAG_UpdateIdentifier);
308ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (currentUD != null) {
309ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        moTree.getRoot().replaceNode(currentUD, child);
310ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
311ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    else {
312ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        moTree.getRoot().addChild(child);
313ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
314ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
315ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
316ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                */
317ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
318ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        writeMO(moTree, mPpsFile, osuManager);
319ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
320ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
321ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static OMAConstructed findTargetTree(MOTree moTree, String fqdn) throws OMAException {
322ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode pps = moTree.getRoot();
323ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (OMANode node : pps.getChildren()) {
324ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode instance = null;
325ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (node.getName().equals(TAG_PerProviderSubscription)) {
326ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                instance = getInstanceNode((OMAConstructed) node);
327ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else if (!node.isLeaf()) {
328ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                instance = node;
329ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
330ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (instance != null) {
331ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                String nodeFqdn = getString(instance.getListValue(FQDNPath.iterator()));
332ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (fqdn.equalsIgnoreCase(nodeFqdn)) {
333ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    return (OMAConstructed) node;
334ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    // targetTree is rooted at the PPS
335ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
336ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
337ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
338ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return null;
339ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
340ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
341ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static OMAConstructed getInstanceNode(OMAConstructed root) throws OMAException {
342ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (OMANode child : root.getChildren()) {
343ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (!child.isLeaf()) {
344ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return (OMAConstructed) child;
345ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
346ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
347ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        throw new OMAException("Cannot find instance node");
348ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
349ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
350ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public HomeSP modifySP(HomeSP homeSP, Collection<MOData> mods, OSUManager osuManager)
351ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throws IOException {
352ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
353ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Log.d(OSUManager.TAG, "modifying SP: " + mods);
354ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        MOTree moTree;
355ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int ppsMods = 0;
356ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int updateIdentifier = 0;
357ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
358ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            moTree = MOTree.unmarshal(in);
359ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            // moTree is PPS/?/provider-data
360ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
361ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed targetTree = findTargetTree(moTree, homeSP.getFQDN());
362ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (targetTree == null) {
363ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new IOException("Failed to find PPS tree for " + homeSP.getFQDN());
364ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
365ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed instance = getInstanceNode(targetTree);
366ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
367ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (MOData mod : mods) {
368ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                LinkedList<String> tailPath =
369ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        getTailPath(mod.getBaseURI(), TAG_PerProviderSubscription);
370ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMAConstructed modRoot = mod.getMOTree().getRoot();
371ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                // modRoot is the MgmtTree with the actual object as a direct child
372ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                // (e.g. Credential)
373ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
374ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (tailPath.getFirst().equals(TAG_UpdateIdentifier)) {
375ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    updateIdentifier = getInteger(modRoot.getChildren().iterator().next());
376ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    OMANode oldUdi = targetTree.getChild(TAG_UpdateIdentifier);
377ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (getInteger(oldUdi) != updateIdentifier) {
378ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        ppsMods++;
379ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
380ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (oldUdi != null) {
381ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        targetTree.replaceNode(oldUdi, modRoot.getChild(TAG_UpdateIdentifier));
382ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    } else {
383ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        targetTree.addChild(modRoot.getChild(TAG_UpdateIdentifier));
384ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
385ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                } else {
386ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    tailPath.removeFirst();     // Drop the instance
387ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    OMANode current = instance.getListValue(tailPath.iterator());
388ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (current == null) {
389ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        throw new IOException("No previous node for " + tailPath + " in " +
390ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                homeSP.getFQDN());
391ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
392ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    for (OMANode newNode : modRoot.getChildren()) {
393ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        // newNode is something like Credential
394ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        // current is the same existing node
395ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        OMANode old = current.getParent().replaceNode(current, newNode);
396ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        ppsMods++;
397ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
398ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
399ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
400ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
401ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        writeMO(moTree, mPpsFile, osuManager);
402ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
403ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (ppsMods == 0) {
404ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;    // HomeSP not modified.
405ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
406ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
407ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // Return a new rebuilt HomeSP
408ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<HomeSP> sps = buildSPs(moTree);
409ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (sps != null) {
410ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (HomeSP sp : sps) {
411ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (sp.getFQDN().equals(homeSP.getFQDN())) {
412ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    return sp;
413ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
414ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
415ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
416ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Failed to build HomeSP");
417ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
418ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return null;
419ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
420ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
421ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static LinkedList<String> getTailPath(String pathString, String rootName)
422ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throws IOException {
423ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String[] path = pathString.split("/");
424ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int pathIndex;
425ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (pathIndex = 0; pathIndex < path.length; pathIndex++) {
426ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (path[pathIndex].equalsIgnoreCase(rootName)) {
427ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                pathIndex++;
428ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                break;
429ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
430ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
431ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (pathIndex >= path.length) {
432ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new IOException("Bad node-path: " + pathString);
433ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
434ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        LinkedList<String> tailPath = new LinkedList<>();
435ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        while (pathIndex < path.length) {
436ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            tailPath.add(path[pathIndex]);
437ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            pathIndex++;
438ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
439ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return tailPath;
440ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
441ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
442ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public HomeSP getHomeSP(String fqdn) {
443ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return mSPs.get(fqdn);
444ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
445ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
446ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public void removeSP(String fqdn, OSUManager osuManager) throws IOException {
447ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mSPs.remove(fqdn) == null) {
448ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Log.d(OSUManager.TAG, "No HS20 profile to delete for " + fqdn);
449ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return;
450ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
451ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
452ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Log.d(OSUManager.TAG, "Deleting HS20 profile for " + fqdn);
453ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
454ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        MOTree moTree;
455ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
456ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            moTree = MOTree.unmarshal(in);
457ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed tbd = findTargetTree(moTree, fqdn);
458ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (tbd == null) {
459ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new IOException("Node " + fqdn + " doesn't exist in MO tree");
460ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
461ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed pps = moTree.getRoot();
462ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode removed = pps.removeNode("?", tbd);
463ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (removed == null) {
464ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new IOException("Failed to remove " + fqdn + " out of MO tree");
465ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
466ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
467ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        writeMO(moTree, mPpsFile, osuManager);
468ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        osuManager.spDeleted(fqdn);
469ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
470ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
471ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public MOTree getMOTree(HomeSP homeSP) throws IOException {
472ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
473ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            MOTree moTree = MOTree.unmarshal(in);
474ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed target = findTargetTree(moTree, homeSP.getFQDN());
475ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (target == null) {
476ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new IOException("Can't find " + homeSP.getFQDN() + " in MO tree");
477ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
478ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, target);
479ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
480ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
481ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
482ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static void writeMO(MOTree moTree, File f, OSUManager osuManager) throws IOException {
483ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try (BufferedOutputStream out =
484ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                     new BufferedOutputStream(new FileOutputStream(f, false))) {
485ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            moTree.marshal(out);
486ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            out.flush();
487ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
488ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
489ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
490ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static String fqdnList(Collection<HomeSP> sps) {
491ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        StringBuilder sb = new StringBuilder();
492ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        boolean first = true;
493ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (HomeSP sp : sps) {
494ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (first) {
495ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                first = false;
496ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
497ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                sb.append(", ");
498ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
499ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            sb.append(sp.getFQDN());
500ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
501ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return sb.toString();
502ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
503ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
504ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static OMANode buildHomeSPTree(HomeSP homeSP, OMAConstructed root, int instanceID)
505ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throws IOException {
506ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode providerSubNode = root.addChild(getInstanceString(instanceID),
507ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                null, null, null);
508ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
509ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // The HomeSP:
510ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode homeSpNode = providerSubNode.addChild(TAG_HomeSP, null, null, null);
511ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!homeSP.getSSIDs().isEmpty()) {
512ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed nwkIDNode =
513ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    (OMAConstructed) homeSpNode.addChild(TAG_NetworkID, null, null, null);
514ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int instance = 0;
515ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (Map.Entry<String, Long> entry : homeSP.getSSIDs().entrySet()) {
516ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMAConstructed inode =
517ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        (OMAConstructed) nwkIDNode
518ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                .addChild(getInstanceString(instance++), null, null, null);
519ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_SSID, null, entry.getKey(), null);
520ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (entry.getValue() != null) {
521ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    inode.addChild(TAG_HESSID, null,
522ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                            String.format("%012x", entry.getValue()), null);
523ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
524ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
525ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
526ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
527ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        homeSpNode.addChild(TAG_FriendlyName, null, homeSP.getFriendlyName(), null);
528ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
529ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (homeSP.getIconURL() != null) {
530ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            homeSpNode.addChild(TAG_IconURL, null, homeSP.getIconURL(), null);
531ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
532ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
533ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        homeSpNode.addChild(TAG_FQDN, null, homeSP.getFQDN(), null);
534ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
535ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!homeSP.getMatchAllOIs().isEmpty() || !homeSP.getMatchAnyOIs().isEmpty()) {
536ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed homeOIList =
537ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    (OMAConstructed) homeSpNode.addChild(TAG_HomeOIList, null, null, null);
538ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
539ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int instance = 0;
540ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (Long oi : homeSP.getMatchAllOIs()) {
541ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMAConstructed inode =
542ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
543ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                null, null, null);
544ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
545ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_HomeOIRequired, null, "TRUE", null);
546ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
547ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (Long oi : homeSP.getMatchAnyOIs()) {
548ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMAConstructed inode =
549ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
550ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                null, null, null);
551ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
552ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_HomeOIRequired, null, "FALSE", null);
553ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
554ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
555ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
556ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!homeSP.getOtherHomePartners().isEmpty()) {
557ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMAConstructed otherPartners =
558ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    (OMAConstructed) homeSpNode.addChild(TAG_OtherHomePartners, null, null, null);
559ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int instance = 0;
560ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (String fqdn : homeSP.getOtherHomePartners()) {
561ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMAConstructed inode =
562ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        (OMAConstructed) otherPartners.addChild(getInstanceString(instance++),
563ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                null, null, null);
564ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                inode.addChild(TAG_FQDN, null, fqdn, null);
565ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
566ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
567ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
568ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (!homeSP.getRoamingConsortiums().isEmpty()) {
569ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            homeSpNode.addChild(TAG_RoamingConsortiumOI, null,
570ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    getRCList(homeSP.getRoamingConsortiums()), null);
571ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
572ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
573ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // The Credential:
574ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode credentialNode = providerSubNode.addChild(TAG_Credential, null, null, null);
575ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Credential cred = homeSP.getCredential();
576ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        EAPMethod method = cred.getEAPMethod();
577ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
578ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (cred.getCtime() > 0) {
579ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            credentialNode.addChild(TAG_CreationDate,
580ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    null, DTFormat.format(new Date(cred.getCtime())), null);
581ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
582ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (cred.getExpTime() > 0) {
583ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            credentialNode.addChild(TAG_ExpirationDate,
584ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    null, DTFormat.format(new Date(cred.getExpTime())), null);
585ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
586ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
587ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_SIM
588ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKA
589ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKAPrim) {
590ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
591ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode simNode = credentialNode.addChild(TAG_SIM, null, null, null);
592ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            simNode.addChild(TAG_IMSI, null, cred.getImsi().toString(), null);
593ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            simNode.addChild(TAG_EAPType, null,
594ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
595ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
596ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TTLS) {
597ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
598ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode unpNode = credentialNode.addChild(TAG_UsernamePassword, null, null, null);
599ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            unpNode.addChild(TAG_Username, null, cred.getUserName(), null);
600ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            unpNode.addChild(TAG_Password, null,
601ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Base64.encodeToString(cred.getPassword().getBytes(StandardCharsets.UTF_8),
602ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                            Base64.DEFAULT), null);
603ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode eapNode = unpNode.addChild(TAG_EAPMethod, null, null, null);
604ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            eapNode.addChild(TAG_EAPType, null,
605ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
606ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            eapNode.addChild(TAG_InnerMethod, null,
607ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    ((NonEAPInnerAuth) method.getAuthParam()).getOMAtype(), null);
608ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
609ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TLS) {
610ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
611ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode certNode = credentialNode.addChild(TAG_DigitalCertificate, null, null, null);
612ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            certNode.addChild(TAG_CertificateType, null, Credential.CertTypeX509, null);
613ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            certNode.addChild(TAG_CertSHA256Fingerprint, null,
614ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Utils.toHex(cred.getFingerPrint()), null);
615ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
616ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
617ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Invalid credential on " + homeSP.getFQDN());
618ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
619ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
620ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        credentialNode.addChild(TAG_Realm, null, cred.getRealm(), null);
621ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
622ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // !!! Note: This node defines CRL checking through OSCP, I suspect we won't be able
623ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // to do that so it is commented out:
624ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        //credentialNode.addChild(TAG_CheckAAAServerCertStatus, null, "TRUE", null);
625ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return providerSubNode;
626ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
627ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
628ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static String getInstanceString(int instance) {
629ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return "r1i" + instance;
630ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
631ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
632ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static String getRCList(Collection<Long> rcs) {
633ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        StringBuilder builder = new StringBuilder();
634ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        boolean first = true;
635ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (Long roamingConsortium : rcs) {
636ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (first) {
637ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                first = false;
638ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
639ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                builder.append(',');
640ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
641ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            builder.append(String.format("%x", roamingConsortium));
642ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
643ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return builder.toString();
644ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
645ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
646ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static List<HomeSP> buildSPs(MOTree moTree) throws OMAException {
647ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMAConstructed spList;
648ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<HomeSP> homeSPs = new ArrayList<>();
649ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (moTree.getRoot().getName().equals(TAG_PerProviderSubscription)) {
650ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            // The old PPS file was rooted at PPS instead of MgmtTree to conserve space
651ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            spList = moTree.getRoot();
652ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
653ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (spList == null) {
654ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return homeSPs;
655ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
656ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
657ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode node : spList.getChildren()) {
658ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (!node.isLeaf()) {
659ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    homeSPs.add(buildHomeSP(node, 0));
660ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
661ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
662ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
663ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode ppsRoot : moTree.getRoot().getChildren()) {
664ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (ppsRoot.getName().equals(TAG_PerProviderSubscription)) {
665ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    Integer updateIdentifier = null;
666ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    OMANode instance = null;
667ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    for (OMANode child : ppsRoot.getChildren()) {
668ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        if (child.getName().equals(TAG_UpdateIdentifier)) {
669ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                            updateIdentifier = getInteger(child);
670ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        } else if (!child.isLeaf()) {
671ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                            instance = child;
672ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        }
673ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
674ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (instance == null) {
675ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        throw new OMAException("PPS node missing instance node");
676ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
677ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    homeSPs.add(buildHomeSP(instance,
678ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                            updateIdentifier != null ? updateIdentifier : 0));
679ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
680ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
681ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
682ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
683ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return homeSPs;
684ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
685ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
686ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static HomeSP buildHomeSP(OMANode ppsRoot, int updateIdentifier) throws OMAException {
687ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode spRoot = ppsRoot.getChild(TAG_HomeSP);
688ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
689ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String fqdn = spRoot.getScalarValue(Arrays.asList(TAG_FQDN).iterator());
690ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String friendlyName = spRoot.getScalarValue(Arrays.asList(TAG_FriendlyName).iterator());
691ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String iconURL = spRoot.getScalarValue(Arrays.asList(TAG_IconURL).iterator());
692ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
693ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        HashSet<Long> roamingConsortiums = new HashSet<>();
694ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String oiString = spRoot.getScalarValue(Arrays.asList(TAG_RoamingConsortiumOI).iterator());
695ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (oiString != null) {
696ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (String oi : oiString.split(",")) {
697ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                roamingConsortiums.add(Long.parseLong(oi.trim(), 16));
698ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
699ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
700ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
701ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Map<String, Long> ssids = new HashMap<>();
702ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
703ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode ssidListNode = spRoot.getListValue(Arrays.asList(TAG_NetworkID).iterator());
704ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (ssidListNode != null) {
705ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode ssidRoot : ssidListNode.getChildren()) {
706ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                OMANode hessidNode = ssidRoot.getChild(TAG_HESSID);
707ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                ssids.put(ssidRoot.getChild(TAG_SSID).getValue(), getMac(hessidNode));
708ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
709ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
710ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
711ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Set<Long> matchAnyOIs = new HashSet<>();
712ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<Long> matchAllOIs = new ArrayList<>();
713ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode homeOIListNode = spRoot.getListValue(Arrays.asList(TAG_HomeOIList).iterator());
714ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (homeOIListNode != null) {
715ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode homeOIRoot : homeOIListNode.getChildren()) {
716ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                String homeOI = homeOIRoot.getChild(TAG_HomeOI).getValue();
717ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (Boolean.parseBoolean(homeOIRoot.getChild(TAG_HomeOIRequired).getValue())) {
718ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    matchAllOIs.add(Long.parseLong(homeOI, 16));
719ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                } else {
720ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    matchAnyOIs.add(Long.parseLong(homeOI, 16));
721ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
722ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
723ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
724ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
725ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Set<String> otherHomePartners = new HashSet<>();
726ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode otherListNode =
727ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                spRoot.getListValue(Arrays.asList(TAG_OtherHomePartners).iterator());
728ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (otherListNode != null) {
729ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode fqdnNode : otherListNode.getChildren()) {
730ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                otherHomePartners.add(fqdnNode.getChild(TAG_FQDN).getValue());
731ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
732ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
733ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
734ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Credential credential = buildCredential(ppsRoot.getChild(TAG_Credential));
735ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
736ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode policyNode = ppsRoot.getChild(TAG_Policy);
737ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Policy policy = policyNode != null ? new Policy(policyNode) : null;
738ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
739ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Map<String, String> aaaTrustRoots;
740ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode aaaRootNode = ppsRoot.getChild(TAG_AAAServerTrustRoot);
741ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (aaaRootNode == null) {
742ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            aaaTrustRoots = null;
743ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
744ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            aaaTrustRoots = new HashMap<>(aaaRootNode.getChildren().size());
745ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            for (OMANode child : aaaRootNode.getChildren()) {
746ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                aaaTrustRoots.put(getString(child, TAG_CertURL),
747ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        getString(child, TAG_CertSHA256Fingerprint));
748ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
749ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
750ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
751ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode updateNode = ppsRoot.getChild(TAG_SubscriptionUpdate);
752ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        UpdateInfo subscriptionUpdate = updateNode != null ? new UpdateInfo(updateNode) : null;
753ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode subNode = ppsRoot.getChild(TAG_SubscriptionParameters);
754ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        SubscriptionParameters subscriptionParameters = subNode != null ?
755ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                new SubscriptionParameters(subNode) : null;
756ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
757ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return new HomeSP(ssids, fqdn, roamingConsortiums, otherHomePartners,
758ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                matchAnyOIs, matchAllOIs, friendlyName, iconURL, credential,
759ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                policy, getInteger(ppsRoot.getChild(TAG_CredentialPriority), 0),
760ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                aaaTrustRoots, subscriptionUpdate, subscriptionParameters, updateIdentifier);
761ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
762ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
763ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static Credential buildCredential(OMANode credNode) throws OMAException {
764ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        long ctime = getTime(credNode.getChild(TAG_CreationDate));
765ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        long expTime = getTime(credNode.getChild(TAG_ExpirationDate));
766ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String realm = getString(credNode.getChild(TAG_Realm));
767ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        boolean checkAAACert = getBoolean(credNode.getChild(TAG_CheckAAAServerCertStatus));
768ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
769ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode unNode = credNode.getChild(TAG_UsernamePassword);
770ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode certNode = credNode.getChild(TAG_DigitalCertificate);
771ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode simNode = credNode.getChild(TAG_SIM);
772ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
773ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int alternatives = 0;
774ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        alternatives += unNode != null ? 1 : 0;
775ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        alternatives += certNode != null ? 1 : 0;
776ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        alternatives += simNode != null ? 1 : 0;
777ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (alternatives != 1) {
778ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Expected exactly one credential type, got " + alternatives);
779ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
780ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
781ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (unNode != null) {
782ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String userName = getString(unNode.getChild(TAG_Username));
783ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String password = getString(unNode.getChild(TAG_Password));
784ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            boolean machineManaged = getBoolean(unNode.getChild(TAG_MachineManaged));
785ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String softTokenApp = getString(unNode.getChild(TAG_SoftTokenApp));
786ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            boolean ableToShare = getBoolean(unNode.getChild(TAG_AbleToShare));
787ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
788ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            OMANode eapMethodNode = unNode.getChild(TAG_EAPMethod);
789ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            int eapID = getInteger(eapMethodNode.getChild(TAG_EAPType));
790ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
791ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            EAP.EAPMethodID eapMethodID = EAP.mapEAPMethod(eapID);
792ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (eapMethodID == null) {
793ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Unknown EAP method: " + eapID);
794ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
795ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
796ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Long vid = getOptionalInteger(eapMethodNode.getChild(TAG_VendorId));
797ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Long vtype = getOptionalInteger(eapMethodNode.getChild(TAG_VendorType));
798ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Long innerEAPType = getOptionalInteger(eapMethodNode.getChild(TAG_InnerEAPType));
799ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            EAP.EAPMethodID innerEAPMethod = null;
800ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (innerEAPType != null) {
801ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                innerEAPMethod = EAP.mapEAPMethod(innerEAPType.intValue());
802ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (innerEAPMethod == null) {
803ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    throw new OMAException("Bad inner EAP method: " + innerEAPType);
804ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
805ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
806ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
807ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Long innerVid = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorID));
808ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Long innerVtype = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorType));
809ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String innerNonEAPMethod = getString(eapMethodNode.getChild(TAG_InnerMethod));
810ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
811ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            EAPMethod eapMethod;
812ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (innerEAPMethod != null) {
813ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                eapMethod = new EAPMethod(eapMethodID, new InnerAuthEAP(innerEAPMethod));
814ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else if (vid != null) {
815ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                eapMethod = new EAPMethod(eapMethodID,
816ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        new ExpandedEAPMethod(EAP.AuthInfoID.ExpandedEAPMethod,
817ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                vid.intValue(), vtype));
818ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else if (innerVid != null) {
819ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                eapMethod =
820ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        new EAPMethod(eapMethodID, new ExpandedEAPMethod(EAP.AuthInfoID
821ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                .ExpandedInnerEAPMethod, innerVid.intValue(), innerVtype));
822ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else if (innerNonEAPMethod != null) {
823ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                eapMethod = new EAPMethod(eapMethodID, new NonEAPInnerAuth(innerNonEAPMethod));
824ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
825ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Incomplete set of EAP parameters");
826ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
827ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
828ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, userName,
829ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    password, machineManaged, softTokenApp, ableToShare);
830ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
831ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (certNode != null) {
832ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            try {
833ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                String certTypeString = getString(certNode.getChild(TAG_CertificateType));
834ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                byte[] fingerPrint = getOctets(certNode.getChild(TAG_CertSHA256Fingerprint));
835ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
836ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                EAPMethod eapMethod = new EAPMethod(EAP.EAPMethodID.EAP_TLS, null);
837ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
838ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return new Credential(ctime, expTime, realm, checkAAACert, eapMethod,
839ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        Credential.mapCertType(certTypeString), fingerPrint);
840ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } catch (NumberFormatException nfe) {
841ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Bad hex string: " + nfe.toString());
842ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
843ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
844ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (simNode != null) {
845ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            try {
846ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                IMSIParameter imsi = new IMSIParameter(getString(simNode.getChild(TAG_IMSI)));
847ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
848ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                EAPMethod eapMethod =
849ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        new EAPMethod(EAP.mapEAPMethod(getInteger(simNode.getChild(TAG_EAPType))),
850ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                                null);
851ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
852ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, imsi);
853ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } catch (IOException ioe) {
854ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Failed to parse IMSI: " + ioe);
855ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
856ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
857ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        throw new OMAException("Missing credential parameters");
858ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
859ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
860ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static OMANode getChild(OMANode node, String key) throws OMAException {
861ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode child = node.getChild(key);
862ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (child == null) {
863ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("No such node: " + key);
864ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
865ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return child;
866ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
867ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
868ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static String getString(OMANode node, String key) throws OMAException {
869ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode child = node.getChild(key);
870ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (child == null) {
871ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Missing value for " + key);
872ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (!child.isLeaf()) {
873ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException(key + " is not a leaf node");
874ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
875ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return child.getValue();
876ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
877ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
878ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static long getLong(OMANode node, String key, Long dflt) throws OMAException {
879ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode child = node.getChild(key);
880ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (child == null) {
881ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (dflt != null) {
882ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return dflt;
883ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
884ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Missing value for " + key);
885ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
886ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
887ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (!child.isLeaf()) {
888ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException(key + " is not a leaf node");
889ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
890ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String value = child.getValue();
891ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            try {
892ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                long result = Long.parseLong(value);
893ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                if (result < 0) {
894ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    throw new OMAException("Negative value for " + key);
895ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
896ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return result;
897ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } catch (NumberFormatException nfe) {
898ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                throw new OMAException("Value for " + key + " is non-numeric: " + value);
899ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
900ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
901ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
902ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
903ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static <T> T getSelection(OMANode node, String key) throws OMAException {
904ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        OMANode child = node.getChild(key);
905ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (child == null) {
906ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Missing value for " + key);
907ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (!child.isLeaf()) {
908ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException(key + " is not a leaf node");
909ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
910ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return getSelection(key, child.getValue());
911ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
912ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
913ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static <T> T getSelection(String key, String value) throws OMAException {
914ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (value == null) {
915ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("No value for " + key);
916ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
917ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Map<String, Object> kvp = sSelectionMap.get(key);
918ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        T result = (T) kvp.get(value.toLowerCase());
919ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (result == null) {
920ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Invalid value '" + value + "' for " + key);
921ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
922ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return result;
923ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
924ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
925ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static boolean getBoolean(OMANode boolNode) {
926ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return boolNode != null && Boolean.parseBoolean(boolNode.getValue());
927ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
928ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
929ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static String getString(OMANode stringNode) {
930ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return stringNode != null ? stringNode.getValue() : null;
931ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
932ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
933ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static int getInteger(OMANode intNode, int dflt) throws OMAException {
934ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (intNode == null) {
935ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return dflt;
936ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
937ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return getInteger(intNode);
938ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
939ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
940ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static int getInteger(OMANode intNode) throws OMAException {
941ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (intNode == null) {
942ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Missing integer value");
943ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
944ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
945ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return Integer.parseInt(intNode.getValue());
946ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (NumberFormatException nfe) {
947ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Invalid integer: " + intNode.getValue());
948ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
949ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
950ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
951ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static Long getMac(OMANode macNode) throws OMAException {
952ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (macNode == null) {
953ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
954ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
955ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
956ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return Long.parseLong(macNode.getValue(), 16);
957ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (NumberFormatException nfe) {
958ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Invalid MAC: " + macNode.getValue());
959ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
960ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
961ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
962ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static Long getOptionalInteger(OMANode intNode) throws OMAException {
963ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (intNode == null) {
964ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
965ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
966ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
967ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return Long.parseLong(intNode.getValue());
968ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (NumberFormatException nfe) {
969ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Invalid integer: " + intNode.getValue());
970ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
971ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
972ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
973ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static long getTime(OMANode timeNode) throws OMAException {
974ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (timeNode == null) {
975ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return Utils.UNSET_TIME;
976ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
977ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        String timeText = timeNode.getValue();
978ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        try {
979ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Date date = DTFormat.parse(timeText);
980ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return date.getTime();
981ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } catch (ParseException pe) {
982ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Badly formatted time: " + timeText);
983ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
984ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
985ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
986ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static byte[] getOctets(OMANode octetNode) throws OMAException {
987ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (octetNode == null) {
988ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throw new OMAException("Missing byte value");
989ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
990ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return Utils.hexToBytes(octetNode.getValue());
991ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
992ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist}
993