1 /****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.james.jdkim.impl;
21
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.james.jdkim.api.PublicKeyRecordRetriever;
27 import org.apache.james.jdkim.exceptions.PermFailException;
28 import org.apache.james.jdkim.exceptions.TempFailException;
29 import org.xbill.DNS.Lookup;
30 import org.xbill.DNS.Record;
31 import org.xbill.DNS.Resolver;
32 import org.xbill.DNS.TXTRecord;
33 import org.xbill.DNS.TextParseException;
34 import org.xbill.DNS.Type;
35
36 public class DNSPublicKeyRecordRetriever implements PublicKeyRecordRetriever {
37
38 // The resolver used for the lookup
39 protected Resolver resolver;
40
41 public DNSPublicKeyRecordRetriever() {
42 this(Lookup.getDefaultResolver());
43 }
44
45 public DNSPublicKeyRecordRetriever(Resolver resolver) {
46 this.resolver = resolver;
47 }
48
49 /**
50 * @see org.apache.james.jdkim.api.PublicKeyRecordRetriever#getRecords(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence)
51 */
52 public List/* String */getRecords(CharSequence methodAndOptions,
53 CharSequence selector, CharSequence token)
54 throws TempFailException, PermFailException {
55 if (!"dns/txt".equals(methodAndOptions))
56 throw new PermFailException("Only dns/txt is supported: "
57 + methodAndOptions + " options unsupported.");
58 try {
59 Lookup query = new Lookup(selector + "._domainkey." + token,
60 Type.TXT);
61 query.setResolver(resolver);
62
63 Record[] rr = query.run();
64 int queryResult = query.getResult();
65
66 if (queryResult == Lookup.TRY_AGAIN) {
67 throw new TempFailException(query.getErrorString());
68 }
69
70 List/* String */records = convertRecordsToList(rr);
71 return records;
72 } catch (TextParseException e) {
73 // TODO log
74 return null;
75 }
76 }
77
78 /**
79 * Convert the given TXT Record array to a String List
80 *
81 * @param rr
82 * Record array
83 * @return list
84 */
85 public static List/* String */convertRecordsToList(Record[] rr) {
86 List/* String */records;
87 if (rr != null && rr.length > 0) {
88 records = new ArrayList/* String */();
89 for (int i = 0; i < rr.length; i++) {
90 switch (rr[i].getType()) {
91 case Type.TXT:
92 TXTRecord txt = (TXTRecord) rr[i];
93 if (txt.getStrings().size() == 1) {
94 // This was required until dnsjava 2.0.6 because dnsjava
95 // was escaping
96 // the result like it was doublequoted (JDKIM-7).
97 // records.add(((String)txt.getStrings().get(0)).replaceAll("\\\\",
98 // ""));
99 records.add(((String) txt.getStrings().get(0)));
100 } else {
101 StringBuffer sb = new StringBuffer();
102 for (Iterator/* String */it = txt.getStrings()
103 .iterator(); it.hasNext();) {
104 String k = (String) it.next();
105 // This was required until dnsjava 2.0.6 because
106 // dnsjava was escaping
107 // the result like it was doublequoted (JDKIM-7).
108 // k = k.replaceAll("\\\\", "");
109 sb.append(k);
110 }
111 records.add(sb.toString());
112 }
113 break;
114 default:
115 return null;
116 }
117 }
118 } else {
119 records = null;
120 }
121 return records;
122 }
123
124 }