gecko/mobile/components/phone/nsPhoneSupport.cpp
2010-02-09 17:00:40 -08:00

447 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 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 Minimo Tel Protocol Handler.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation <http://www.mozilla.org/>.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@meer.net>
* Nino D'Aversa <ninodaversa@gmail.com>
* Alex Pakhotin <alexp@mozilla.com>
*
* 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 MPL, 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 MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef WINCE_WINDOWS_MOBILE
#include <windows.h>
#include <phone.h>
#endif
#ifdef MOZ_PLATFORM_MAEMO
#include <dbus/dbus.h>
#endif
#include "nsStringAPI.h"
#include "nsIPhoneSupport.h"
#include "nsIGenericFactory.h"
class nsPhoneSupport : public nsIPhoneSupport
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPHONESUPPORT
nsPhoneSupport() {};
~nsPhoneSupport(){};
};
NS_IMPL_ISUPPORTS1(nsPhoneSupport, nsIPhoneSupport)
NS_IMETHODIMP
nsPhoneSupport::MakeCall(const PRUnichar *telephoneNumber, const PRUnichar *telephoneDescription, PRBool aPrompt)
{
long result = -1;
#ifdef WINCE_WINDOWS_MOBILE
typedef LONG (*__PhoneMakeCall)(PHONEMAKECALLINFO *ppmci);
HMODULE hPhoneDLL = LoadLibraryW(L"phone.dll");
if (hPhoneDLL) {
__PhoneMakeCall MakeCall = (__PhoneMakeCall) GetProcAddress(hPhoneDLL,
"PhoneMakeCall");
if (MakeCall) {
PHONEMAKECALLINFO callInfo;
callInfo.cbSize = sizeof(PHONEMAKECALLINFO);
callInfo.dwFlags = aPrompt ? PMCF_PROMPTBEFORECALLING : PMCF_DEFAULT;
callInfo.pszDestAddress = telephoneNumber;
callInfo.pszAppName = nsnull;
callInfo.pszCalledParty = telephoneDescription;
callInfo.pszComment = nsnull;
result = MakeCall(&callInfo);
}
FreeLibrary(hPhoneDLL);
}
#endif
return (result == 0) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsPhoneSupport::SwitchTask()
{
#ifdef MOZ_PLATFORM_MAEMO // 5 only?
DBusError error;
dbus_error_init(&error);
DBusConnection *conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
DBusMessage *msg = dbus_message_new_signal("/com/nokia/hildon_desktop",
"com.nokia.hildon_desktop",
"exit_app_view");
if (msg) {
dbus_connection_send(conn, msg, NULL);
dbus_message_unref(msg);
dbus_connection_flush(conn);
}
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
#ifdef WINCE
///////////////////////////////////////////////////////////////////////////////
// Default Browser Registry Settings
// Based on the browser\components\shell\src\nsWindowsShellService.cpp
//
// The following keys have to be changed for Windows Mobile:
//
// [HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai\:DEFBROWSER]
// 0=Pocket IE
// 1=:MSPIE
//
// [HKEY_CLASSES_ROOT\file\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\ftp\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\http\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\https\Shell\Open\Command]
// (Default)=iexplore.exe %1
//
// --- Optional: ---
//
// [HKEY_CLASSES_ROOT\htmlfile\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\xhtmlfile\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\xmlfile\Shell\Open\Command]
// [HKEY_CLASSES_ROOT\xslfile\Shell\Open\Command]
// (Default)=iexplore.exe file:%1
//
///////////////////////////////////////////////////////////////////////////////
#define MAX_BUF 1024
#define REG_SUCCEEDED(val) \
(val == ERROR_SUCCESS)
#define REG_FAILED(val) \
(val != ERROR_SUCCESS)
typedef struct {
HKEY keyRoot;
char* keyName;
char* valueName;
char* valueData;
char* backupValueName;
} SETTING;
#define APP_REG_NAME "Fennec"
#define BACKUP_KEY_ROOT HKEY_LOCAL_MACHINE
#define BACKUP_KEY "Software\\Mozilla\\Fennec\\DefaultBrowserBackup"
#define DEFBROWSERREG "Software\\Microsoft\\Shell\\Rai\\:DEFBROWSER"
#define VAL_OPEN "\"%APPPATH%\" \"%1\""
#define SHELL_OPEN "\\Shell\\Open\\Command"
static SETTING gSettings[] = {
{ HKEY_LOCAL_MACHINE, DEFBROWSERREG, "0", APP_REG_NAME, "Rai_DEFBROWSER_0" },
{ HKEY_LOCAL_MACHINE, DEFBROWSERREG, "1", "\"%APPPATH%\"", "Rai_DEFBROWSER_1" },
{ HKEY_CLASSES_ROOT, "http" SHELL_OPEN, "", VAL_OPEN, "http" },
{ HKEY_CLASSES_ROOT, "https" SHELL_OPEN, "", VAL_OPEN, "https" },
// Optional in Firefox
{ HKEY_CLASSES_ROOT, "file" SHELL_OPEN, "", VAL_OPEN, "file" },
{ HKEY_CLASSES_ROOT, "ftp" SHELL_OPEN, "", VAL_OPEN, "ftp" },
{ HKEY_CLASSES_ROOT, "htmlfile" SHELL_OPEN, "", VAL_OPEN, "htmlfile" },
{ HKEY_CLASSES_ROOT, "xhtmlfile" SHELL_OPEN, "", VAL_OPEN, "xhtmlfile" },
{ HKEY_CLASSES_ROOT, "xmlfile" SHELL_OPEN, "", VAL_OPEN, "xmlfile" },
{ HKEY_CLASSES_ROOT, "xslfile" SHELL_OPEN, "", VAL_OPEN, "xslfile" },
// Opera changes these as well
{ HKEY_CLASSES_ROOT, ".htm", "", "htmlfile", ".htm" },
{ HKEY_CLASSES_ROOT, ".html", "", "htmlfile", ".html" },
{ HKEY_CLASSES_ROOT, ".xml", "", "xmlfile", ".xml" },
{ HKEY_CLASSES_ROOT, ".xsl", "", "xslfile", ".xsl" },
};
const PRInt32 gSettingsCount = sizeof(gSettings)/sizeof(SETTING);
static nsresult
OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
{
const nsString &flatName = PromiseFlatString(aKeyName);
DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey);
switch (res) {
case ERROR_ACCESS_DENIED:
return NS_ERROR_FILE_ACCESS_DENIED;
case ERROR_FILE_NOT_FOUND:
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
static nsresult
OpenKeyForWriting(HKEY aStartKey, const nsAString& aKeyName, HKEY* aKey)
{
const nsString &flatName = PromiseFlatString(aKeyName);
DWORD dwDisp = 0;
DWORD res = ::RegCreateKeyExW(aStartKey, flatName.get(), 0, NULL,
0, KEY_READ | KEY_WRITE, NULL, aKey,
&dwDisp);
switch (res) {
case ERROR_ACCESS_DENIED:
return NS_ERROR_FILE_ACCESS_DENIED;
case ERROR_FILE_NOT_FOUND:
res = ::RegCreateKeyExW(aStartKey, flatName.get(), 0, NULL,
0, KEY_READ | KEY_WRITE, NULL, aKey,
NULL);
if (res != ERROR_SUCCESS)
return NS_ERROR_FILE_ACCESS_DENIED;
}
return NS_OK;
}
void
SetRegValue(HKEY aKeyRoot, const nsString& aKeyName, const nsString& aValueName, const nsString& aValue)
{
PRUnichar buf[MAX_BUF];
DWORD len = sizeof buf;
HKEY theKey;
nsresult rv = OpenKeyForWriting(aKeyRoot, aKeyName, &theKey);
if (NS_FAILED(rv))
return;
// Get the current value.
DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(aValueName).get(),
NULL, NULL, (LPBYTE)buf, &len);
// Set the new value if it doesn't exist or it is different than the current
// value.
nsAutoString current(buf);
if (REG_FAILED(res) || !current.Equals(aValue)) {
const nsString &flatValue = PromiseFlatString(aValue);
::RegSetValueExW(theKey, PromiseFlatString(aValueName).get(),
0, REG_SZ, (const BYTE *)flatValue.get(),
(flatValue.Length() + 1) * sizeof(PRUnichar));
}
// Close the key we opened.
::RegCloseKey(theKey);
}
DWORD
GetRegValue(HKEY aKeyRoot, const nsString& aKeyName, const nsString& aValueName, nsString& aValue)
{
aValue = L"";
PRUnichar currValue[MAX_BUF];
::ZeroMemory(currValue, sizeof(currValue));
HKEY theKey;
DWORD res = OpenKeyForReading(aKeyRoot, aKeyName, &theKey);
if (REG_FAILED(res))
return res;
DWORD len = sizeof currValue;
res = ::RegQueryValueExW(theKey, PromiseFlatString(aValueName).get(),
NULL, NULL, (LPBYTE)currValue, &len);
// Close the key we opened.
::RegCloseKey(theKey);
if (REG_SUCCEEDED(res))
aValue = currValue;
return res;
}
#endif // WINCE
NS_IMETHODIMP
nsPhoneSupport::IsDefaultBrowser(PRBool* aIsDefaultBrowser)
{
#ifdef WINCE
*aIsDefaultBrowser = PR_TRUE;
SETTING* settings;
SETTING* end = gSettings + gSettingsCount;
PRUnichar exePath[MAX_BUF];
if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
return NS_ERROR_FAILURE;
nsAutoString appPath(exePath);
nsresult rv;
PRUnichar currValue[MAX_BUF];
for (settings = gSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 dataPath(settings->valueData);
NS_ConvertUTF8toUTF16 key(settings->keyName);
NS_ConvertUTF8toUTF16 value(settings->valueName);
PRInt32 offset = dataPath.Find("%APPPATH%");
if (offset >= 0)
dataPath.Replace(offset, 9, appPath);
::ZeroMemory(currValue, sizeof(currValue));
HKEY theKey;
rv = OpenKeyForReading(settings->keyRoot, key, &theKey);
if (NS_FAILED(rv)) {
*aIsDefaultBrowser = PR_FALSE;
return NS_OK;
}
DWORD len = sizeof currValue;
DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
NULL, NULL, (LPBYTE)currValue, &len);
// Close the key we opened.
::RegCloseKey(theKey);
if (REG_FAILED(res) ||
!dataPath.Equals(currValue)) {
// Key wasn't set, or was set to something other than our registry entry
*aIsDefaultBrowser = PR_FALSE;
return NS_OK;
}
}
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
nsPhoneSupport::SetDefaultBrowser()
{
#ifdef WINCE
PRBool defaultBrowser = PR_FALSE;
nsresult result = IsDefaultBrowser(&defaultBrowser);
if (defaultBrowser || result != NS_OK)
{
// Already set as default browser
return result;
}
SETTING* settings;
SETTING* end = gSettings + gSettingsCount;
PRUnichar exePath[MAX_BUF];
if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
return NS_ERROR_FAILURE;
nsAutoString appPath(exePath);
for (settings = gSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 dataPath(settings->valueData);
NS_ConvertUTF8toUTF16 key(settings->keyName);
NS_ConvertUTF8toUTF16 value(settings->valueName);
NS_ConvertUTF8toUTF16 backupKey(BACKUP_KEY);
NS_ConvertUTF8toUTF16 backupValue(settings->backupValueName);
PRInt32 offset = dataPath.Find("%APPPATH%");
if (offset >= 0)
dataPath.Replace(offset, 9, appPath);
nsString dataOld;
if (REG_SUCCEEDED(GetRegValue(settings->keyRoot, key, value, dataOld))) {
SetRegValue(BACKUP_KEY_ROOT, backupKey, backupValue, dataOld);
SetRegValue(settings->keyRoot, key, value, dataPath);
}
}
// On Windows CE RegFlushKey can negatively impact performance if there are a
// lot of pending writes to the HKEY_CLASSES_ROOT registry hive but it is
// necessary to save the values in the case where the user performs a hard
// power off of the device.
::RegFlushKey(HKEY_CLASSES_ROOT);
::RegFlushKey(HKEY_LOCAL_MACHINE);
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
nsPhoneSupport::RestoreDefaultBrowser()
{
#ifdef WINCE
PRBool defaultBrowser = PR_FALSE;
nsresult result = IsDefaultBrowser(&defaultBrowser);
if (!defaultBrowser || result != NS_OK)
{
// Not default browser - nothing to restore
return result;
}
SETTING* settings;
SETTING* end = gSettings + gSettingsCount;
for (settings = gSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 key(settings->keyName);
NS_ConvertUTF8toUTF16 value(settings->valueName);
NS_ConvertUTF8toUTF16 backupKey(BACKUP_KEY);
NS_ConvertUTF8toUTF16 backupValue(settings->backupValueName);
nsString dataOld;
if (REG_SUCCEEDED(GetRegValue(BACKUP_KEY_ROOT, backupKey, backupValue, dataOld)))
SetRegValue(settings->keyRoot, key, value, dataOld);
}
::RegFlushKey(HKEY_CLASSES_ROOT);
::RegFlushKey(HKEY_LOCAL_MACHINE);
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
//------------------------------------------------------------------------------
// XPCOM REGISTRATION BELOW
//------------------------------------------------------------------------------
#define nsPhoneSupport_CID \
{ 0x2a08c9e4, 0xf853, 0x4f02, \
{0x88, 0xd8, 0xd6, 0x2f, 0x27, 0xca, 0x06, 0x85} }
#define nsPhoneSupport_ContractID "@mozilla.org/phone/support;1"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPhoneSupport)
static const nsModuleComponentInfo components[] =
{
{ "Phone Support",
nsPhoneSupport_CID,
nsPhoneSupport_ContractID,
nsPhoneSupportConstructor,
nsnull,
nsnull
}
};
NS_IMPL_NSGETMODULE(nsPhoneSupportModule, components)