001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.search; 018 019import org.jivesoftware.smack.SmackException.NoResponseException; 020import org.jivesoftware.smack.SmackException.NotConnectedException; 021import org.jivesoftware.smack.XMPPConnection; 022import org.jivesoftware.smack.XMPPException.XMPPErrorException; 023import org.jivesoftware.smack.packet.IQ; 024import org.jivesoftware.smack.provider.IQProvider; 025import org.jivesoftware.smack.util.PacketParserUtils; 026import org.jivesoftware.smackx.xdata.Form; 027import org.jivesoftware.smackx.xdata.FormField; 028import org.jivesoftware.smackx.xdata.packet.DataForm; 029import org.xmlpull.v1.XmlPullParser; 030 031/** 032 * Implements the protocol currently used to search information repositories on the Jabber network. To date, the jabber:iq:search protocol 033 * has been used mainly to search for people who have registered with user directories (e.g., the "Jabber User Directory" hosted at users.jabber.org). 034 * However, the jabber:iq:search protocol is not limited to user directories, and could be used to search other Jabber information repositories 035 * (such as chatroom directories) or even to provide a Jabber interface to conventional search engines. 036 * <p/> 037 * The basic functionality is to query an information repository regarding the possible search fields, to send a search query, and to receive search results. 038 * 039 * @author Derek DeMoro 040 */ 041public class UserSearch extends IQ { 042 043 /** 044 * Creates a new instance of UserSearch. 045 */ 046 public UserSearch() { 047 } 048 049 public String getChildElementXML() { 050 StringBuilder buf = new StringBuilder(); 051 buf.append("<query xmlns=\"jabber:iq:search\">"); 052 buf.append(getExtensionsXML()); 053 buf.append("</query>"); 054 return buf.toString(); 055 } 056 057 /** 058 * Returns the form for all search fields supported by the search service. 059 * 060 * @param con the current XMPPConnection. 061 * @param searchService the search service to use. (ex. search.jivesoftware.com) 062 * @return the search form received by the server. 063 * @throws XMPPErrorException 064 * @throws NoResponseException 065 * @throws NotConnectedException 066 */ 067 public Form getSearchForm(XMPPConnection con, String searchService) throws NoResponseException, XMPPErrorException, NotConnectedException { 068 UserSearch search = new UserSearch(); 069 search.setType(IQ.Type.GET); 070 search.setTo(searchService); 071 072 IQ response = (IQ) con.createPacketCollectorAndSend(search).nextResultOrThrow(); 073 return Form.getFormFrom(response); 074 } 075 076 /** 077 * Sends the filled out answer form to be sent and queried by the search service. 078 * 079 * @param con the current XMPPConnection. 080 * @param searchForm the <code>Form</code> to send for querying. 081 * @param searchService the search service to use. (ex. search.jivesoftware.com) 082 * @return ReportedData the data found from the query. 083 * @throws XMPPErrorException 084 * @throws NoResponseException 085 * @throws NotConnectedException 086 */ 087 public ReportedData sendSearchForm(XMPPConnection con, Form searchForm, String searchService) throws NoResponseException, XMPPErrorException, NotConnectedException { 088 UserSearch search = new UserSearch(); 089 search.setType(IQ.Type.SET); 090 search.setTo(searchService); 091 search.addExtension(searchForm.getDataFormToSend()); 092 093 IQ response = (IQ) con.createPacketCollectorAndSend(search).nextResultOrThrow(); 094 return ReportedData.getReportedDataFrom(response); 095 } 096 097 /** 098 * Sends the filled out answer form to be sent and queried by the search service. 099 * 100 * @param con the current XMPPConnection. 101 * @param searchForm the <code>Form</code> to send for querying. 102 * @param searchService the search service to use. (ex. search.jivesoftware.com) 103 * @return ReportedData the data found from the query. 104 * @throws XMPPErrorException 105 * @throws NoResponseException 106 * @throws NotConnectedException 107 */ 108 public ReportedData sendSimpleSearchForm(XMPPConnection con, Form searchForm, String searchService) throws NoResponseException, XMPPErrorException, NotConnectedException { 109 SimpleUserSearch search = new SimpleUserSearch(); 110 search.setForm(searchForm); 111 search.setType(IQ.Type.SET); 112 search.setTo(searchService); 113 114 SimpleUserSearch response = (SimpleUserSearch) con.createPacketCollectorAndSend(search).nextResultOrThrow(); 115 return response.getReportedData(); 116 } 117 118 /** 119 * Internal Search service Provider. 120 */ 121 public static class Provider implements IQProvider { 122 123 /** 124 * Provider Constructor. 125 */ 126 public Provider() { 127 super(); 128 } 129 130 public IQ parseIQ(XmlPullParser parser) throws Exception { 131 UserSearch search = null; 132 SimpleUserSearch simpleUserSearch = new SimpleUserSearch(); 133 134 boolean done = false; 135 while (!done) { 136 int eventType = parser.next(); 137 if (eventType == XmlPullParser.START_TAG && parser.getName().equals("instructions")) { 138 buildDataForm(simpleUserSearch, parser.nextText(), parser); 139 return simpleUserSearch; 140 } 141 else if (eventType == XmlPullParser.START_TAG && parser.getName().equals("item")) { 142 simpleUserSearch.parseItems(parser); 143 return simpleUserSearch; 144 } 145 else if (eventType == XmlPullParser.START_TAG && parser.getNamespace().equals("jabber:x:data")) { 146 // Otherwise, it must be a packet extension. 147 search = new UserSearch(); 148 search.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), 149 parser.getNamespace(), parser)); 150 151 } 152 else if (eventType == XmlPullParser.END_TAG) { 153 if (parser.getName().equals("query")) { 154 done = true; 155 } 156 } 157 } 158 159 if (search != null) { 160 return search; 161 } 162 return simpleUserSearch; 163 } 164 } 165 166 private static void buildDataForm(SimpleUserSearch search, String instructions, XmlPullParser parser) throws Exception { 167 DataForm dataForm = new DataForm(Form.TYPE_FORM); 168 boolean done = false; 169 dataForm.setTitle("User Search"); 170 dataForm.addInstruction(instructions); 171 while (!done) { 172 int eventType = parser.next(); 173 174 if (eventType == XmlPullParser.START_TAG && !parser.getNamespace().equals("jabber:x:data")) { 175 String name = parser.getName(); 176 FormField field = new FormField(name); 177 178 // Handle hard coded values. 179 if(name.equals("first")){ 180 field.setLabel("First Name"); 181 } 182 else if(name.equals("last")){ 183 field.setLabel("Last Name"); 184 } 185 else if(name.equals("email")){ 186 field.setLabel("Email Address"); 187 } 188 else if(name.equals("nick")){ 189 field.setLabel("Nickname"); 190 } 191 192 field.setType(FormField.TYPE_TEXT_SINGLE); 193 dataForm.addField(field); 194 } 195 else if (eventType == XmlPullParser.END_TAG) { 196 if (parser.getName().equals("query")) { 197 done = true; 198 } 199 } 200 else if (eventType == XmlPullParser.START_TAG && parser.getNamespace().equals("jabber:x:data")) { 201 search.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), 202 parser.getNamespace(), parser)); 203 done = true; 204 } 205 } 206 if (search.getExtension("x", "jabber:x:data") == null) { 207 search.addExtension(dataForm); 208 } 209 } 210 211 212}