1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "jingle/notifier/listener/push_notifications_subscribe_task.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/logging.h"
11 #include "jingle/notifier/listener/notification_constants.h"
12 #include "jingle/notifier/listener/xml_element_util.h"
13 #include "third_party/libjingle_xmpp/task_runner/task.h"
14 #include "third_party/libjingle_xmpp/xmllite/qname.h"
15 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
16 #include "third_party/libjingle_xmpp/xmpp/constants.h"
17 #include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
18 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
19 
20 namespace notifier {
21 
PushNotificationsSubscribeTask(jingle_xmpp::XmppTaskParentInterface * parent,const SubscriptionList & subscriptions,Delegate * delegate)22 PushNotificationsSubscribeTask::PushNotificationsSubscribeTask(
23     jingle_xmpp::XmppTaskParentInterface* parent,
24     const SubscriptionList& subscriptions,
25     Delegate* delegate)
26     : XmppTask(parent, jingle_xmpp::XmppEngine::HL_SINGLE),
27       subscriptions_(subscriptions), delegate_(delegate) {
28 }
29 
~PushNotificationsSubscribeTask()30 PushNotificationsSubscribeTask::~PushNotificationsSubscribeTask() {
31 }
32 
HandleStanza(const jingle_xmpp::XmlElement * stanza)33 bool PushNotificationsSubscribeTask::HandleStanza(
34     const jingle_xmpp::XmlElement* stanza) {
35   if (!MatchResponseIq(stanza, GetClient()->jid().BareJid(), task_id()))
36     return false;
37   QueueStanza(stanza);
38   return true;
39 }
40 
ProcessStart()41 int PushNotificationsSubscribeTask::ProcessStart() {
42   DVLOG(1) << "Push notifications: Subscription task started.";
43   std::unique_ptr<jingle_xmpp::XmlElement> iq_stanza(
44       MakeSubscriptionMessage(subscriptions_, GetClient()->jid(), task_id()));
45   DVLOG(1) << "Push notifications: Subscription stanza: "
46           << XmlElementToString(*iq_stanza.get());
47 
48   if (SendStanza(iq_stanza.get()) != jingle_xmpp::XMPP_RETURN_OK) {
49     if (delegate_)
50       delegate_->OnSubscriptionError();
51     return STATE_ERROR;
52   }
53   return STATE_RESPONSE;
54 }
55 
ProcessResponse()56 int PushNotificationsSubscribeTask::ProcessResponse() {
57   DVLOG(1) << "Push notifications: Subscription response received.";
58   const jingle_xmpp::XmlElement* stanza = NextStanza();
59   if (stanza == NULL) {
60     return STATE_BLOCKED;
61   }
62   DVLOG(1) << "Push notifications: Subscription response: "
63            << XmlElementToString(*stanza);
64   // We've received a response to our subscription request.
65   if (stanza->HasAttr(jingle_xmpp::QN_TYPE) &&
66     stanza->Attr(jingle_xmpp::QN_TYPE) == jingle_xmpp::STR_RESULT) {
67     if (delegate_)
68       delegate_->OnSubscribed();
69     return STATE_DONE;
70   }
71   // An error response was received.
72   if (delegate_)
73     delegate_->OnSubscriptionError();
74   return STATE_ERROR;
75 }
76 
MakeSubscriptionMessage(const SubscriptionList & subscriptions,const jingle_xmpp::Jid & jid,const std::string & task_id)77 jingle_xmpp::XmlElement* PushNotificationsSubscribeTask::MakeSubscriptionMessage(
78     const SubscriptionList& subscriptions,
79     const jingle_xmpp::Jid& jid, const std::string& task_id) {
80   DCHECK(jid.IsFull());
81   const jingle_xmpp::QName kQnSubscribe(
82       kPushNotificationsNamespace, "subscribe");
83 
84   // Create the subscription stanza using the notifications protocol.
85   // <iq from={full_jid} to={bare_jid} type="set" id={id}>
86   //  <subscribe xmlns="google:push">
87   //    <item channel={channel_name} from={domain_name or bare_jid}/>
88   //    <item channel={channel_name2} from={domain_name or bare_jid}/>
89   //    <item channel={channel_name3} from={domain_name or bare_jid}/>
90   //  </subscribe>
91   // </iq>
92   jingle_xmpp::XmlElement* iq = MakeIq(jingle_xmpp::STR_SET, jid.BareJid(), task_id);
93   jingle_xmpp::XmlElement* subscribe = new jingle_xmpp::XmlElement(kQnSubscribe, true);
94   iq->AddElement(subscribe);
95 
96   for (SubscriptionList::const_iterator iter =
97            subscriptions.begin(); iter != subscriptions.end(); ++iter) {
98     jingle_xmpp::XmlElement* item = new jingle_xmpp::XmlElement(
99         jingle_xmpp::QName(kPushNotificationsNamespace, "item"));
100     item->AddAttr(jingle_xmpp::QName(jingle_xmpp::STR_EMPTY, "channel"),
101                   iter->channel.c_str());
102     item->AddAttr(jingle_xmpp::QN_FROM, iter->from.c_str());
103     subscribe->AddElement(item);
104   }
105   return iq;
106 }
107 
108 }  // namespace notifier
109