/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim:expandtab:shiftwidth=4:tabstop=4: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Novell code. * * The Initial Developer of the Original Code is Novell, Inc. * Portions created by the Initial Developer are Copyright (C) 2006 * the Initial Developer. All Rights Reserved. * * Original Author: Robert O'Callahan (rocallahan@novell.com) * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsNetworkManagerListener.h" #include "nsNetCID.h" #include "nsServiceManagerUtils.h" #include "nsIObserverService.h" #include "nsStringAPI.h" // Define NetworkManager API constants. This avoids a dependency on // NetworkManager-devel. #define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" #define NM_DBUS_PATH "/org/freedesktop/NetworkManager" #define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" #define NM_DBUS_SIGNAL_STATE_CHANGE "StateChange" typedef enum NMState { NM_STATE_UNKNOWN = 0, NM_STATE_ASLEEP, NM_STATE_CONNECTING, NM_STATE_CONNECTED, NM_STATE_DISCONNECTED } NMState; nsNetworkManagerListener::nsNetworkManagerListener() : mLinkUp(PR_TRUE), mNetworkManagerActive(PR_FALSE), mOK(PR_TRUE), mManageIOService(PR_TRUE) { } nsNetworkManagerListener::~nsNetworkManagerListener() { if (mDBUS) { mDBUS->RemoveClient(this); } } NS_IMPL_ISUPPORTS1(nsNetworkManagerListener, nsINetworkLinkService) nsresult nsNetworkManagerListener::GetIsLinkUp(PRBool* aIsUp) { *aIsUp = mLinkUp; return NS_OK; } nsresult nsNetworkManagerListener::GetLinkStatusKnown(PRBool* aKnown) { *aKnown = mNetworkManagerActive; return NS_OK; } nsresult nsNetworkManagerListener::Init() { mDBUS = nsDBusService::Get(); if (!mDBUS) return NS_ERROR_OUT_OF_MEMORY; nsresult rv = mDBUS->AddClient(this); if (NS_FAILED(rv)) { mDBUS = nsnull; return rv; } if (!mOK) return NS_ERROR_FAILURE; return NS_OK; } static void NetworkStatusNotify(DBusPendingCall *pending, void* user_data) { DBusMessage* msg = dbus_pending_call_steal_reply(pending); if (!msg) return; if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) { NS_STATIC_CAST(nsNetworkManagerListener*, user_data)->UpdateNetworkStatus(msg); } dbus_message_unref(msg); } void nsNetworkManagerListener::RegisterWithConnection(DBusConnection* connection) { DBusError error; dbus_error_init(&error); dbus_bus_add_match(connection, "type='signal'," "interface='" NM_DBUS_INTERFACE "'," "sender='" NM_DBUS_SERVICE "'," "path='" NM_DBUS_PATH "'", &error); mOK = !dbus_error_is_set(&error); dbus_error_free(&error); if (!mOK) return; DBusMessage* msg = dbus_message_new_method_call(NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "state"); if (!msg) { mOK = PR_FALSE; return; } DBusPendingCall* reply = mDBUS->SendWithReply(this, msg); if (!reply) { mOK = PR_FALSE; return; } dbus_pending_call_set_notify(reply, NetworkStatusNotify, this, NULL); dbus_pending_call_unref(reply); } void nsNetworkManagerListener::NotifyNetworkStatusObservers() { nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); if (!observerService) return; const PRUnichar* status; if (mNetworkManagerActive) { status = mLinkUp ? NS_LITERAL_STRING(NS_NETWORK_LINK_DATA_UP).get() : NS_LITERAL_STRING(NS_NETWORK_LINK_DATA_DOWN).get(); } else { status = NS_LITERAL_STRING(NS_NETWORK_LINK_DATA_UNKNOWN).get(); } observerService->NotifyObservers(NS_STATIC_CAST(nsISupports*, this), NS_NETWORK_LINK_TOPIC, status); } void nsNetworkManagerListener::UnregisterWithConnection(DBusConnection* connection) { mNetworkManagerActive = PR_FALSE; NotifyNetworkStatusObservers(); } PRBool nsNetworkManagerListener::HandleMessage(DBusMessage* message) { if (dbus_message_is_signal(message, NM_DBUS_INTERFACE, NM_DBUS_SIGNAL_STATE_CHANGE)) { UpdateNetworkStatus(message); return PR_TRUE; } return PR_FALSE; } void nsNetworkManagerListener::UpdateNetworkStatus(DBusMessage* msg) { PRInt32 result; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &result, DBUS_TYPE_INVALID)) return; mNetworkManagerActive = PR_TRUE; PRBool wasUp = mLinkUp; mLinkUp = result == NM_STATE_CONNECTED; if (wasUp == mLinkUp) return; NotifyNetworkStatusObservers(); }