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