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.bookmarks;
018
019import java.io.IOException;
020import java.util.ArrayList;
021import java.util.List;
022
023import org.jivesoftware.smack.util.ParserUtils;
024import org.jivesoftware.smack.util.XmlStringBuilder;
025import org.jivesoftware.smack.xml.XmlPullParser;
026import org.jivesoftware.smack.xml.XmlPullParserException;
027
028import org.jivesoftware.smackx.iqprivate.packet.PrivateData;
029import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider;
030
031import org.jxmpp.JxmppContext;
032import org.jxmpp.jid.EntityBareJid;
033import org.jxmpp.jid.parts.Resourcepart;
034
035/**
036 * Bookmarks is used for storing and retrieving URLS and Conference rooms.
037 * Bookmark Storage (XEP-0048) defined a protocol for the storage of bookmarks to conference rooms and other entities
038 * in a Jabber user's account.
039 * See the following code sample for saving Bookmarks:
040 * <pre>
041 * XMPPConnection con = new XMPPTCPConnection("jabber.org");
042 * con.login("john", "doe");
043 * Bookmarks bookmarks = new Bookmarks();
044 * // Bookmark a URL
045 * BookmarkedURL url = new BookmarkedURL();
046 * url.setName("Google");
047 * url.setURL("http://www.jivesoftware.com");
048 * bookmarks.addURL(url);
049 * // Bookmark a Conference room.
050 * BookmarkedConference conference = new BookmarkedConference();
051 * conference.setName("My Favorite Room");
052 * conference.setAutoJoin("true");
053 * conference.setJID("dev@conference.jivesoftware.com");
054 * bookmarks.addConference(conference);
055 * // Save Bookmarks using PrivateDataManager.
056 * PrivateDataManager manager = new PrivateDataManager(con);
057 * manager.setPrivateData(bookmarks);
058 * LastActivity activity = LastActivity.getLastActivity(con, "xray@jabber.org");
059 * </pre>
060 *
061 * @author Derek DeMoro
062 */
063public class Bookmarks implements PrivateData {
064
065    public static final String NAMESPACE = "storage:bookmarks";
066    public static final String ELEMENT = "storage";
067
068    private final List<BookmarkedURL> bookmarkedURLS;
069    private final List<BookmarkedConference> bookmarkedConferences;
070
071    /**
072     * Required Empty Constructor to use Bookmarks.
073     */
074    public Bookmarks() {
075        bookmarkedURLS = new ArrayList<>();
076        bookmarkedConferences = new ArrayList<>();
077    }
078
079    /**
080     * Adds a BookmarkedURL.
081     *
082     * @param bookmarkedURL the bookmarked bookmarkedURL.
083     */
084    public void addBookmarkedURL(BookmarkedURL bookmarkedURL) {
085        bookmarkedURLS.add(bookmarkedURL);
086    }
087
088    /**
089     * Removes a bookmarked bookmarkedURL.
090     *
091     * @param bookmarkedURL the bookmarked bookmarkedURL to remove.
092     */
093    public void removeBookmarkedURL(BookmarkedURL bookmarkedURL) {
094        bookmarkedURLS.remove(bookmarkedURL);
095    }
096
097    /**
098     * Removes all BookmarkedURLs from user's bookmarks.
099     */
100    public void clearBookmarkedURLS() {
101        bookmarkedURLS.clear();
102    }
103
104    /**
105     * Add a BookmarkedConference to bookmarks.
106     *
107     * @param bookmarkedConference the conference to remove.
108     */
109    public void addBookmarkedConference(BookmarkedConference bookmarkedConference) {
110        bookmarkedConferences.add(bookmarkedConference);
111    }
112
113    /**
114     * Removes a BookmarkedConference.
115     *
116     * @param bookmarkedConference the BookmarkedConference to remove.
117     */
118    public void removeBookmarkedConference(BookmarkedConference bookmarkedConference) {
119        bookmarkedConferences.remove(bookmarkedConference);
120    }
121
122    /**
123     * Removes all BookmarkedConferences from Bookmarks.
124     */
125    public void clearBookmarkedConferences() {
126        bookmarkedConferences.clear();
127    }
128
129    /**
130     * Returns a Collection of all Bookmarked URLs for this user.
131     *
132     * @return a collection of all Bookmarked URLs.
133     */
134    public List<BookmarkedURL> getBookmarkedURLS() {
135        return bookmarkedURLS;
136    }
137
138    /**
139     * Returns a Collection of all Bookmarked Conference for this user.
140     *
141     * @return a collection of all Bookmarked Conferences.
142     */
143    public List<BookmarkedConference> getBookmarkedConferences() {
144        return bookmarkedConferences;
145    }
146
147
148    /**
149     * Returns the root element name.
150     *
151     * @return the element name.
152     */
153    @Override
154    public String getElementName() {
155        return ELEMENT;
156    }
157
158    /**
159     * Returns the root element XML namespace.
160     *
161     * @return the namespace.
162     */
163    @Override
164    public String getNamespace() {
165        return NAMESPACE;
166    }
167
168    /**
169     * Returns the XML representation of the PrivateData.
170     *
171     * @return the private data as XML.
172     */
173    @Override
174    public XmlStringBuilder toXML() {
175        XmlStringBuilder buf = new XmlStringBuilder();
176        buf.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket();
177
178        for (BookmarkedURL urlStorage : getBookmarkedURLS()) {
179            if (urlStorage.isShared()) {
180                continue;
181            }
182            buf.halfOpenElement("url").attribute("name", urlStorage.getName()).attribute("url", urlStorage.getURL());
183            buf.condAttribute(urlStorage.isRss(), "rss", "true");
184            buf.closeEmptyElement();
185        }
186
187        // Add Conference additions
188        for (BookmarkedConference conference : getBookmarkedConferences()) {
189            if (conference.isShared()) {
190                continue;
191            }
192            buf.halfOpenElement("conference");
193            buf.attribute("name", conference.getName());
194            buf.attribute("autojoin", Boolean.toString(conference.isAutoJoin()));
195            buf.attribute("jid", conference.getJid());
196            buf.rightAngleBracket();
197
198            buf.optElement("nick", conference.getNickname());
199            buf.optElement("password", conference.getPassword());
200
201            buf.closeElement("conference");
202        }
203
204        buf.closeElement(ELEMENT);
205        return buf;
206    }
207
208    /**
209     * The IQ Provider for BookmarkStorage.
210     *
211     * @author Derek DeMoro
212     */
213    public static class Provider implements PrivateDataProvider {
214
215        /**
216         * Empty Constructor for PrivateDataProvider.
217         */
218        public Provider() {
219            super();
220        }
221
222        @Override
223        public PrivateData parsePrivateData(XmlPullParser parser, JxmppContext jxmppContext) throws XmlPullParserException, IOException {
224            Bookmarks storage = new Bookmarks();
225
226            boolean done = false;
227            while (!done) {
228                XmlPullParser.Event eventType = parser.next();
229                if (eventType == XmlPullParser.Event.START_ELEMENT && "url".equals(parser.getName())) {
230                    final BookmarkedURL urlStorage = getURLStorage(parser);
231                    if (urlStorage != null) {
232                        storage.addBookmarkedURL(urlStorage);
233                    }
234                }
235                else if (eventType == XmlPullParser.Event.START_ELEMENT &&
236                        "conference".equals(parser.getName())) {
237                    final BookmarkedConference conference = getConferenceStorage(parser, jxmppContext);
238                    storage.addBookmarkedConference(conference);
239                }
240                else if (eventType == XmlPullParser.Event.END_ELEMENT && "storage".equals(parser.getName())) {
241                    done = true;
242                }
243            }
244
245
246            return storage;
247        }
248    }
249
250    private static BookmarkedURL getURLStorage(XmlPullParser parser) throws IOException, XmlPullParserException {
251        String name = parser.getAttributeValue("", "name");
252        String url = parser.getAttributeValue("", "url");
253        String rssString = parser.getAttributeValue("", "rss");
254        boolean rss = rssString != null && "true".equals(rssString);
255
256        BookmarkedURL urlStore = new BookmarkedURL(url, name, rss);
257        boolean done = false;
258        while (!done) {
259            XmlPullParser.Event eventType = parser.next();
260            if (eventType == XmlPullParser.Event.START_ELEMENT
261                        && "shared_bookmark".equals(parser.getName())) {
262                    urlStore.setShared(true);
263            }
264            else if (eventType == XmlPullParser.Event.END_ELEMENT && "url".equals(parser.getName())) {
265                done = true;
266            }
267        }
268        return urlStore;
269    }
270
271    private static BookmarkedConference getConferenceStorage(XmlPullParser parser, JxmppContext jxmppContext) throws XmlPullParserException, IOException {
272        String name = parser.getAttributeValue("", "name");
273        boolean autojoin = ParserUtils.getBooleanAttribute(parser, "autojoin", false);
274        EntityBareJid jid = ParserUtils.getBareJidAttribute(parser, jxmppContext);
275
276        BookmarkedConference conf = new BookmarkedConference(jid);
277        conf.setName(name);
278        conf.setAutoJoin(autojoin);
279
280        // Check for nickname
281        boolean done = false;
282        while (!done) {
283            XmlPullParser.Event eventType = parser.next();
284            if (eventType == XmlPullParser.Event.START_ELEMENT && "nick".equals(parser.getName())) {
285                String nickString = parser.nextText();
286                conf.setNickname(Resourcepart.from(nickString));
287            }
288            else if (eventType == XmlPullParser.Event.START_ELEMENT && "password".equals(parser.getName())) {
289                conf.setPassword(parser.nextText());
290            }
291            else if (eventType == XmlPullParser.Event.START_ELEMENT
292                        && "shared_bookmark".equals(parser.getName())) {
293                    conf.setShared(true);
294            }
295            else if (eventType == XmlPullParser.Event.END_ELEMENT && "conference".equals(parser.getName())) {
296                done = true;
297            }
298        }
299
300
301        return conf;
302    }
303}