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/xmpp_push_client.h"
6
7#include "base/logging.h"
8#include "base/message_loop/message_loop_proxy.h"
9#include "jingle/notifier/base/notifier_options_util.h"
10#include "jingle/notifier/listener/push_client_observer.h"
11#include "jingle/notifier/listener/send_ping_task.h"
12#include "jingle/notifier/listener/push_notifications_send_update_task.h"
13
14namespace notifier {
15
16XmppPushClient::XmppPushClient(const NotifierOptions& notifier_options)
17    : notifier_options_(notifier_options) {
18  DCHECK(notifier_options_.request_context_getter->
19         GetNetworkTaskRunner()->BelongsToCurrentThread());
20}
21
22XmppPushClient::~XmppPushClient() {
23  DCHECK(thread_checker_.CalledOnValidThread());
24}
25
26void XmppPushClient::OnConnect(
27    base::WeakPtr<buzz::XmppTaskParentInterface> base_task) {
28  DCHECK(thread_checker_.CalledOnValidThread());
29  base_task_ = base_task;
30
31  if (!base_task_.get()) {
32    NOTREACHED();
33    return;
34  }
35
36  // Listen for notifications.
37  {
38    // Owned by |base_task_|.
39    PushNotificationsListenTask* listener =
40        new PushNotificationsListenTask(base_task_.get(), this);
41    listener->Start();
42  }
43
44  // Send subscriptions.
45  {
46    // Owned by |base_task_|.
47    PushNotificationsSubscribeTask* subscribe_task =
48        new PushNotificationsSubscribeTask(
49            base_task_.get(), subscriptions_, this);
50    subscribe_task->Start();
51  }
52
53  std::vector<Notification> notifications_to_send;
54  notifications_to_send.swap(pending_notifications_to_send_);
55  for (std::vector<Notification>::const_iterator it =
56           notifications_to_send.begin();
57       it != notifications_to_send.end(); ++it) {
58    DVLOG(1) << "Push: Sending pending notification " << it->ToString();
59    SendNotification(*it);
60  }
61}
62
63void XmppPushClient::OnTransientDisconnection() {
64  DCHECK(thread_checker_.CalledOnValidThread());
65  DVLOG(1) << "Push: Transient disconnection";
66  base_task_.reset();
67  FOR_EACH_OBSERVER(PushClientObserver, observers_,
68                    OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
69}
70
71void XmppPushClient::OnCredentialsRejected() {
72  DCHECK(thread_checker_.CalledOnValidThread());
73  DVLOG(1) << "Push: Credentials rejected";
74  base_task_.reset();
75  FOR_EACH_OBSERVER(
76      PushClientObserver, observers_,
77      OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED));
78}
79
80void XmppPushClient::OnNotificationReceived(
81    const Notification& notification) {
82  DCHECK(thread_checker_.CalledOnValidThread());
83  FOR_EACH_OBSERVER(PushClientObserver, observers_,
84                    OnIncomingNotification(notification));
85}
86
87void XmppPushClient::OnPingResponseReceived() {
88  DCHECK(thread_checker_.CalledOnValidThread());
89  FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse());
90}
91
92void XmppPushClient::OnSubscribed() {
93  DCHECK(thread_checker_.CalledOnValidThread());
94  FOR_EACH_OBSERVER(PushClientObserver, observers_,
95                    OnNotificationsEnabled());
96}
97
98void XmppPushClient::OnSubscriptionError() {
99  DCHECK(thread_checker_.CalledOnValidThread());
100  FOR_EACH_OBSERVER(PushClientObserver, observers_,
101                    OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
102}
103
104void XmppPushClient::AddObserver(PushClientObserver* observer) {
105  DCHECK(thread_checker_.CalledOnValidThread());
106  observers_.AddObserver(observer);
107}
108
109void XmppPushClient::RemoveObserver(PushClientObserver* observer) {
110  DCHECK(thread_checker_.CalledOnValidThread());
111  observers_.RemoveObserver(observer);
112}
113
114void XmppPushClient::UpdateSubscriptions(
115    const SubscriptionList& subscriptions) {
116  DCHECK(thread_checker_.CalledOnValidThread());
117  subscriptions_ = subscriptions;
118}
119
120void XmppPushClient::UpdateCredentials(
121      const std::string& email, const std::string& token) {
122  DCHECK(thread_checker_.CalledOnValidThread());
123  DVLOG(1) << "Push: Updating credentials for " << email;
124  xmpp_settings_ = MakeXmppClientSettings(notifier_options_, email, token);
125  if (login_.get()) {
126    login_->UpdateXmppSettings(xmpp_settings_);
127  } else {
128    DVLOG(1) << "Push: Starting XMPP connection";
129    base_task_.reset();
130    login_.reset(new notifier::Login(this,
131                                     xmpp_settings_,
132                                     notifier_options_.request_context_getter,
133                                     GetServerList(notifier_options_),
134                                     notifier_options_.try_ssltcp_first,
135                                     notifier_options_.auth_mechanism));
136    login_->StartConnection();
137  }
138}
139
140void XmppPushClient::SendNotification(const Notification& notification) {
141  DCHECK(thread_checker_.CalledOnValidThread());
142  if (!base_task_.get()) {
143    // TODO(akalin): Figure out whether we really need to do this.
144    DVLOG(1) << "Push: Cannot send notification "
145             << notification.ToString() << "; sending later";
146    pending_notifications_to_send_.push_back(notification);
147    return;
148  }
149  // Owned by |base_task_|.
150  PushNotificationsSendUpdateTask* task =
151      new PushNotificationsSendUpdateTask(base_task_.get(), notification);
152  task->Start();
153}
154
155void XmppPushClient::SendPing() {
156  DCHECK(thread_checker_.CalledOnValidThread());
157  if (!base_task_.get()) {
158    DVLOG(1) << "Push: Cannot send ping";
159    return;
160  }
161  // Owned by |base_task_|.
162  SendPingTask* task = new SendPingTask(base_task_.get(), this);
163  task->Start();
164}
165
166}  // namespace notifier
167