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 "talk/base/task.h" 13 #include "talk/xmllite/qname.h" 14 #include "talk/xmllite/xmlelement.h" 15 #include "talk/xmpp/xmppclient.h" 16 #include "talk/xmpp/constants.h" 17 #include "talk/xmpp/xmppengine.h" 18 19 namespace notifier { 20 21 PushNotificationsListenTask::Delegate::~Delegate() { 22 } 23 24 PushNotificationsListenTask::PushNotificationsListenTask( 25 buzz::XmppTaskParentInterface* parent, Delegate* delegate) 26 : buzz::XmppTask(parent, buzz::XmppEngine::HL_TYPE), 27 delegate_(delegate) { 28 DCHECK(delegate_); 29 } 30 31 PushNotificationsListenTask::~PushNotificationsListenTask() { 32 } 33 34 int PushNotificationsListenTask::ProcessStart() { 35 return STATE_RESPONSE; 36 } 37 38 int PushNotificationsListenTask::ProcessResponse() { 39 const buzz::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 buzz::QName kQnPush(kPushNotificationsNamespace, "push"); 61 const buzz::QName kQnChannel(buzz::STR_EMPTY, "channel"); 62 const buzz::QName kQnData(kPushNotificationsNamespace, "data"); 63 64 const buzz::XmlElement* push_element = stanza->FirstNamed(kQnPush); 65 if (push_element) { 66 Notification notification; 67 notification.channel = push_element->Attr(kQnChannel); 68 const buzz::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, ¬ification.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 87 bool PushNotificationsListenTask::HandleStanza(const buzz::XmlElement* stanza) { 88 if (IsValidNotification(stanza)) { 89 QueueStanza(stanza); 90 return true; 91 } 92 return false; 93 } 94 95 bool PushNotificationsListenTask::IsValidNotification( 96 const buzz::XmlElement* stanza) { 97 // We don't do much validation here, just check if the stanza is a message 98 // stanza. 99 return (stanza->Name() == buzz::QN_MESSAGE); 100 } 101 102 } // namespace notifier 103