1 // Copyright (c) 2011 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_listen_task.h"
6 
7 #include "base/base64.h"
8 #include "base/logging.h"
9 #include "jingle/notifier/listener/notification_constants.h"
10 #include "jingle/notifier/listener/notification_defines.h"
11 #include "jingle/notifier/listener/xml_element_util.h"
12 #include "third_party/libjingle_xmpp/task_runner/task.h"
13 #include "third_party/libjingle_xmpp/xmllite/qname.h"
14 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
15 #include "third_party/libjingle_xmpp/xmpp/constants.h"
16 #include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
17 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
18 
19 namespace notifier {
20 
~Delegate()21 PushNotificationsListenTask::Delegate::~Delegate() {
22 }
23 
PushNotificationsListenTask(jingle_xmpp::XmppTaskParentInterface * parent,Delegate * delegate)24 PushNotificationsListenTask::PushNotificationsListenTask(
25     jingle_xmpp::XmppTaskParentInterface* parent, Delegate* delegate)
26         : jingle_xmpp::XmppTask(parent, jingle_xmpp::XmppEngine::HL_TYPE),
27           delegate_(delegate) {
28   DCHECK(delegate_);
29 }
30 
~PushNotificationsListenTask()31 PushNotificationsListenTask::~PushNotificationsListenTask() {
32 }
33 
ProcessStart()34 int PushNotificationsListenTask::ProcessStart() {
35   return STATE_RESPONSE;
36 }
37 
ProcessResponse()38 int PushNotificationsListenTask::ProcessResponse() {
39   const jingle_xmpp::XmlElement* stanza = NextStanza();
40   if (stanza == NULL) {
41     return STATE_BLOCKED;
42   }
43 
44   DVLOG(1) << "Received stanza " << XmlElementToString(*stanza);
45 
46   // The push notifications service does not need us to acknowledge receipt of
47   // the notification to the buzz server.
48 
49   // TODO(sanjeevr): Write unittests to cover this.
50   // Extract the service URL and service-specific data from the stanza.
51   // Note that we treat the channel name as service URL.
52   // The response stanza has the following format.
53   // <message from="{url or bare jid}" to={full jid}>
54   //  <push xmlns="google:push" channel={channel name}>
55   //    <recipient to={bare jid}>{base-64 encoded data}</recipient>
56   //    <data>{base-64 encoded data}</data>
57   //  </push>
58   // </message>
59 
60   const jingle_xmpp::QName kQnPush(kPushNotificationsNamespace, "push");
61   const jingle_xmpp::QName kQnChannel(jingle_xmpp::STR_EMPTY, "channel");
62   const jingle_xmpp::QName kQnData(kPushNotificationsNamespace, "data");
63 
64   const jingle_xmpp::XmlElement* push_element = stanza->FirstNamed(kQnPush);
65   if (push_element) {
66     Notification notification;
67     notification.channel = push_element->Attr(kQnChannel);
68     const jingle_xmpp::XmlElement* data_element = push_element->FirstNamed(kQnData);
69     if (data_element) {
70       const std::string& base64_encoded_data = data_element->BodyText();
71       if (!base::Base64Decode(base64_encoded_data, &notification.data)) {
72         LOG(WARNING) << "Could not base64-decode " << base64_encoded_data;
73       }
74     } else {
75       LOG(WARNING) << "No data element found in push element "
76                    << XmlElementToString(*push_element);
77     }
78     DVLOG(1) << "Received notification " << notification.ToString();
79     delegate_->OnNotificationReceived(notification);
80   } else {
81     LOG(WARNING) << "No push element found in stanza "
82                  << XmlElementToString(*stanza);
83   }
84   return STATE_RESPONSE;
85 }
86 
HandleStanza(const jingle_xmpp::XmlElement * stanza)87 bool PushNotificationsListenTask::HandleStanza(const jingle_xmpp::XmlElement* stanza) {
88   if (IsValidNotification(stanza)) {
89     QueueStanza(stanza);
90     return true;
91   }
92   return false;
93 }
94 
IsValidNotification(const jingle_xmpp::XmlElement * stanza)95 bool PushNotificationsListenTask::IsValidNotification(
96     const jingle_xmpp::XmlElement* stanza) {
97   // We don't do much validation here, just check if the stanza is a message
98   // stanza.
99   return (stanza->Name() == jingle_xmpp::QN_MESSAGE);
100 }
101 
102 }  // namespace notifier
103