Compare commits

..

18 Commits

Author SHA1 Message Date
alecf%netscape.com
e953a4ea87 C++ side of fix for bug 100212 - move consumers of nsIFile.URL into nsIIOService. r=dougt, sr=darin
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111529 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-08 01:31:25 +00:00
srilatha%netscape.com
22ea3cb16d checking in for rdayal. Files already on trunk.
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111225 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-02 00:08:30 +00:00
srilatha%netscape.com
e021985dac checking in for rdayal, fix for bug # 109101, r=ssu, sr=bienvenu.
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111224 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-02 00:01:48 +00:00
srilatha%netscape.com
37c7fe2cc1 checking in for rdayal. fix for bug # 116993 r=ssu, sr=sspitzer.
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111223 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-02 00:01:03 +00:00
srilatha%netscape.com
92449d5f2b checking in for rdayal. Fix for bug # 116993, r=ssu, sr=sspitzer
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111222 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-01 23:57:54 +00:00
srilatha%netscape.com
0f4c47bad2 checking in for rdayal. Fixes for bug #s 109101 and 115307. r=ducarroz, r=ssu, sr=bienvenu, sr=sspietzer
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111221 18797224-902f-48f8-a5cc-f745e15eee43
2002-01-01 23:50:41 +00:00
cavin%netscape.com
66a09211ae Checking in for rdayal.
Bug # 106137, changes for trunk landing.
r=dougt, sr=alecf, sr=mscott.


git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@111093 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-26 23:15:27 +00:00
(no author)
4d276aa864 This commit was manufactured by cvs2svn to create branch
'MAPI_NEW_DIR_TRUNK'.

git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110704 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 09:14:30 +00:00
alecf%netscape.com
9a9d38606a removing generated files
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110679 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:26:34 +00:00
alecf%netscape.com
7ef7f62f45 remove these files from the branch
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110676 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:16:53 +00:00
alecf%netscape.com
412bc70111 argh, I'll get this right yet.. this should be #if 1
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110674 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:09:41 +00:00
alecf%netscape.com
cf982c25ce oops put that #if back
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110672 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:08:22 +00:00
alecf%netscape.com
dfb5dde44f remove some files that are no longer on this branch
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110671 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:07:50 +00:00
alecf%netscape.com
5b5ddf1efb add new files for rajiv
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110670 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:06:04 +00:00
alecf%netscape.com
2765860524 land rajiv's latest patches for MAPI support - not reviewed yet, but on the way
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110668 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 01:03:35 +00:00
alecf%netscape.com
95560e128c remove obsolete files from branch
git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@110658 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-18 00:11:06 +00:00
srilatha%netscape.com
2c4edc911e Merging 094 with the private branch. Later this will be merged on to the trunk
bug #104672.


git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@107615 18797224-902f-48f8-a5cc-f745e15eee43
2001-11-07 20:16:06 +00:00
(no author)
82d37c5f89 This commit was manufactured by cvs2svn to create branch
'MAPI_NEW_DIR_TRUNK'.

git-svn-id: svn://10.0.0.236/branches/MAPI_NEW_DIR_TRUNK@107204 18797224-902f-48f8-a5cc-f745e15eee43
2001-11-03 04:06:55 +00:00
275 changed files with 5119 additions and 27716 deletions

View File

@@ -0,0 +1,70 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#include "nsISupports.idl"
interface nsIDOMWindow;
/**
* This interface provides support for registering Mozilla as the default
* Mail Client. This interface can also be used to get/set the user preference
* for the default Mail Client.
*
*/
[scriptable, uuid(c5be14ba-4e0a-4eec-a1b8-04363761d63c)]
interface nsIMapiRegistry: nsISupports {
/** This is set to TRUE if Mozilla is the default Application
*/
attribute boolean isDefaultMailClient;
/** This is set TRUE only once per session.
*/
readonly attribute boolean showDialog;
/** This will bring the dialog asking the user if he/she wants to set
* Mozilla as default Mail Client.
* Call this only if Mozilla is not the default Mail client
*/
void showMailIntegrationDialog(in nsIDOMWindow parentWindow);
};
%{C++
#define NS_IMAPIREGISTRY_CONTRACTID "@mozilla.org/mapiregistry;1"
#define NS_IMAPIREGISTRY_CLASSNAME "Mozilla MAPI Registry"
%}

View File

@@ -0,0 +1,27 @@
#!nmake
#
# The contents of this file are subject to the Netscape 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/NPL/
#
# 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Srilatha Moturi <srilatha@netscape.com>
# Krishna Mohan Khandrika <kkhandrika@netscape.com>
DEPTH=..\..
DIRS=mapihook resources mapiDll
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,54 @@
; ***** 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 Mozilla.
;
; The Initial Developer of the Original Code is
; Netscape Communications Corp.
; Portions created by the Initial Developer are Copyright (C) 2001
; the Initial Developer. All Rights Reserved.
;
; Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 *****
LIBRARY mozMapi32.dll
DESCRIPTION 'Mozilla Simple MAPI Support'
EXPORTS
MAPILogon
MAPILogoff
MAPISendMail
MAPISendDocuments
MAPIFindNext
MAPIReadMail
MAPISaveMail
MAPIDeleteMail
MAPIAddress
MAPIDetails
MAPIResolveName
MAPIFreeBuffer
GetMapiDllVersion

View File

@@ -0,0 +1,346 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.com)
* Contributor(s): Rajiv Dayal (rdayal@netscape.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 ***** */
#include <windows.h>
#include <tchar.h>
#include <mapidefs.h>
#include <mapi.h>
#include "msgMapi.h"
#include "msgMapiMain.h"
#define MAX_RECIPS 100
#define MAX_FILES 100
const CLSID CLSID_CMapiImp = {0x29f458be, 0x8866, 0x11d5,
{0xa3, 0xdd, 0x0, 0xb0, 0xd0, 0xf3, 0xba, 0xa7}};
const IID IID_nsIMapi = {0x6EDCD38E,0x8861,0x11d5,
{0xA3,0xDD,0x00,0xB0,0xD0,0xF3,0xBA,0xA7}};
DWORD tId = 0;
BOOL WINAPI DllMain(HINSTANCE aInstance, DWORD aReason, LPVOID aReserved)
{
switch (aReason)
{
case DLL_PROCESS_ATTACH : tId = TlsAlloc();
if (tId == 0xFFFFFFFF)
return FALSE;
break;
case DLL_PROCESS_DETACH : TlsFree(tId);
break;
}
return TRUE;
}
BOOL InitMozillaReference(nsIMapi **aRetValue)
{
// Check wehther this thread has a valid Interface
// by looking into thread-specific-data variable
*aRetValue = (nsIMapi *)TlsGetValue(tId);
// Check whether the pointer actually resolves to
// a valid method call; otherwise mozilla is not running
if ((*aRetValue) && (*aRetValue)->IsValid() == S_OK)
return TRUE;
HRESULT hRes = ::CoInitialize(nsnull) ;
hRes = ::CoCreateInstance(CLSID_CMapiImp, NULL, CLSCTX_LOCAL_SERVER,
IID_nsIMapi, (LPVOID *)aRetValue);
if (hRes == S_OK && (*aRetValue)->Initialize() == S_OK)
if (TlsSetValue(tId, (LPVOID)(*aRetValue)))
return TRUE;
// Either CoCreate or TlsSetValue failed; so return FALSE
if ((*aRetValue))
(*aRetValue)->Release();
::CoUninitialize();
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////////////
// The MAPILogon function begins a Simple MAPI session, loading the default message ////
// store and address book providers ////
////////////////////////////////////////////////////////////////////////////////////////
ULONG FAR PASCAL MAPILogon(ULONG aUIParam, LPTSTR aProfileName,
LPTSTR aPassword, FLAGS aFlags,
ULONG aReserved, LPLHANDLE aSession)
{
HRESULT hr = 0;
ULONG nSessionId = 0;
nsIMapi *pNsMapi = NULL;
if (!InitMozillaReference(&pNsMapi))
return MAPI_E_FAILURE;
if (!(aFlags & MAPI_UNICODE))
{
// Need to convert the parameters to Unicode.
char *pUserName = (char *) aProfileName;
char *pPassWord = (char *) aPassword;
TCHAR ProfileName[MAX_NAME_LEN] = {0};
TCHAR PassWord[MAX_PW_LEN] = {0};
if (pUserName != NULL)
{
if (!MultiByteToWideChar(CP_ACP, 0, pUserName, -1, ProfileName,
MAX_NAME_LEN))
return MAPI_E_FAILURE;
}
if (pPassWord != NULL)
{
if (!MultiByteToWideChar(CP_ACP, 0, pPassWord, -1, PassWord,
MAX_NAME_LEN))
return MAPI_E_FAILURE;
}
hr = pNsMapi->Login(aUIParam, ProfileName, PassWord, aFlags,
&nSessionId);
}
else
hr = pNsMapi->Login(aUIParam, aProfileName, aPassword,
aFlags, &nSessionId);
if (hr == S_OK)
(*aSession) = (LHANDLE) nSessionId;
else
return nSessionId;
return SUCCESS_SUCCESS;
}
ULONG FAR PASCAL MAPILogoff (LHANDLE aSession, ULONG aUIParam,
FLAGS aFlags, ULONG aReserved)
{
nsIMapi *pNsMapi = (nsIMapi *)TlsGetValue(tId);
if (pNsMapi != NULL)
{
if (pNsMapi->Logoff((ULONG) aSession) == S_OK)
pNsMapi->Release();
pNsMapi = NULL;
}
TlsSetValue(tId, NULL);
::CoUninitialize();
return SUCCESS_SUCCESS;
}
ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession, ULONG ulUIParam, lpnsMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved )
{
HRESULT hr = 0;
BOOL bTempSession = FALSE ;
nsIMapi *pNsMapi = NULL;
if (!InitMozillaReference(&pNsMapi))
return MAPI_E_FAILURE;
if (lpMessage->nRecipCount > MAX_RECIPS)
return MAPI_E_TOO_MANY_RECIPIENTS ;
if (lpMessage->nFileCount > MAX_FILES)
return MAPI_E_TOO_MANY_FILES ;
if ( (!(flFlags & MAPI_DIALOG)) && (lpMessage->lpRecips == NULL) )
return MAPI_E_UNKNOWN_RECIPIENT ;
if (!lhSession || pNsMapi->IsValidSession(lhSession) != S_OK)
{
FLAGS LoginFlag ;
if ( (flFlags & MAPI_LOGON_UI) && (flFlags & MAPI_NEW_SESSION) )
LoginFlag = MAPI_LOGON_UI | MAPI_NEW_SESSION ;
else if (flFlags & MAPI_LOGON_UI)
LoginFlag = MAPI_LOGON_UI ;
hr = MAPILogon (ulUIParam, (LPTSTR) NULL, (LPTSTR) NULL, LoginFlag, 0, &lhSession) ;
if (hr != SUCCESS_SUCCESS)
return MAPI_E_LOGIN_FAILURE ;
bTempSession = TRUE ;
}
// we need to deal with null data passed in by MAPI clients, specially when MAPI_DIALOG is set.
// The MS COM type lib code generated by MIDL for the MS COM interfaces checks for these parameters
// to be non null, although null is a valid value for them here.
nsMapiRecipDesc * lpRecips ;
nsMapiFileDesc * lpFiles ;
nsMapiMessage Message ;
memset (&Message, 0, sizeof (nsMapiMessage) ) ;
nsMapiRecipDesc Recipient ;
memset (&Recipient, 0, sizeof (nsMapiRecipDesc) );
nsMapiFileDesc Files ;
memset (&Files, 0, sizeof (nsMapiFileDesc) ) ;
if(!lpMessage)
{
lpMessage = &Message ;
}
if(!lpMessage->lpRecips)
{
lpRecips = &Recipient ;
}
else
lpRecips = lpMessage->lpRecips ;
if(!lpMessage->lpFiles)
{
lpFiles = &Files ;
}
else
lpFiles = lpMessage->lpFiles ;
HANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, (LPCTSTR) MAPI_SENDCOMPLETE_EVENT) ;
hr = pNsMapi->SendMail (lhSession, lpMessage,
(short) lpMessage->nRecipCount, lpRecips,
(short) lpMessage->nFileCount, lpFiles,
flFlags, ulReserved);
// we are seeing a problem when using Word, although we return success from the MAPI support
// MS COM interface in mozilla, we are getting this error here. This is a temporary hack !!
if (hr == 0x800703e6)
hr = SUCCESS_SUCCESS;
if (hr == SUCCESS_SUCCESS)
WaitForSingleObject (hEvent, INFINITE) ;
CloseHandle (hEvent) ;
if (bTempSession)
MAPILogoff (lhSession, ulUIParam, 0,0) ;
return hr ;
}
ULONG FAR PASCAL MAPISendDocuments(ULONG ulUIParam, LPTSTR lpszDelimChar, LPTSTR lpszFilePaths,
LPTSTR lpszFileNames, ULONG ulReserved)
{
LHANDLE lhSession ;
nsIMapi *pNsMapi = NULL;
if (!InitMozillaReference(&pNsMapi))
return MAPI_E_FAILURE;
unsigned long result = MAPILogon (ulUIParam, (LPTSTR) NULL, (LPTSTR) NULL, MAPI_LOGON_UI, 0, &lhSession) ;
if (result != SUCCESS_SUCCESS)
return MAPI_E_LOGIN_FAILURE ;
HRESULT hr;
HANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, (LPCTSTR) MAPI_SENDCOMPLETE_EVENT) ;
hr = pNsMapi->SendDocuments(lhSession, (LPTSTR) lpszDelimChar, (LPTSTR) lpszFilePaths,
(LPTSTR) lpszFileNames, ulReserved) ;
if (hr == SUCCESS_SUCCESS)
WaitForSingleObject (hEvent, INFINITE) ;
CloseHandle (hEvent) ;
MAPILogoff (lhSession, ulUIParam, 0,0) ;
return hr ;
}
ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageType,
LPTSTR lpszSeedMessageID, FLAGS flFlags, ULONG ulReserved,
LPTSTR lpszMessageID)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved, lpMapiMessage FAR *lppMessage)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPISaveMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved, LPTSTR lpszMessageID)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIDeleteMail(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIAddress(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszCaption,
ULONG nEditFields, LPTSTR lpszLabels, ULONG nRecips,
lpMapiRecipDesc lpRecips, FLAGS flFlags,
ULONG ulReserved, LPULONG lpnNewRecips,
lpMapiRecipDesc FAR *lppNewRecips)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIDetails(LHANDLE lhSession, ULONG ulUIParam, lpMapiRecipDesc lpRecip,
FLAGS flFlags, ULONG ulReserved)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszName,
FLAGS flFlags, ULONG ulReserved, lpMapiRecipDesc FAR *lppRecip)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL MAPIFreeBuffer(LPVOID pv)
{
return MAPI_E_FAILURE;
}
ULONG FAR PASCAL GetMapiDllVersion()
{
return 94;
}

View File

@@ -0,0 +1,62 @@
# ***** 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 Mozilla.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corp.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 *****
DEPTH=..\..\..
MODULE = mozMapi32
EXPORT_LIBRARY = $(MODULE)
LIBRARY_NAME = $(MODULE)
DEFFILE = Mapi32.def
REQUIRES = MapiProxy \
msgMapi \
xpcom \
string \
$(NULL)
include <$(DEPTH)\config\config.mak>
###############################################################
LCFLAGS=-DUNICODE -D_UNICODE
OBJS= .\$(OBJDIR)\MapiDll.obj \
$(NULL)
WIN_LIBS= ole32.lib \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,47 @@
; ***** 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 Mozilla.
;
; The Initial Developer of the Original Code is
; Netscape Communications Corp.
; Portions created by the Initial Developer are Copyright (C) 2001
; the Initial Developer. All Rights Reserved.
;
; Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 *****
LIBRARY MapiProxy.dll
DESCRIPTION 'Proxy/Stub DLL'
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE

View File

@@ -0,0 +1,68 @@
# ***** 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 Mozilla.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corp.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 *****
DEPTH=..\..\..\..
MODULE = MapiProxy
EXPORT_LIBRARY = $(MODULE)
LIBRARY_NAME = $(MODULE)
DEFFILE = MapiProxy.def
include <$(DEPTH)\config\config.mak>
##################################################################
LCFLAGS=-DREGISTER_PROXY_DLL -DUNICODE -D_UNICODE
OBJS= .\$(OBJDIR)\dlldata.obj \
.\$(OBJDIR)\msgMapi_p.obj \
.\$(OBJDIR)\msgMapi_i.obj \
$(NULL)
WIN_LIBS= rpcrt4.lib
EXPORTS= msgMapi.h \
$(NULL)
include <$(DEPTH)\config\rules.mak>
msgMapi.h msgMapi_p.c msgMapi_i.c dlldata.c : msgMapi.idl
midl $(UNICODE_FLAGS) msgMapi.idl
clobber::
rm -f dlldata.c msgMapi_i.c msgMapi_p.c msgMapi.h

View File

@@ -0,0 +1,114 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.com)
* Contributor(s): Rajiv Dayal (rdayal@netscape.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 ***** */
// This idl will be compiled by MIDL. MS-COM is used
// as brdige between MAPI clients and the Mozilla.
import "unknwn.idl";
typedef wchar_t LOGIN_PW_TYPE[256];
typedef struct
{
unsigned long ulReserved;
unsigned long flFlags; /* Flags */
unsigned long nPosition_NotUsed; /* character in text to be replaced by attachment */
LPTSTR lpszPathName; /* Full path name including file name */
LPTSTR lpszFileName; /* Real (original) file name */
unsigned char * lpFileType_NotUsed ;
} nsMapiFileDesc, * lpnsMapiFileDesc;
typedef struct
{
unsigned long ulReserved;
unsigned long ulRecipClass; /* MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG */
LPTSTR lpszName; /* Recipient name to display */
LPTSTR lpszAddress; /* Recipient email address */
unsigned long ulEIDSize_NotUsed;
unsigned char * lpEntryID_NotUsed ;
} nsMapiRecipDesc, * lpnsMapiRecipDesc;
typedef struct
{
unsigned long ulReserved;
LPTSTR lpszSubject; /* Message Subject */
LPTSTR lpszNoteText; /* Message Text */
LPTSTR lpszMessageType_NotUsed;
LPTSTR lpszDateReceived_notUsed; /* in YYYY/MM/DD HH:MM format */
LPTSTR lpszConversationID_NotUsed; /* conversation thread ID */
unsigned long flFlags; /* unread,return receipt */
lpnsMapiRecipDesc lpOriginator; /* Originator descriptor */
unsigned long nRecipCount; /* Number of recipients */
lpnsMapiRecipDesc lpRecips; /* Recipient descriptors */
unsigned long nFileCount; /* # of file attachments */
lpnsMapiFileDesc lpFiles; /* Attachment descriptors */
} nsMapiMessage, * lpnsMapiMessage;
[
object,
uuid(6EDCD38E-8861-11d5-A3DD-00B0D0F3BAA7),
helpstring("nsIMapi Inteface"),
pointer_default(unique)
]
interface nsIMapi : IUnknown
{
HRESULT Login(unsigned long aUIArg, LOGIN_PW_TYPE aLogin,
LOGIN_PW_TYPE aPassWord, unsigned long aFlags,
[out] unsigned long *aSessionId);
HRESULT Initialize();
HRESULT IsValid();
HRESULT IsValidSession([in] unsigned long aSession);
HRESULT SendMail([in] unsigned long aSession, [in] lpnsMapiMessage aMessage,
[in] short aRecipCount, [in, size_is(aRecipCount)] lpnsMapiRecipDesc aRecips,
[in] short aFileCount, [in, size_is(aFileCount)] lpnsMapiFileDesc aFiles,
[in] unsigned long aFlags, [in] unsigned long aReserved) ;
HRESULT SendDocuments( [in] unsigned long aSession,
[in] LPTSTR aDelimChar, [in] LPTSTR aFilePaths,
[in] LPTSTR aFileNames, [in] ULONG aFlags ) ;
HRESULT Logoff (unsigned long aSession);
HRESULT CleanUp();
};

View File

@@ -0,0 +1,41 @@
# ***** 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 Mozilla.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corp.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s): Srilatha Moturi (srilatha@netscape.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 *****
DEPTH=..\..\..
DIRS= build public src
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,49 @@
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.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 *****
DEPTH=..\..\..\..
MODULE=msgMapi
XPIDL_MODULE=mapihook
XPIDLSRCS = \
.\nsIMapiRegistry.idl \
.\nsIMapiSupport.idl \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,70 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#include "nsISupports.idl"
interface nsIDOMWindow;
/**
* This interface provides support for registering Mozilla as the default
* Mail Client. This interface can also be used to get/set the user preference
* for the default Mail Client.
*
*/
[scriptable, uuid(c5be14ba-4e0a-4eec-a1b8-04363761d63c)]
interface nsIMapiRegistry: nsISupports {
/** This is set to TRUE if Mozilla is the default Application
*/
attribute boolean isDefaultMailClient;
/** This is set TRUE only once per session.
*/
readonly attribute boolean showDialog;
/** This will bring the dialog asking the user if he/she wants to set
* Mozilla as default Mail Client.
* Call this only if Mozilla is not the default Mail client
*/
void showMailIntegrationDialog(in nsIDOMWindow parentWindow);
};
%{C++
#define NS_IMAPIREGISTRY_CONTRACTID "@mozilla.org/mapiregistry;1"
#define NS_IMAPIREGISTRY_CLASSNAME "Mozilla MAPI Registry"
%}

View File

@@ -0,0 +1,64 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* 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 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 ***** */
#include "nsISupports.idl"
/**
* This interface provides support for registering Mozilla as a COM component
* for extending the use of Mail/News through Simple MAPI.
*
*/
[noscript, uuid(8967fed2-c8bb-11d5-a3e9-00b0d0f3baa7)]
interface nsIMapiSupport : nsISupports {
/** Initiates MAPI support
*/
void initializeMAPISupport();
/** Shuts down the MAPI support
*/
void shutdownMAPISupport();
};
%{C++
#define NS_IMAPISUPPORT_CONTRACTID "@mozilla.org/mapisupport;1"
#define NS_IMAPISUPPORT_CLASSNAME "Mozilla MAPI Support"
%}

View File

@@ -0,0 +1,323 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika <kkhandrika@netscape.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 ***** */
#undef _UNICODE
#undef UNICODE
#include <objbase.h>
#include "nsString.h"
#include "Registry.h"
#define MAPI_PROXY_DLL_NAME "MapiProxy.dll"
#define MAPI_STARTUP_ARG " /MAPIStartUp"
#define MAX_SIZE 2048
// Size of a CLSID as a string
const int CLSID_STRING_SIZE = 39;
// Proxy/Stub Dll Routines
typedef HRESULT (__stdcall ProxyServer)();
// Convert a CLSID to a char string.
BOOL CLSIDtochar(const CLSID& clsid, char* szCLSID,
int length)
{
LPOLESTR wszCLSID = NULL;
// Get CLSID
HRESULT hr = StringFromCLSID(clsid, &wszCLSID);
if (FAILED(hr))
return FALSE;
// Covert from wide characters to non-wide.
wcstombs(szCLSID, wszCLSID, length);
// Free memory.
CoTaskMemFree(wszCLSID);
return TRUE;
}
// Create a key and set its value.
BOOL setKeyAndValue(nsCAutoString keyName, const char* subKey,
const char* theValue)
{
HKEY hKey;
BOOL retValue = TRUE;
nsCAutoString theKey(keyName);
if (subKey != NULL)
{
theKey += "\\";
theKey += subKey;
}
// Create and open key and subkey.
long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, theKey.get(),
0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (lResult != ERROR_SUCCESS)
return FALSE ;
// Set the Value.
if (theValue != NULL)
{
lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)theValue,
strlen(theValue)+1);
if (lResult != ERROR_SUCCESS)
retValue = FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
// Delete a key and all of its descendents.
LONG recursiveDeleteKey(HKEY hKeyParent, // Parent of key to delete
const char* lpszKeyChild) // Key to delete
{
// Open the child.
HKEY hKeyChild ;
LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
KEY_ALL_ACCESS, &hKeyChild) ;
if (lRes != ERROR_SUCCESS)
{
return lRes ;
}
// Enumerate all of the decendents of this child.
FILETIME time ;
char szBuffer[MAX_SIZE] ;
DWORD dwSize = MAX_SIZE ;
while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
NULL, NULL, &time) == S_OK)
{
// Delete the decendents of this child.
lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;
if (lRes != ERROR_SUCCESS)
{
// Cleanup before exiting.
RegCloseKey(hKeyChild) ;
return lRes;
}
dwSize = MAX_SIZE;
}
// Close the child.
RegCloseKey(hKeyChild) ;
// Delete this child.
return RegDeleteKey(hKeyParent, lpszKeyChild) ;
}
void RegisterProxy()
{
HINSTANCE h = NULL;
ProxyServer *RegisterFunc = NULL;
char szModule[MAX_SIZE];
char *pTemp = NULL;
HMODULE hModule = GetModuleHandle(NULL);
DWORD dwResult = ::GetModuleFileName(hModule, szModule,
sizeof(szModule)/sizeof(char));
if (dwResult == 0)
return;
pTemp = strrchr(szModule, '\\');
if (pTemp == NULL)
return;
*pTemp = '\0';
nsCAutoString proxyPath(szModule);
proxyPath += "\\";
proxyPath += MAPI_PROXY_DLL_NAME;
h = LoadLibrary(proxyPath.get());
if (h == NULL)
return;
RegisterFunc = (ProxyServer *) GetProcAddress(h, "DllRegisterServer");
if (RegisterFunc)
RegisterFunc();
FreeLibrary(h);
}
void UnRegisterProxy()
{
HINSTANCE h = NULL;
ProxyServer *UnRegisterFunc = NULL;
char szModule[MAX_SIZE];
char *pTemp = NULL;
HMODULE hModule = GetModuleHandle(NULL);
DWORD dwResult = ::GetModuleFileName(hModule, szModule,
sizeof(szModule)/sizeof(char));
if (dwResult == 0)
return;
pTemp = strrchr(szModule, '\\');
if (pTemp == NULL)
return;
*pTemp = '\0';
nsCAutoString proxyPath(szModule);
proxyPath += "\\";
proxyPath += MAPI_PROXY_DLL_NAME;
h = LoadLibrary(proxyPath.get());
if (h == NULL)
return;
UnRegisterFunc = (ProxyServer *) GetProcAddress(h, "DllUnregisterServer");
if (UnRegisterFunc)
UnRegisterFunc();
FreeLibrary(h);
}
// Register the component in the registry.
HRESULT RegisterServer(const CLSID& clsid, // Class ID
const char* szFriendlyName, // Friendly Name
const char* szVerIndProgID, // Programmatic
const char* szProgID) // IDs
{
HMODULE hModule = GetModuleHandle(NULL);
char szModuleName[MAX_SIZE];
char szCLSID[CLSID_STRING_SIZE];
nsCAutoString independentProgId(szVerIndProgID);
nsCAutoString progId(szProgID);
DWORD dwResult = ::GetModuleFileName(hModule, szModuleName,
sizeof(szModuleName)/sizeof(char));
if (dwResult == 0)
return S_FALSE;
nsCAutoString moduleName(szModuleName);
nsCAutoString registryKey("CLSID\\");
moduleName += MAPI_STARTUP_ARG;
// Convert the CLSID into a char.
if (!CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)))
return S_FALSE;
registryKey += szCLSID;
// Add the CLSID to the registry.
if (!setKeyAndValue(registryKey, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(registryKey, "LocalServer32", moduleName.get()))
return S_FALSE;
// Add the ProgID subkey under the CLSID key.
if (!setKeyAndValue(registryKey, "ProgID", szProgID))
return S_FALSE;
// Add the version-independent ProgID subkey under CLSID key.
if (!setKeyAndValue(registryKey, "VersionIndependentProgID", szVerIndProgID))
return S_FALSE;
// Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
if (!setKeyAndValue(independentProgId, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(independentProgId, "CLSID", szCLSID))
return S_FALSE;
if (!setKeyAndValue(independentProgId, "CurVer", szProgID))
return S_FALSE;
// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
if (!setKeyAndValue(progId, NULL, szFriendlyName))
return S_FALSE;
if (!setKeyAndValue(progId, "CLSID", szCLSID))
return S_FALSE;
RegisterProxy();
return S_OK;
}
LONG UnregisterServer(const CLSID& clsid, // Class ID
const char* szVerIndProgID, // Programmatic
const char* szProgID) // IDs
{
LONG lResult = S_OK;
// Convert the CLSID into a char.
char szCLSID[CLSID_STRING_SIZE];
if (!CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)))
return S_FALSE;
UnRegisterProxy();
nsCAutoString registryKey("CLSID\\");
registryKey += szCLSID;
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, registryKey.get());
if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND)
return lResult;
registryKey += "\\LocalServer32";
// Delete only the path for this server.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, registryKey.get());
if (lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND)
return lResult;
// Delete the version-independent ProgID Key.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID);
if (lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND)
return lResult;
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID);
return lResult;
}

View File

@@ -0,0 +1,56 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Krishna Mohan Khandrika <kkhandrika@netscape.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 ***** */
#ifndef _REGISTRY_H_
#define _REGISTRY_H_
#include <objbase.h>
// This function will register a component in the Registry.
HRESULT RegisterServer(const CLSID& clsid,
const char* szFriendlyName,
const char* szVerIndProgID,
const char* szProgID) ;
// This function will unregister a component.
HRESULT UnregisterServer(const CLSID& clsid,
const char* szVerIndProgID,
const char* szProgID) ;
#endif

View File

@@ -0,0 +1,107 @@
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.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 *****
DEPTH=..\..\..\..
MODULE = msgMapi
MAKE_OBJ_TYPE = DLL
LIBRARY_NAME=$(MODULE)
MODULE_NAME = $(MODULE)
REQUIRES = xpcom \
string \
MapiProxy \
appshell \
windowwatcher \
dom \
profile \
msgbase \
pref \
msgbaseutil \
msgcompo \
mailnews \
necko \
intl \
editor \
msgdb \
uriloader \
appstartup \
$(NULL)
include <$(DEPTH)\config\config.mak>
############################################################################
LCFLAGS=-DUNICODE -D_UNICODE
OBJS= \
..\build\$(OBJDIR)\msgMapi_i.obj \
.\$(OBJDIR)\msgMapiFactory.obj \
.\$(OBJDIR)\msgMapiHook.obj \
.\$(OBJDIR)\msgMapiImp.obj \
.\$(OBJDIR)\msgMapiMain.obj \
.\$(OBJDIR)\msgMapiSupport.obj \
.\$(OBJDIR)\nsMapiRegistry.obj \
.\$(OBJDIR)\nsMapiRegistryUtils.obj \
.\$(OBJDIR)\Registry.obj \
$(NULL)
LLIBS= \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\msgbsutl.lib \
$(LIBNSPR) \
$(NULL)
WIN_LIBS= \
ole32.lib \
$(NULL)
EXPORTS= \
msgMapiFactory.h \
msgMapiHook.h \
msgMapiImp.h \
msgMapiMain.h \
msgMapiSupport.h \
nsMapiRegistry.h \
nsMapiRegistryUtils.h \
Registry.h \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,118 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#undef UNICODE
#undef _UNICODE
#include "msgMapiFactory.h"
#include "msgMapiImp.h"
#include "msgMapi.h"
CMapiFactory ::CMapiFactory()
: m_cRef(1)
{
}
CMapiFactory::~CMapiFactory()
{
}
STDMETHODIMP CMapiFactory::QueryInterface(const IID& aIid, void** aPpv)
{
if ((aIid == IID_IUnknown) || (aIid == IID_IClassFactory))
{
*aPpv = static_cast<IClassFactory*>(this);
}
else
{
*aPpv = nsnull;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*aPpv)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CMapiFactory::AddRef()
{
return (PR_AtomicIncrement(&m_cRef));
}
STDMETHODIMP_(ULONG) CMapiFactory::Release()
{
PRInt32 temp;
temp = PR_AtomicDecrement(&m_cRef);
if (m_cRef == 0)
{
delete this;
return 0;
}
return temp;
}
STDMETHODIMP CMapiFactory::CreateInstance(IUnknown* aUnknownOuter,
const IID& aIid,
void** aPpv)
{
// Cannot aggregate.
if (aUnknownOuter != nsnull)
{
return CLASS_E_NOAGGREGATION ;
}
// Create component.
CMapiImp* pImp = new CMapiImp();
if (pImp == nsnull)
{
return E_OUTOFMEMORY ;
}
// Get the requested interface.
HRESULT hr = pImp->QueryInterface(aIid, aPpv);
// Release the IUnknown pointer.
// (If QueryInterface failed, component will delete itself.)
pImp->Release();
return hr;
}
STDMETHODIMP CMapiFactory::LockServer(PRBool aLock)
{
return S_OK ;
}

View File

@@ -0,0 +1,69 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#ifndef MSG_MAPI_FACTORY_H
#define MSG_MAPI_FACTORY_H
#include <windows.h>
#include <objbase.h>
#include "nspr.h"
class CMapiFactory : public IClassFactory
{
public :
// IUnknown
STDMETHODIMP QueryInterface (REFIID aIid, void** aPpv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IClassFactory
STDMETHODIMP CreateInstance (LPUNKNOWN aUnkOuter, REFIID aIid, void **aPpv);
STDMETHODIMP LockServer (BOOL aLock);
CMapiFactory ();
~CMapiFactory ();
private :
PRInt32 m_cRef;
};
#endif // MSG_MAPI_FACTORY_H

View File

@@ -0,0 +1,777 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.com)
* Contributor(s): Srilatha Moturi (srilatha@netscape.com)
* Contributor(s): Rajiv Dayal (rdayal@netscape.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 ***** */
#define MAPI_STARTUP_ARG "/MAPIStartUp"
#define MAPI_STARTUP_ARG "/MAPIStartUp"
#include <mapidefs.h>
#include <mapi.h>
#include <tchar.h>
#include "nsCOMPtr.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsISupports.h"
#include "nsIPromptService.h"
#include "nsAppShellCIDs.h"
#include "nsIDOMWindowInternal.h"
#include "nsIAppShellService.h"
#include "nsINativeAppSupport.h"
#include "nsICmdLineService.h"
#include "nsIProfileInternal.h"
#include "nsIMsgAccountManager.h"
#include "nsIDOMWindowInternal.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsMsgBaseCID.h"
#include "nsIStringBundle.h"
#include "nsIPref.h"
#include "nsString.h"
#include "nsIMsgAttachment.h"
#include "nsIMsgCompFields.h"
#include "nsIMsgComposeParams.h"
#include "nsIMsgCompose.h"
#include "nsMsgCompCID.h"
#include "nsIMsgSend.h"
#include "nsIProxyObjectManager.h"
#include "nsIMsgComposeService.h"
#include "nsProxiedService.h"
#include "nsSpecialSystemDirectory.h"
#include "nsMsgI18N.h"
#include "msgMapi.h"
#include "msgMapiHook.h"
#include "msgMapiSupport.h"
#include "msgMapiMain.h"
#include "nsNetUtil.h"
static NS_DEFINE_CID(kCmdLineServiceCID, NS_COMMANDLINE_SERVICE_CID);
class nsMAPISendListener : public nsIMsgSendListener
{
public:
virtual ~nsMAPISendListener() { }
// nsISupports interface
NS_DECL_ISUPPORTS
/* void OnStartSending (in string aMsgID, in PRUint32 aMsgSize); */
NS_IMETHOD OnStartSending(const char *aMsgID, PRUint32 aMsgSize) { return NS_OK; }
/* void OnProgress (in string aMsgID, in PRUint32 aProgress, in PRUint32 aProgressMax); */
NS_IMETHOD OnProgress(const char *aMsgID, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK;}
/* void OnStatus (in string aMsgID, in wstring aMsg); */
NS_IMETHOD OnStatus(const char *aMsgID, const PRUnichar *aMsg) { return NS_OK;}
/* void OnStopSending (in string aMsgID, in nsresult aStatus, in wstring aMsg, in nsIFileSpec returnFileSpec); */
NS_IMETHOD OnStopSending(const char *aMsgID, nsresult aStatus, const PRUnichar *aMsg,
nsIFileSpec *returnFileSpec) {
m_done = PR_TRUE;
HANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, (LPCTSTR) MAPI_SENDCOMPLETE_EVENT) ;
SetEvent (hEvent) ;
CloseHandle (hEvent) ;
return NS_OK ;
}
/* void OnSendNotPerformed */
NS_IMETHOD OnSendNotPerformed(const char *aMsgID, nsresult aStatus)
{
return OnStopSending(aMsgID, aStatus, nsnull, nsnull) ;
}
/* void OnGetDraftFolderURI (); */
NS_IMETHOD OnGetDraftFolderURI(const char *aFolderURI) {return NS_OK;}
static nsresult CreateMAPISendListener( nsIMsgSendListener **ppListener);
PRBool IsDone() { return m_done ; }
protected :
nsMAPISendListener() {
NS_INIT_REFCNT();
m_done = PR_FALSE;
}
PRBool m_done;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(nsMAPISendListener, nsIMsgSendListener)
nsresult nsMAPISendListener::CreateMAPISendListener( nsIMsgSendListener **ppListener)
{
NS_ENSURE_ARG_POINTER(ppListener) ;
*ppListener = new nsMAPISendListener();
if (! *ppListener)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*ppListener);
return NS_OK;
}
PRBool nsMapiHook::isMapiService = PR_FALSE;
PRBool nsMapiHook::Initialize()
{
nsresult rv;
nsCOMPtr<nsINativeAppSupport> native;
nsCOMPtr<nsICmdLineService> cmdLineArgs(do_GetService(kCmdLineServiceCID, &rv));
if (NS_FAILED(rv)) return PR_FALSE;
nsCOMPtr<nsIAppShellService> appShell (do_GetService( "@mozilla.org/appshell/appShellService;1", &rv));
if (NS_FAILED(rv)) return PR_FALSE;
rv = appShell->GetNativeAppSupport( getter_AddRefs( native ));
if (NS_FAILED(rv)) return PR_FALSE;
rv = native->EnsureProfile(cmdLineArgs);
if (NS_FAILED(rv)) return PR_FALSE;
return PR_TRUE;
}
void nsMapiHook::CleanUp()
{
// This routine will be fully implemented in future
// to cleanup mapi related stuff inside mozilla code.
}
PRBool nsMapiHook::DisplayLoginDialog(PRBool aLogin, PRUnichar **aUsername, \
PRUnichar **aPassword)
{
nsresult rv;
PRBool btnResult = PR_FALSE;
nsCOMPtr<nsIAppShellService> appShell(do_GetService( "@mozilla.org/appshell/appShellService;1", &rv));
if (NS_FAILED(rv) || !appShell) return PR_FALSE;
nsCOMPtr<nsIPromptService> dlgService(do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv));
if (NS_SUCCEEDED(rv) && dlgService)
{
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
if (NS_FAILED(rv) || !bundleService) return PR_FALSE;
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle));
if (NS_FAILED(rv) || !bundle) return PR_FALSE;
nsCOMPtr<nsIStringBundle> brandBundle;
rv = bundleService->CreateBundle(
"chrome://global/locale/brand.properties",
getter_AddRefs(brandBundle));
if (NS_FAILED(rv)) return PR_FALSE;
nsXPIDLString brandName;
rv = brandBundle->GetStringFromName(
NS_LITERAL_STRING("brandShortName").get(),
getter_Copies(brandName));
if (NS_FAILED(rv)) return PR_FALSE;
nsXPIDLString loginTitle;
const PRUnichar *brandStrings[] = { brandName.get() };
NS_NAMED_LITERAL_STRING(loginTitlePropertyTag, "loginTitle");
const PRUnichar *dTitlePropertyTag = loginTitlePropertyTag.get();
rv = bundle->FormatStringFromName(dTitlePropertyTag, brandStrings, 1,
getter_Copies(loginTitle));
if (NS_FAILED(rv)) return PR_FALSE;
if (aLogin)
{
nsXPIDLString loginText;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("loginTextwithName").get(),
getter_Copies(loginText));
if (NS_FAILED(rv) || !loginText) return PR_FALSE;
rv = dlgService->PromptUsernameAndPassword(nsnull, loginTitle,
loginText, aUsername, aPassword,
nsnull, PR_FALSE, &btnResult);
}
else
{
//nsString loginString;
nsXPIDLString loginText;
const PRUnichar *userNameStrings[] = { *aUsername };
NS_NAMED_LITERAL_STRING(loginTextPropertyTag, "loginText");
const PRUnichar *dpropertyTag = loginTextPropertyTag.get();
rv = bundle->FormatStringFromName(dpropertyTag, userNameStrings, 1,
getter_Copies(loginText));
if (NS_FAILED(rv)) return PR_FALSE;
rv = dlgService->PromptPassword(nsnull, loginTitle, loginText,
aPassword, nsnull, PR_FALSE, &btnResult);
}
}
return btnResult;
}
PRBool nsMapiHook::VerifyUserName(const PRUnichar *aUsername, char **aIdKey)
{
nsresult rv;
if (aUsername == nsnull)
return PR_FALSE;
nsCOMPtr<nsIMsgAccountManager> accountManager(do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv));
if (NS_FAILED(rv)) return PR_FALSE;
nsCOMPtr<nsISupportsArray> identities;
rv = accountManager->GetAllIdentities(getter_AddRefs(identities));
if (NS_FAILED(rv)) return PR_FALSE;
PRUint32 numIndentities;
identities->Count(&numIndentities);
for (PRUint32 i = 0; i < numIndentities; i++)
{
// convert supports->Identity
nsCOMPtr<nsISupports> thisSupports;
rv = identities->GetElementAt(i, getter_AddRefs(thisSupports));
if (NS_FAILED(rv)) continue;
nsCOMPtr<nsIMsgIdentity> thisIdentity(do_QueryInterface(thisSupports, &rv));
if (NS_SUCCEEDED(rv) && thisIdentity)
{
nsXPIDLCString email;
rv = thisIdentity->GetEmail(getter_Copies(email));
if (NS_FAILED(rv)) continue;
// get the username from the email and compare with the username
nsCAutoString aEmail(email.get());
PRInt32 index = aEmail.FindChar('@');
if (index != -1)
aEmail.Truncate(index);
if (nsDependentString(aUsername) == NS_ConvertASCIItoUCS2(aEmail)) // == overloaded
return NS_SUCCEEDED(thisIdentity->GetKey(aIdKey));
}
}
return PR_FALSE;
}
PRBool
nsMapiHook::IsBlindSendAllowed()
{
PRBool enabled = PR_FALSE;
PRBool warn = PR_TRUE;
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
if (prefs) {
prefs->GetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND,&warn);
prefs->GetBoolPref(PREF_MAPI_BLIND_SEND_ENABLED,&enabled);
}
if (!enabled)
return PR_FALSE;
if (!warn)
return PR_TRUE; // Everything is okay.
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
if (NS_FAILED(rv) || !bundleService) return PR_FALSE;
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(MAPI_PROPERTIES_CHROME, getter_AddRefs(bundle));
if (NS_FAILED(rv) || !bundle) return PR_FALSE;
nsXPIDLString warningMsg;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("mapiBlindSendWarning").get(),
getter_Copies(warningMsg));
if (NS_FAILED(rv)) return PR_FALSE;
nsXPIDLString dontShowAgainMessage;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("mapiBlindSendDontShowAgain").get(),
getter_Copies(dontShowAgainMessage));
if (NS_FAILED(rv)) return PR_FALSE;
nsCOMPtr<nsIPromptService> dlgService(do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv));
if (NS_FAILED(rv) || !dlgService) return PR_FALSE;
PRBool continueToWarn = PR_TRUE;
PRBool okayToContinue = PR_FALSE;
dlgService->ConfirmCheck(nsnull, nsnull, warningMsg, dontShowAgainMessage, &continueToWarn, &okayToContinue);
if (!continueToWarn && okayToContinue && prefs)
prefs->SetBoolPref(PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND,PR_FALSE);
return okayToContinue;
}
// this is used for Send without UI
nsresult nsMapiHook::BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields)
{
nsresult rv = NS_OK ;
if (!IsBlindSendAllowed())
return NS_ERROR_FAILURE;
/** create nsIMsgComposeParams obj and other fields to populate it **/
// get parent window
nsCOMPtr<nsIAppShellService> appService = do_GetService( "@mozilla.org/appshell/appShellService;1", &rv);
if (NS_FAILED(rv)|| (!appService) ) return rv ;
nsCOMPtr<nsIDOMWindowInternal> hiddenWindow;
rv = appService->GetHiddenDOMWindow(getter_AddRefs(hiddenWindow));
if ( NS_FAILED(rv) ) return rv ;
// smtp password and Logged in used IdKey from MapiConfig (session obj)
nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ;
if (!pMapiConfig) return NS_ERROR_FAILURE ; // get the singelton obj
PRUnichar * password = pMapiConfig->GetPassword(aSession) ;
// password
nsCAutoString smtpPassword ;
smtpPassword.AssignWithConversion (password) ;
// Id key
char * MsgIdKey = pMapiConfig->GetIdKey(aSession) ;
// get the MsgIdentity for the above key using AccountManager
nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ;
if (NS_FAILED(rv) || (!accountManager) ) return rv ;
nsCOMPtr <nsIMsgIdentity> pMsgId ;
rv = accountManager->GetIdentity (MsgIdKey, getter_AddRefs(pMsgId)) ;
if (NS_FAILED(rv) ) return rv ;
// create a send listener to get back the send status
nsCOMPtr <nsIMsgSendListener> sendListener ;
rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ;
if (NS_FAILED(rv) || (!sendListener) ) return rv;
// create the compose params object
nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
// populate the compose params
pMsgComposeParams->SetType(nsIMsgCompType::New);
pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
pMsgComposeParams->SetIdentity(pMsgId);
pMsgComposeParams->SetComposeFields(aCompFields);
pMsgComposeParams->SetSendListener(sendListener) ;
pMsgComposeParams->SetSmtpPassword(smtpPassword.get());
// create the nsIMsgCompose object to send the object
nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv));
if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ;
/** initialize nsIMsgCompose, Send the message, wait for send completion response **/
rv = pMsgCompose->Initialize(hiddenWindow, pMsgComposeParams) ;
if (NS_FAILED(rv)) return rv ;
pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, pMsgId, nsnull) ;
if (NS_FAILED(rv)) return rv ;
// assign to interface pointer from nsCOMPtr to facilitate typecast below
nsIMsgSendListener * pSendListener = sendListener ;
// we need to wait here to make sure that we return only after send is completed
// so we will have a event loop here which will process the events till the Send IsDone.
nsCOMPtr<nsIEventQueueService> pEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
nsCOMPtr<nsIEventQueue> eventQueue;
pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD,getter_AddRefs(eventQueue));
while ( !((nsMAPISendListener *) pSendListener)->IsDone() )
eventQueue->ProcessPendingEvents();
return rv ;
}
// this is used to populate comp fields with Unicode data
nsresult nsMapiHook::PopulateCompFields(lpnsMapiMessage aMessage,
nsIMsgCompFields * aCompFields)
{
nsresult rv = NS_OK ;
if (aMessage->lpOriginator)
{
PRUnichar * From = aMessage->lpOriginator->lpszAddress ;
aCompFields->SetFrom (From) ;
}
nsAutoString To ;
nsAutoString Cc ;
nsAutoString Bcc ;
nsAutoString Comma ;
Comma.AssignWithConversion(",");
if (aMessage->lpRecips)
{
for (int i=0 ; i < (int) aMessage->nRecipCount ; i++)
{
if (aMessage->lpRecips[i].lpszAddress)
{
switch (aMessage->lpRecips[i].ulRecipClass)
{
case MAPI_TO :
if (To.Length() > 0)
To += Comma ;
To += (PRUnichar *) aMessage->lpRecips[i].lpszAddress ;
break ;
case MAPI_CC :
if (Cc.Length() > 0)
Cc += Comma ;
Cc += (PRUnichar *) aMessage->lpRecips[i].lpszAddress ;
break ;
case MAPI_BCC :
if (Bcc.Length() > 0)
Bcc += Comma ;
Bcc += (PRUnichar *) aMessage->lpRecips[i].lpszAddress ;
break ;
}
}
}
}
// set To, Cc, Bcc
aCompFields->SetTo (To.get()) ;
aCompFields->SetCc (Cc.get()) ;
aCompFields->SetBcc (Bcc.get()) ;
// set subject
if (aMessage->lpszSubject)
{
PRUnichar * Subject = aMessage->lpszSubject ;
aCompFields->SetSubject(Subject) ;
}
// handle attachments as File URL
rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, PR_TRUE) ;
if (NS_FAILED(rv)) return rv ;
// set body
if (aMessage->lpszNoteText)
{
PRUnichar * Body = aMessage->lpszNoteText ;
rv = aCompFields->SetBody(Body) ;
}
#ifdef RAJIV_DEBUG
// testing what all was set in CompFields
printf ("To : %S \n", To.get()) ;
printf ("CC : %S \n", Cc.get() ) ;
printf ("BCC : %S \n", Bcc.get() ) ;
#endif
return rv ;
}
nsresult nsMapiHook::HandleAttachments (nsIMsgCompFields * aCompFields, PRInt32 aFileCount,
lpnsMapiFileDesc aFiles, BOOL aIsUnicode)
{
nsresult rv = NS_OK ;
nsCAutoString Attachments ;
nsCAutoString TempFiles ;
nsCOMPtr <nsILocalFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
if (NS_FAILED(rv) || (!pFile) ) return rv ;
for (int i=0 ; i < aFileCount ; i++)
{
if (aFiles[i].lpszPathName)
{
// check if attachment exists
if (aIsUnicode)
pFile->InitWithUnicodePath (aFiles[i].lpszPathName) ;
else
pFile->InitWithPath ((char *) aFiles[i].lpszPathName) ;
PRBool bExist ;
rv = pFile->Exists(&bExist) ;
if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
// create Msg attachment object
nsCOMPtr<nsIMsgAttachment> attachment = do_CreateInstance(NS_MSGATTACHMENT_CONTRACTID, &rv);
if (NS_FAILED(rv) || (!attachment) ) return rv ;
// set url
nsXPIDLCString pURL ;
NS_GetURLSpecFromFile(pFile, getter_Copies(pURL));
attachment->SetUrl(pURL) ;
if (aFiles[i].lpszFileName)
{
if (! aIsUnicode)
{
nsAutoString realFileName ;
realFileName.AssignWithConversion ((char *) aFiles[i].lpszFileName) ;
attachment->SetName(realFileName.get()) ;
// attachment->SetName( (nsDependentString(aFiles[i].lpszFileName)).get() );
}
else
attachment->SetName(aFiles[i].lpszFileName) ;
}
attachment->SetTemporary(PR_FALSE) ;
rv = aCompFields->AddAttachment (attachment);
}
}
return rv ;
}
// this is used to convert non Unicode data and then populate comp fields
nsresult nsMapiHook::PopulateCompFieldsWithConversion(lpnsMapiMessage aMessage,
nsIMsgCompFields * aCompFields)
{
nsresult rv = NS_OK ;
if (aMessage->lpOriginator)
{
nsAutoString From ;
From.AssignWithConversion((char *) aMessage->lpOriginator->lpszAddress);
aCompFields->SetFrom (From.get()) ;
}
nsAutoString To ;
nsAutoString Cc ;
nsAutoString Bcc ;
nsAutoString Comma ;
Comma.AssignWithConversion(",");
if (aMessage->lpRecips)
{
for (int i=0 ; i < (int) aMessage->nRecipCount ; i++)
{
if (aMessage->lpRecips[i].lpszAddress)
{
switch (aMessage->lpRecips[i].ulRecipClass)
{
case MAPI_TO :
if (To.Length() > 0)
To += Comma ;
To.AppendWithConversion ((char *) aMessage->lpRecips[i].lpszAddress);
break ;
case MAPI_CC :
if (Cc.Length() > 0)
Cc += Comma ;
Cc.AppendWithConversion ((char *) aMessage->lpRecips[i].lpszAddress);
break ;
case MAPI_BCC :
if (Bcc.Length() > 0)
Bcc += Comma ;
Bcc.AppendWithConversion ((char *) aMessage->lpRecips[i].lpszAddress) ;
break ;
}
}
}
}
// set To, Cc, Bcc
aCompFields->SetTo (To.get()) ;
aCompFields->SetCc (Cc.get()) ;
aCompFields->SetBcc (Bcc.get()) ;
nsCAutoString platformCharSet;
// set subject
if (aMessage->lpszSubject)
{
nsAutoString Subject ;
if (platformCharSet.IsEmpty())
platformCharSet.Assign(nsMsgI18NFileSystemCharset());
rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszSubject, Subject);
if (NS_FAILED(rv)) return rv ;
aCompFields->SetSubject(Subject.get()) ;
}
// handle attachments as File URL
rv = HandleAttachments (aCompFields, aMessage->nFileCount, aMessage->lpFiles, PR_FALSE) ;
if (NS_FAILED(rv)) return rv ;
// set body
if (aMessage->lpszNoteText)
{
nsAutoString Body ;
if (platformCharSet.IsEmpty())
platformCharSet.Assign(nsMsgI18NFileSystemCharset());
rv = ConvertToUnicode(platformCharSet.get(), (char *) aMessage->lpszNoteText, Body);
if (NS_FAILED(rv)) return rv ;
rv = aCompFields->SetBody(Body.get()) ;
}
#ifdef RAJIV_DEBUG
// testing what all was set in CompFields
printf ("To : %S \n", To.get()) ;
printf ("CC : %S \n", Cc.get() ) ;
printf ("BCC : %S \n", Bcc.get() ) ;
#endif
return rv ;
}
// this is used to populate the docs as attachments in the Comp fields for Send Documents
nsresult nsMapiHook::PopulateCompFieldsForSendDocs(nsIMsgCompFields * aCompFields, ULONG aFlags,
PRUnichar * aDelimChar, PRUnichar * aFilePaths)
{
nsAutoString strDelimChars ;
nsString strFilePaths;
nsresult rv = NS_OK ;
if (aFlags & MAPI_UNICODE)
{
if (aDelimChar)
strDelimChars.Assign (aDelimChar) ;
if (aFilePaths)
strFilePaths.Assign (aFilePaths) ;
}
else
{
if (aDelimChar)
strDelimChars.AssignWithConversion ((char*) aDelimChar) ;
if (aFilePaths)
strFilePaths.AssignWithConversion ((char *) aFilePaths) ;
}
// check for comma in filename
if (strDelimChars.Find (",") == kNotFound) // if comma is not in the delimiter specified by user
{
if (strFilePaths.Find(",") != kNotFound) // if comma found in filenames return error
return NS_ERROR_FILE_INVALID_PATH ;
}
nsCString Attachments ;
// only 1 file is to be sent, no delim specified
if ((!strDelimChars.Length()) && (strFilePaths.Length()>0))
{
nsCOMPtr <nsILocalFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
if (NS_FAILED(rv) || (!pFile) ) return rv ;
pFile->InitWithUnicodePath (strFilePaths.get()) ;
PRBool bExist ;
rv = pFile->Exists(&bExist) ;
if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
nsXPIDLCString pURL ;
NS_GetURLSpecFromFile(pFile, getter_Copies(pURL));
if (pURL)
Attachments.Assign(pURL) ;
// set attachments for comp field and return
rv = aCompFields->SetAttachments (Attachments.get());
return rv ;
}
// multiple files to be sent, delim specified
nsCOMPtr <nsILocalFile> pFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv) ;
if (NS_FAILED(rv) || (!pFile) ) return rv ;
PRInt32 offset = 0 ;
PRInt32 FilePathsLen = strFilePaths.Length() ;
if (FilePathsLen)
{
PRUnichar * newFilePaths = (PRUnichar *) strFilePaths.get() ;
while (offset != kNotFound)
{
nsString RemainingPaths ;
RemainingPaths.Assign(newFilePaths) ;
offset = RemainingPaths.Find (strDelimChars) ;
if (offset != kNotFound)
{
RemainingPaths.SetLength (offset) ;
if ((offset + strDelimChars.Length()) < FilePathsLen)
newFilePaths += offset + strDelimChars.Length() ;
}
pFile->InitWithUnicodePath (RemainingPaths.get()) ;
#ifdef RAJIV_DEBUG
printf ("File : %S \n", RemainingPaths.get()) ;
#endif
PRBool bExist ;
rv = pFile->Exists(&bExist) ;
if (NS_FAILED(rv) || (!bExist) ) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
nsXPIDLCString pURL ;
NS_GetURLSpecFromFile(pFile, getter_Copies(pURL));
if (pURL)
{
if (Attachments.Length() > 0)
Attachments.Append(",") ;
Attachments.Append(pURL) ;
}
}
rv = aCompFields->SetAttachments (Attachments.get());
}
return rv ;
}
// this used for Send with UI
nsresult nsMapiHook::ShowComposerWindow (unsigned long aSession, nsIMsgCompFields * aCompFields)
{
nsresult rv = NS_OK ;
// create a send listener to get back the send status
nsCOMPtr <nsIMsgSendListener> sendListener ;
rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ;
if (NS_FAILED(rv) || (!sendListener) ) return rv ;
// create the compose params object
nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv));
if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ;
// populate the compose params
pMsgComposeParams->SetType(nsIMsgCompType::New);
pMsgComposeParams->SetFormat(nsIMsgCompFormat::Default);
pMsgComposeParams->SetComposeFields(aCompFields);
pMsgComposeParams->SetSendListener(sendListener) ;
/** get the nsIMsgComposeService object to open the compose window **/
nsCOMPtr <nsIMsgComposeService> compService = do_GetService (NS_MSGCOMPOSESERVICE_CONTRACTID) ;
if (NS_FAILED(rv)|| (!compService) ) return rv ;
rv = compService->OpenComposeWindowWithParams(nsnull, pMsgComposeParams) ;
if (NS_FAILED(rv)) return rv ;
return rv ;
}

View File

@@ -0,0 +1,66 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#ifndef MSG_MAPI_HOOK_H_
#define MSG_MAPI_HOOK_H_
#include "prtypes.h"
class nsMapiHook
{
public :
static PRBool Initialize();
static PRBool DisplayLoginDialog(PRBool aLogin, PRUnichar **aUsername,
PRUnichar **aPassword);
static PRBool VerifyUserName(const PRUnichar *aUsername, char **aIdKey);
static PRBool IsBlindSendAllowed () ;
static nsresult BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) ;
static nsresult ShowComposerWindow (unsigned long aSession, nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFields(lpnsMapiMessage aMessage, nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFieldsWithConversion(lpnsMapiMessage aMessage,
nsIMsgCompFields * aCompFields) ;
static nsresult PopulateCompFieldsForSendDocs(nsIMsgCompFields * aCompFields,
ULONG aFlags, LPTSTR aDelimChar, LPTSTR aFilePaths) ;
static nsresult HandleAttachments (nsIMsgCompFields * aCompFields, PRInt32 aFileCount,
lpnsMapiFileDesc aFiles, BOOL aIsUnicode) ;
static void CleanUp();
static PRBool isMapiService;
};
#endif // MSG_MAPI_HOOK_H_

View File

@@ -0,0 +1,266 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.com)
* Contributor(s): Rajiv Dayal (rdayal@netscape.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 ***** */
#include <mapidefs.h>
#include <mapi.h>
#include "msgMapi.h"
#include "msgMapiImp.h"
#include "msgMapiFactory.h"
#include "msgMapiMain.h"
#include "nsMsgCompFields.h"
#include "msgMapiHook.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsMsgCompCID.h"
CMapiImp::CMapiImp()
: m_cRef(1)
{
m_Lock = PR_NewLock();
}
CMapiImp::~CMapiImp()
{
if (m_Lock)
PR_DestroyLock(m_Lock);
}
STDMETHODIMP CMapiImp::QueryInterface(const IID& aIid, void** aPpv)
{
if (aIid == IID_IUnknown)
{
*aPpv = static_cast<nsIMapi*>(this);
}
else if (aIid == IID_nsIMapi)
{
*aPpv = static_cast<nsIMapi*>(this);
}
else
{
*aPpv = nsnull;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*aPpv)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CMapiImp::AddRef()
{
return PR_AtomicIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CMapiImp::Release()
{
PRInt32 temp;
temp = PR_AtomicDecrement(&m_cRef);
if (m_cRef == 0)
{
delete this;
return 0;
}
return temp;
}
STDMETHODIMP CMapiImp::IsValid()
{
return S_OK;
}
STDMETHODIMP CMapiImp::IsValidSession(unsigned long aSession)
{
nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration();
if (pConfig && pConfig->IsSessionValid(aSession))
return S_OK;
return E_FAIL;
}
STDMETHODIMP CMapiImp::Initialize()
{
HRESULT hr = E_FAIL;
if (!m_Lock)
return E_FAIL;
PR_Lock(m_Lock);
// Initialize MAPI Configuration
nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration();
if (pConfig != nsnull)
if (nsMapiHook::Initialize())
hr = S_OK;
PR_Unlock(m_Lock);
return hr;
}
STDMETHODIMP CMapiImp::Login(unsigned long aUIArg, LOGIN_PW_TYPE aLogin, LOGIN_PW_TYPE aPassWord,
unsigned long aFlags, unsigned long *aSessionId)
{
HRESULT hr = E_FAIL;
PRBool bNewSession = PR_FALSE;
char *id_key = nsnull;
if (aFlags & MAPI_NEW_SESSION)
bNewSession = PR_TRUE;
// Check For Profile Name
if (aLogin != nsnull && aLogin[0] != '\0')
{
if (nsMapiHook::VerifyUserName(aLogin, &id_key) == PR_FALSE)
{
*aSessionId = MAPI_E_LOGIN_FAILURE;
return hr;
}
}
// finally register(create) the session.
PRUint32 nSession_Id;
PRInt16 nResult = 0;
nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration();
if (pConfig != nsnull)
nResult = pConfig->RegisterSession(aUIArg, aLogin, aPassWord,
(aFlags & MAPI_FORCE_DOWNLOAD), bNewSession,
&nSession_Id, id_key);
switch (nResult)
{
case -1 :
{
*aSessionId = MAPI_E_TOO_MANY_SESSIONS;
return hr;
}
case 0 :
{
*aSessionId = MAPI_E_INSUFFICIENT_MEMORY;
return hr;
}
default :
{
*aSessionId = nSession_Id;
break;
}
}
return S_OK;
}
STDMETHODIMP CMapiImp::SendMail( unsigned long aSession, lpnsMapiMessage aMessage,
short aRecipCount, lpnsMapiRecipDesc aRecips , short aFileCount, lpnsMapiFileDesc aFiles ,
unsigned long aFlags, unsigned long aReserved)
{
nsresult rv = NS_OK ;
// Assign the pointers in the aMessage struct to the array of Recips and Files
// recieved here from MS COM. These are used in BlindSendMail and ShowCompWin fns
aMessage->lpRecips = aRecips ;
aMessage->lpFiles = aFiles ;
/** create nsIMsgCompFields obj and populate it **/
nsCOMPtr<nsIMsgCompFields> pCompFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ;
if (NS_FAILED(rv) || (!pCompFields) ) return MAPI_E_INSUFFICIENT_MEMORY ;
if (aFlags & MAPI_UNICODE)
rv = nsMapiHook::PopulateCompFields(aMessage, pCompFields) ;
else
rv = nsMapiHook::PopulateCompFieldsWithConversion(aMessage, pCompFields) ;
if (NS_SUCCEEDED (rv))
{
// see flag to see if UI needs to be brought up
if (!(aFlags & MAPI_DIALOG))
{
rv = nsMapiHook::BlindSendMail(aSession, pCompFields);
}
else
{
rv = nsMapiHook::ShowComposerWindow(aSession, pCompFields);
}
}
return nsMAPIConfiguration::GetMAPIErrorFromNSError (rv) ;
}
STDMETHODIMP CMapiImp::SendDocuments( unsigned long aSession, LPTSTR aDelimChar,
LPTSTR aFilePaths, LPTSTR aFileNames, ULONG aFlags)
{
nsresult rv = NS_OK ;
/** create nsIMsgCompFields obj and populate it **/
nsCOMPtr<nsIMsgCompFields> pCompFields = do_CreateInstance(NS_MSGCOMPFIELDS_CONTRACTID, &rv) ;
if (NS_FAILED(rv) || (!pCompFields) ) return MAPI_E_INSUFFICIENT_MEMORY ;
if (aFilePaths)
{
rv = nsMapiHook::PopulateCompFieldsForSendDocs(pCompFields, aFlags, aDelimChar, aFilePaths) ;
}
if (NS_SUCCEEDED (rv))
rv = nsMapiHook::ShowComposerWindow(aSession, pCompFields);
return nsMAPIConfiguration::GetMAPIErrorFromNSError (rv) ;
}
STDMETHODIMP CMapiImp::Logoff (unsigned long aSession)
{
nsMAPIConfiguration *pConfig = nsMAPIConfiguration::GetMAPIConfiguration();
if (pConfig->UnRegisterSession((PRUint32)aSession))
return S_OK;
return E_FAIL;
}
STDMETHODIMP CMapiImp::CleanUp()
{
nsMapiHook::CleanUp();
return S_OK;
}

View File

@@ -0,0 +1,92 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#ifndef MSG_MAPI_IMP_H
#define MSG_MAPI_IMP_H
#include <windows.h>
#include <mapi.h>
#include "msgMapi.h"
#include "nsXPIDLString.h"
#include "nspr.h"
const CLSID CLSID_CMapiImp = {0x29f458be, 0x8866, 0x11d5, {0xa3, 0xdd, 0x0, 0xb0, 0xd0, 0xf3, 0xba, 0xa7}};
// this class implements the MS COM interface nsIMapi that provides the methods
// called by mapi32.dll to perform the mail operations as specified by MAPI.
// These class methods in turn use the Mozilla Mail XPCOM interfaces to do so.
class CMapiImp : public nsIMapi
{
public :
// IUnknown
STDMETHODIMP QueryInterface(const IID& aIid, void** aPpv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// Interface INsMapi
STDMETHODIMP Login(unsigned long aUIArg, LOGIN_PW_TYPE aLogin,
LOGIN_PW_TYPE aPassWord, unsigned long aFlags,
unsigned long *aSessionId);
STDMETHODIMP SendMail( unsigned long aSession, lpnsMapiMessage aMessage,
short aRecipCount, lpnsMapiRecipDesc aRecips ,
short aFileCount, lpnsMapiFileDesc aFiles ,
unsigned long aFlags, unsigned long aReserved) ;
STDMETHODIMP SendDocuments( unsigned long aSession, LPTSTR aDelimChar,
LPTSTR aFilePaths, LPTSTR aFileNames, ULONG aFlags);
STDMETHODIMP Initialize();
STDMETHODIMP IsValid();
STDMETHODIMP IsValidSession(unsigned long aSession);
STDMETHODIMP Logoff (unsigned long aSession);
STDMETHODIMP CleanUp();
CMapiImp();
~CMapiImp();
private :
PRLock *m_Lock;
PRInt32 m_cRef;
};
#endif // MSG_MAPI_IMP_H

View File

@@ -0,0 +1,376 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#include <mapidefs.h>
#include <mapi.h>
#include "msgCore.h"
#include "nsMsgComposeStringBundle.h"
#include "msgMapiMain.h"
#include "nsIServiceManager.h"
#include "nsCOMPtr.h"
// move to xpcom bug 81956.
class nsPRUintKey : public nsHashKey {
protected:
PRUint32 mKey;
public:
nsPRUintKey(PRUint32 key) : mKey(key) {}
PRUint32 HashCode(void) const {
return mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return mKey == ((const nsPRUintKey *) aKey)->mKey;
}
nsHashKey *Clone() const {
return new nsPRUintKey(mKey);
}
PRUint32 GetValue() { return mKey; }
};
//
nsMAPIConfiguration *nsMAPIConfiguration::m_pSelfRef = nsnull;
PRUint32 nsMAPIConfiguration::session_generator = 0;
PRUint32 nsMAPIConfiguration::sessionCount = 0;
nsMAPIConfiguration *nsMAPIConfiguration::GetMAPIConfiguration()
{
if (m_pSelfRef == nsnull)
m_pSelfRef = new nsMAPIConfiguration();
return m_pSelfRef;
}
nsMAPIConfiguration::nsMAPIConfiguration()
: m_nMaxSessions(MAX_SESSIONS)
{
m_Lock = PR_NewLock();
}
static PRBool
FreeSessionMapEntries(nsHashKey *aKey, void *aData, void* aClosure)
{
nsMAPISession *pTemp = (nsMAPISession*) aData;
if (pTemp)
{
delete pTemp;
pTemp = nsnull;
}
return PR_TRUE;
}
static PRBool
FreeProfileMapEntries(nsHashKey *aKey, void *aData, void* aClosure)
{
return PR_TRUE;
}
nsMAPIConfiguration::~nsMAPIConfiguration()
{
if (m_Lock)
PR_DestroyLock(m_Lock);
m_SessionMap.Reset(FreeSessionMapEntries);
m_ProfileMap.Reset(FreeProfileMapEntries);
}
void nsMAPIConfiguration::OpenConfiguration()
{
// No. of max. sessions is set to MAX_SESSIONS. In future
// if it is decided to have configuration (registry)
// parameter, this function can be used to set the
// max sessions;
return;
}
PRInt16 nsMAPIConfiguration::RegisterSession(PRUint32 aHwnd,
const PRUnichar *aUserName, const PRUnichar *aPassword,
PRBool aForceDownLoad, PRBool aNewSession,
PRUint32 *aSession, char *aIdKey)
{
PRInt16 nResult = 0;
PRUint32 n_SessionId = 0;
PR_Lock(m_Lock);
// Check whether max sessions is exceeded
if (sessionCount >= m_nMaxSessions)
{
PR_Unlock(m_Lock);
return -1;
}
if (aUserName != nsnull && aUserName[0] != '\0')
{
nsStringKey usernameKey(aUserName);
n_SessionId = (PRUint32) m_ProfileMap.Get(&usernameKey);
}
// try to share a session; if not create a session
if (n_SessionId > 0)
{
nsPRUintKey sessionKey(n_SessionId);
nsMAPISession *pTemp = (nsMAPISession *)m_SessionMap.Get(&sessionKey);
if (pTemp != nsnull)
{
pTemp->IncrementSession();
*aSession = n_SessionId;
nResult = 1;
}
}
else if (aNewSession || n_SessionId == 0) // checking for n_SessionId is a concession
{
// create a new session ; if new session is specified OR there is no session
nsMAPISession *pTemp = nsnull;
pTemp = new nsMAPISession(aHwnd, aUserName,
aPassword, aForceDownLoad, aIdKey);
if (pTemp != nsnull)
{
session_generator++;
// I don't think there will be (2 power 32) sessions alive
// in a cycle. This is an assumption
if (session_generator == 0)
session_generator++;
nsPRUintKey sessionKey(session_generator);
m_SessionMap.Put(&sessionKey, pTemp);
if (aUserName != nsnull && aUserName[0] != '\0')
{
nsStringKey usernameKey(aUserName);
m_ProfileMap.Put(&usernameKey, (void*)session_generator);
}
*aSession = session_generator;
sessionCount++;
nResult = 1;
}
}
PR_Unlock(m_Lock);
return nResult;
}
PRBool nsMAPIConfiguration::UnRegisterSession(PRUint32 aSessionID)
{
PRBool bResult = PR_FALSE;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsPRUintKey sessionKey(aSessionID);
nsMAPISession *pTemp = (nsMAPISession *)m_SessionMap.Get(&sessionKey);
if (pTemp != nsnull)
{
if (pTemp->DecrementSession() == 0)
{
if (pTemp->m_pProfileName.get() != nsnull)
{
nsStringKey stringKey(pTemp->m_pProfileName.get());
m_ProfileMap.Remove(&stringKey);
}
m_SessionMap.Remove(&sessionKey);
sessionCount--;
bResult = PR_TRUE;
}
}
}
PR_Unlock(m_Lock);
return bResult;
}
PRBool nsMAPIConfiguration::IsSessionValid(PRUint32 aSessionID)
{
if (aSessionID == 0)
return PR_FALSE;
PRBool retValue = PR_FALSE;
nsPRUintKey sessionKey(aSessionID);
PR_Lock(m_Lock);
retValue = m_SessionMap.Exists(&sessionKey);
PR_Unlock(m_Lock);
return retValue;
}
PRUnichar *nsMAPIConfiguration::GetPassword(PRUint32 aSessionID)
{
PRUnichar *pResult = nsnull;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsPRUintKey sessionKey(aSessionID);
nsMAPISession *pTemp = (nsMAPISession *)m_SessionMap.Get(&sessionKey);
if (pTemp)
{
pResult = pTemp->GetPassword();
}
}
PR_Unlock(m_Lock);
return pResult;
}
char *nsMAPIConfiguration::GetIdKey(PRUint32 aSessionID)
{
char *pResult = nsnull;
PR_Lock(m_Lock);
if (aSessionID != 0)
{
nsPRUintKey sessionKey(aSessionID);
nsMAPISession *pTemp = (nsMAPISession *)m_SessionMap.Get(&sessionKey);
if (pTemp)
{
pResult = pTemp->GetIdKey();
}
}
PR_Unlock(m_Lock);
return pResult;
}
// util func
HRESULT nsMAPIConfiguration::GetMAPIErrorFromNSError (nsresult res)
{
HRESULT hr = SUCCESS_SUCCESS ;
if (NS_SUCCEEDED (hr)) return hr ;
// if failure return the related MAPI failure code
switch (res)
{
case NS_MSG_NO_RECIPIENTS :
hr = MAPI_E_BAD_RECIPTYPE ;
break ;
case NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS :
hr = MAPI_E_INVALID_RECIPS ;
break ;
case NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER :
hr = MAPI_E_LOGIN_FAILURE ;
break ;
case NS_MSG_UNABLE_TO_OPEN_FILE :
case NS_MSG_UNABLE_TO_OPEN_TMP_FILE :
case NS_MSG_COULDNT_OPEN_FCC_FOLDER :
case NS_ERROR_FILE_INVALID_PATH :
hr = MAPI_E_ATTACHMENT_OPEN_FAILURE ;
break ;
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST :
hr = MAPI_E_ATTACHMENT_NOT_FOUND ;
break ;
case NS_MSG_CANCELLING :
hr = MAPI_E_USER_ABORT ;
break ;
case NS_MSG_ERROR_WRITING_FILE :
case NS_MSG_UNABLE_TO_SAVE_TEMPLATE :
case NS_MSG_UNABLE_TO_SAVE_DRAFT :
hr = MAPI_E_ATTACHMENT_WRITE_FAILURE ;
break ;
default :
hr = MAPI_E_FAILURE ;
break ;
}
return hr ;
}
nsMAPISession::nsMAPISession(PRUint32 aHwnd, const PRUnichar *aUserName,\
const PRUnichar *aPassword, \
PRBool aForceDownLoad, char *aKey)
: m_bIsForcedDownLoad(aForceDownLoad),
m_hAppHandle(aHwnd),
m_nShared(1),
m_pIdKey(aKey)
{
m_pProfileName.Assign(aUserName);
m_pPassword.Assign(aPassword);
}
nsMAPISession::~nsMAPISession()
{
if (m_pIdKey != nsnull)
{
delete [] m_pIdKey;
m_pIdKey = nsnull;
}
}
PRUint32 nsMAPISession::IncrementSession()
{
return ++m_nShared;
}
PRUint32 nsMAPISession::DecrementSession()
{
return --m_nShared;
}
PRUint32 nsMAPISession::GetSessionCount()
{
return m_nShared;
}
PRUnichar *nsMAPISession::GetPassword()
{
return (PRUnichar *)m_pPassword.get();
}
char *nsMAPISession::GetIdKey()
{
return m_pIdKey;
}

View File

@@ -0,0 +1,112 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#ifndef MSG_MAPI_MAIN_H_
#define NSG_MAPI_MAIN_H_
#define MAX_NAME_LEN 256
#define MAX_PW_LEN 256
#define MAX_SESSIONS 50
#define MAPI_SENDCOMPLETE_EVENT "SendCompletionEvent"
#define MAPI_PROPERTIES_CHROME "chrome://messenger-mapi/locale/mapi.properties"
#define PREF_MAPI_WARN_PRIOR_TO_BLIND_SEND "mapi.blind-send.warn"
#define PREF_MAPI_BLIND_SEND_ENABLED "mapi.blind-send.enabled"
#include "nsXPIDLString.h"
#include "nspr.h"
#include "nsString.h"
#include "nsHashtable.h"
class nsMAPIConfiguration
{
private :
static PRUint32 session_generator;
static PRUint32 sessionCount;
static nsMAPIConfiguration *m_pSelfRef;
PRLock *m_Lock;
PRUint32 m_nMaxSessions;
nsHashtable m_ProfileMap;
nsHashtable m_SessionMap;
nsMAPIConfiguration();
public :
static nsMAPIConfiguration *GetMAPIConfiguration();
void OpenConfiguration();
PRInt16 RegisterSession(PRUint32 aHwnd, const PRUnichar *aUserName, \
const PRUnichar *aPassword, PRBool aForceDownLoad, \
PRBool aNewSession, PRUint32 *aSession, char *aIdKey);
PRBool IsSessionValid(PRUint32 aSessionID);
PRBool UnRegisterSession(PRUint32 aSessionID);
PRUnichar *GetPassword(PRUint32 aSessionID);
char *GetIdKey(PRUint32 aSessionID);
~nsMAPIConfiguration();
// a util func
static HRESULT GetMAPIErrorFromNSError (nsresult res) ;
};
class nsMAPISession
{
friend class nsMAPIConfiguration;
private :
PRBool m_bIsForcedDownLoad;
PRBool m_bApp_or_Service;
PRUint32 m_hAppHandle;
PRUint32 m_nShared;
char *m_pIdKey;
nsString m_pProfileName;
nsString m_pPassword;
public :
nsMAPISession(PRUint32 aHwnd, const PRUnichar *aUserName, \
const PRUnichar *aPassword, \
PRBool aForceDownLoad, char *aKey);
PRUint32 IncrementSession();
PRUint32 DecrementSession();
PRUint32 GetSessionCount();
PRUnichar *nsMAPISession::GetPassword();
char *nsMAPISession::GetIdKey();
~nsMAPISession();
};
#endif // MSG_MAPI_MAIN_H_

View File

@@ -0,0 +1,209 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#include "nsCOMPtr.h"
#include "objbase.h"
#include "nsISupports.h"
#include "nsIGenericFactory.h"
#include "nsIObserverService.h"
#include "nsIAppStartupNotifier.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsICategoryManager.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranchInternal.h"
#include "msgMapiSupport.h"
#include "nsMapiRegistryUtils.h"
#include "nsMapiRegistry.h"
#include "msgMapiImp.h"
/** Implementation of the nsIMapiSupport interface.
* Use standard implementation of nsISupports stuff.
*/
NS_IMPL_THREADSAFE_ISUPPORTS2(nsMapiSupport, nsIMapiSupport, nsIObserver);
static NS_METHOD nsMapiRegistrationProc(nsIComponentManager *aCompMgr,
nsIFile *aPath, const char *registryLocation, const char *componentType,
const nsModuleComponentInfo *info)
{
nsresult rv;
nsCOMPtr<nsICategoryManager> categoryManager(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv))
rv = categoryManager->AddCategoryEntry(APPSTARTUP_CATEGORY, "Mapi Support",
"service," NS_IMAPISUPPORT_CONTRACTID, PR_TRUE, PR_TRUE, nsnull);
return rv ;
}
NS_IMETHODIMP
nsMapiSupport::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
{
nsresult rv = NS_OK ;
if (!nsCRT::strcmp(aTopic, "profile-after-change"))
return InitializeMAPISupport();
if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
return ShutdownMAPISupport();
if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
{
nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject, &rv);
if (NS_FAILED(rv)) return rv;
// which preference changed?
if (!nsCRT::strcmp(MAILNEWS_ALLOW_DEFAULT_MAIL_CLIENT, NS_ConvertUCS2toUTF8(aData).get()))
{
PRBool bIsDefault = PR_FALSE ;
rv = prefs->GetBoolPref(MAILNEWS_ALLOW_DEFAULT_MAIL_CLIENT, &bIsDefault);
if (NS_FAILED(rv)) return rv;
nsCOMPtr <nsIMapiRegistry> mapiRegistry = do_CreateInstance(NS_IMAPIREGISTRY_CONTRACTID, &rv) ;
if (NS_FAILED(rv)) return rv;
return mapiRegistry->SetIsDefaultMailClient(bIsDefault) ;
}
return rv ;
}
nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
if (NS_FAILED(rv)) return rv;
rv = observerService->AddObserver(this,"profile-after-change", PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPrefBranchInternal> prefInternal = do_QueryInterface(prefs, &rv);
if (NS_FAILED(rv)) return rv;
rv = prefInternal->AddObserver(MAILNEWS_ALLOW_DEFAULT_MAIL_CLIENT, this, PR_FALSE);
if (NS_FAILED(rv)) return rv;
return rv;
}
nsMapiSupport::nsMapiSupport()
: m_dwRegister(0),
m_nsMapiFactory(nsnull)
{
NS_INIT_ISUPPORTS();
}
nsMapiSupport::~nsMapiSupport()
{
}
NS_IMETHODIMP
nsMapiSupport::InitializeMAPISupport()
{
::CoInitialize(nsnull) ;
if (m_nsMapiFactory == nsnull) // No Registering if already done. Sanity Check!!
{
m_nsMapiFactory = new CMapiFactory();
if (m_nsMapiFactory != nsnull)
{
HRESULT hr = ::CoRegisterClassObject(CLSID_CMapiImp, \
m_nsMapiFactory, \
CLSCTX_LOCAL_SERVER, \
REGCLS_MULTIPLEUSE, \
&m_dwRegister);
if (FAILED(hr))
{
m_nsMapiFactory->Release() ;
m_nsMapiFactory = nsnull;
return NS_ERROR_FAILURE;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsMapiSupport::ShutdownMAPISupport()
{
if (m_dwRegister != 0)
::CoRevokeClassObject(m_dwRegister);
if (m_nsMapiFactory != nsnull)
{
m_nsMapiFactory->Release();
m_nsMapiFactory = nsnull;
}
::CoUninitialize();
return NS_OK ;
}
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMapiRegistry);
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMapiSupport);
// The list of components we register
static nsModuleComponentInfo components[] =
{
{
NS_IMAPIREGISTRY_CLASSNAME,
NS_IMAPIREGISTRY_CID,
NS_IMAPIREGISTRY_CONTRACTID,
nsMapiRegistryConstructor
},
{
NS_IMAPISUPPORT_CLASSNAME,
NS_IMAPISUPPORT_CID,
NS_IMAPISUPPORT_CONTRACTID,
nsMapiSupportConstructor,
nsMapiRegistrationProc,
nsnull
}
};
NS_IMPL_NSGETMODULE(msgMapiModule, components);

View File

@@ -0,0 +1,66 @@
/* ***** 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 Mozilla
*
* The Initial Developer of the Original Code is
# Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Krishna Mohan Khandrika (kkhandrika@netscape.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 ***** */
#ifndef MSG_MAPI_SUPPORT_H_
#define MSG_MAPI_SUPPORT_H_
#include "nsIObserver.h"
#include "nsIMapiSupport.h"
#include "msgMapiFactory.h"
#define NS_IMAPISUPPORT_CID \
{0x8967fed2, 0xc8bb, 0x11d5, \
{ 0xa3, 0xe9, 0x00, 0xb0, 0xd0, 0xf3, 0xba, 0xa7 }}
class nsMapiSupport : public nsIMapiSupport,
public nsIObserver
{
public :
nsMapiSupport();
~nsMapiSupport();
// Declare all interface methods we must implement.
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIMAPISUPPORT
private :
DWORD m_dwRegister;
CMapiFactory *m_nsMapiFactory;
};
#endif // MSG_MAPI_SUPPORT_H_

View File

@@ -0,0 +1,167 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#include "nsIServiceManager.h"
#include "nsXPIDLString.h"
#include "nsIPromptService.h"
#include "nsIProxyObjectManager.h"
#include "nsProxiedService.h"
#include "nsMapiRegistryUtils.h"
#include "nsMapiRegistry.h"
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
/** Implementation of the nsIMapiRegistry interface.
* Use standard implementation of nsISupports stuff.
*/
NS_IMPL_ISUPPORTS1(nsMapiRegistry, nsIMapiRegistry);
nsMapiRegistry::nsMapiRegistry() {
NS_INIT_ISUPPORTS();
m_ShowDialog = ! m_registryUtils.verifyRestrictedAccess();
m_DefaultMailClient = m_registryUtils.IsDefaultMailClient();
}
nsMapiRegistry::~nsMapiRegistry() {
}
NS_IMETHODIMP
nsMapiRegistry::GetIsDefaultMailClient(PRBool * retval) {
// we need to get the value from registry everytime
// because the registry settings can be changed from
// other mail applications.
*retval = m_registryUtils.IsDefaultMailClient();
return NS_OK;
}
NS_IMETHODIMP
nsMapiRegistry::GetShowDialog(PRBool * retval) {
*retval = m_ShowDialog;
return NS_OK;
}
NS_IMETHODIMP
nsMapiRegistry::SetIsDefaultMailClient(PRBool aIsDefaultMailClient)
{
nsresult rv = NS_OK ;
if (aIsDefaultMailClient)
{
rv = m_registryUtils.setDefaultMailClient();
if (NS_SUCCEEDED(rv))
m_DefaultMailClient = PR_TRUE;
else
m_registryUtils.ShowMapiErrorDialog();
}
else
{
rv = m_registryUtils.unsetDefaultMailClient();
if (NS_SUCCEEDED(rv))
m_DefaultMailClient = PR_FALSE;
else
m_registryUtils.ShowMapiErrorDialog();
}
return rv ;
}
/** This will bring up the dialog box only once per session and
* only if the current app is not default Mail Client.
* This also checks the registry if the registry key
* showMapiDialog is set
*/
NS_IMETHODIMP
nsMapiRegistry::ShowMailIntegrationDialog(nsIDOMWindow *aParentWindow) {
nsresult rv;
if (!m_ShowDialog || !m_registryUtils.getShowDialog()) return NS_OK;
nsCOMPtr<nsIPromptService> promptService(do_GetService(
"@mozilla.org/embedcomp/prompt-service;1", &rv));
if (NS_SUCCEEDED(rv) && promptService)
{
nsCOMPtr<nsIStringBundle> bundle;
rv = m_registryUtils.MakeMapiStringBundle (getter_AddRefs (bundle)) ;
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString dialogTitle;
const PRUnichar *brandStrings[] = { m_registryUtils.brandName() };
NS_NAMED_LITERAL_STRING(dialogTitlePropertyTag, "dialogTitle");
rv = bundle->FormatStringFromName(dialogTitlePropertyTag.get(),
brandStrings, 1,
getter_Copies(dialogTitle));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString dialogText;
NS_NAMED_LITERAL_STRING(dialogTextPropertyTag, "dialogText");
rv = bundle->FormatStringFromName(dialogTextPropertyTag.get(),
brandStrings, 1,
getter_Copies(dialogText));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString checkboxText;
rv = bundle->GetStringFromName(
NS_LITERAL_STRING("checkboxText").get(),
getter_Copies(checkboxText));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
PRBool checkValue = PR_FALSE;
PRInt32 buttonPressed = 0;
rv = promptService->ConfirmEx(aParentWindow,
dialogTitle,
dialogText.get(),
(nsIPromptService::BUTTON_TITLE_YES *
nsIPromptService::BUTTON_POS_0) +
(nsIPromptService::BUTTON_TITLE_NO *
nsIPromptService::BUTTON_POS_1),
nsnull,
nsnull,
nsnull,
checkboxText,
&checkValue,
&buttonPressed);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
rv = m_registryUtils.SetRegistryKey(HKEY_LOCAL_MACHINE, "Software\\Mozilla\\Desktop",
"showMapiDialog", (checkValue) ? "0" : "1");
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
m_ShowDialog = PR_FALSE;
if (!buttonPressed)
rv = SetIsDefaultMailClient(PR_TRUE) ; // SetDefaultMailClient();
}
return rv;
}

View File

@@ -0,0 +1,76 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#ifndef nsmapiregistry_h____
#define nsmapiregistry_h____
#include "nsIMapiRegistry.h"
#ifndef MAX_BUF
#define MAX_BUF 4096
#endif
/* c5be14ba-4e0a-4eec-a1b8-04363761d63c */
#define NS_IMAPIREGISTRY_CID \
{ 0xc5be14ba, 0x4e0a, 0x4eec, {0xa1, 0xb8, 0x04, 0x36, 0x37, 0x61, 0xd6, 0x3c} }
#define NS_IMAPIREGISTRY_CONTRACTID "@mozilla.org/mapiregistry;1"
#define NS_IMAPIREGISTRY_CLASSNAME "Mozilla MAPI Registry"
#define MAILNEWS_ALLOW_DEFAULT_MAIL_CLIENT "mailnews.default_mail_client"
class nsMapiRegistry : public nsIMapiRegistry {
public:
// ctor/dtor
nsMapiRegistry();
virtual ~nsMapiRegistry();
// Declare all interface methods we must implement.
NS_DECL_ISUPPORTS
NS_DECL_NSIMAPIREGISTRY
protected:
PRBool m_DefaultMailClient;
PRBool m_ShowDialog;
nsMapiRegistryUtils m_registryUtils ;
private:
// Special member to handle initialization.
PRBool mHaveBeenSet;
}; // nsMapiRegistry
#endif // nsmapiregistry_h____

View File

@@ -0,0 +1,743 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#undef UNICODE
#undef _UNICODE
#include "nsIServiceManager.h"
#include "msgMapiImp.h"
#include "msgMapiMain.h"
#include "nsMapiRegistryUtils.h"
#include "nsString.h"
#include "nsIStringBundle.h"
#include "nsIPromptService.h"
#include "nsXPIDLString.h"
#include "nsSpecialSystemDirectory.h"
#include "nsDirectoryService.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIPref.h"
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
#define EXE_EXTENSION ".exe"
#define USERAGENT_VERSION_PREF "general.useragent.misc"
#define USERAGENT_VERSION_NS_PREF "general.useragent.vendorSub"
#define USERAGENT_PREF_PREFIX "rv:"
nsMapiRegistryUtils::nsMapiRegistryUtils()
{
m_mapiStringBundle = nsnull ;
}
const char * nsMapiRegistryUtils::thisApplication()
{
if (m_thisApp.IsEmpty()) {
char buffer[MAX_PATH] = {0};
DWORD len = ::GetModuleFileName(NULL, buffer, MAX_PATH);
if (!len) return nsnull ;
char shortPathBuf[MAX_PATH] = {0};
len = ::GetShortPathName(buffer, shortPathBuf, MAX_PATH);
if (!len) return nsnull ;
m_thisApp = buffer;
m_thisApp.ToUpperCase();
}
return m_thisApp.get() ;
}
const PRUnichar * nsMapiRegistryUtils::brandName()
{
nsresult rv;
if (m_brand.IsEmpty()) {
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(
kStringBundleServiceCID, &rv));
if (NS_SUCCEEDED(rv) && bundleService) {
nsCOMPtr<nsIStringBundle> brandBundle;
rv = bundleService->CreateBundle(
"chrome://global/locale/brand.properties",
getter_AddRefs(brandBundle));
if (NS_SUCCEEDED(rv)) {
nsXPIDLString brandName;
rv = brandBundle->GetStringFromName(
NS_LITERAL_STRING("brandShortName").get(),
getter_Copies(brandName));
if (NS_SUCCEEDED(rv)) {
m_brand = brandName ;
}
}
}
}
return m_brand.get() ;
}
const PRUnichar * nsMapiRegistryUtils::versionNo()
{
if (!m_versionNo.IsEmpty())
return m_versionNo.get() ;
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
if (prefs) {
nsXPIDLCString versionStr ;
nsresult rv = prefs->GetCharPref(USERAGENT_VERSION_NS_PREF, getter_Copies(versionStr));
if (NS_SUCCEEDED(rv) && versionStr)
m_versionNo.AssignWithConversion (versionStr.get()) ;
else {
rv = prefs->GetCharPref(USERAGENT_VERSION_PREF, getter_Copies(versionStr));
if (NS_SUCCEEDED(rv) && versionStr) {
m_versionNo.AssignWithConversion (versionStr.get()) ;
m_versionNo.StripChars (USERAGENT_PREF_PREFIX) ;
}
}
}
return m_versionNo.get() ;
}
PRBool nsMapiRegistryUtils::verifyRestrictedAccess() {
char subKey[] = "Software\\Mozilla - Test Key";
PRBool result = PR_FALSE;
DWORD dwDisp = 0;
HKEY key;
// Try to create/open a subkey under HKLM.
DWORD rc = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE,
subKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&key,
&dwDisp);
if (rc == ERROR_SUCCESS) {
// Key was opened; first close it.
::RegCloseKey(key);
// Delete it if we just created it.
switch(dwDisp) {
case REG_CREATED_NEW_KEY:
::RegDeleteKey(HKEY_LOCAL_MACHINE, subKey);
break;
case REG_OPENED_EXISTING_KEY:
break;
}
} else {
// Can't create/open it; we don't have access.
result = PR_TRUE;
}
return result;
}
nsresult nsMapiRegistryUtils::SetRegistryKey(HKEY baseKey, const char * keyName,
const char * valueName, char * value)
{
nsresult result = NS_ERROR_FAILURE;
HKEY key;
LONG rc = ::RegCreateKey(baseKey, keyName, &key);
if (rc == ERROR_SUCCESS) {
rc = ::RegSetValueEx(key, valueName, NULL, REG_SZ,
(LPBYTE)(const char*)value, strlen(value));
if (rc == ERROR_SUCCESS) {
result = NS_OK;
}
::RegCloseKey(key);
}
return result;
}
nsresult nsMapiRegistryUtils::DeleteRegistryValue(HKEY baseKey, const char * keyName,
const char * valueName)
{
nsresult result = NS_ERROR_FAILURE;
HKEY key;
LONG rc = ::RegOpenKey(baseKey, keyName, &key);
if (rc == ERROR_SUCCESS) {
rc = ::RegDeleteValue(key, valueName);
if (rc == ERROR_SUCCESS)
result = NS_OK;
::RegCloseKey(key);
}
return result;
}
void nsMapiRegistryUtils::GetRegistryKey(HKEY baseKey, const char * keyName,
const char * valueName, nsCAutoString & value)
{
HKEY key;
LONG rc = ::RegOpenKey(baseKey, keyName, &key);
if (rc == ERROR_SUCCESS) {
char buffer[MAX_PATH] = {0};
DWORD len = sizeof buffer;
rc = ::RegQueryValueEx(key, valueName, NULL, NULL,
(LPBYTE)buffer, &len);
if (rc == ERROR_SUCCESS) {
if (len)
value = buffer;
}
::RegCloseKey(key);
}
}
PRBool nsMapiRegistryUtils::IsDefaultMailClient()
{
if (!isSmartDll() && !isMozDll())
return PR_FALSE;
nsCAutoString name;
GetRegistryKey(HKEY_LOCAL_MACHINE, "Software\\Clients\\Mail", "", name);
if (!name.IsEmpty()) {
nsCAutoString keyName("Software\\Clients\\Mail\\");
keyName += name.get();
keyName += "\\protocols\\mailto\\shell\\open\\command";
nsCAutoString result;
GetRegistryKey(HKEY_LOCAL_MACHINE, keyName.get(), "", result);
if (!result.IsEmpty()) {
nsCAutoString strExtension;
strExtension.Assign(EXE_EXTENSION);
result.ToUpperCase();
strExtension.ToUpperCase();
PRInt32 index = result.RFind(strExtension.get());
if (index != kNotFound) {
result.Truncate(index + strExtension.Length());
}
nsCAutoString thisApp (thisApplication()) ;
return (result == thisApp);
}
}
return PR_FALSE;
}
nsresult nsMapiRegistryUtils::saveDefaultMailClient()
{
nsresult rv;
nsCAutoString name ;
GetRegistryKey(HKEY_LOCAL_MACHINE,"Software\\Clients\\Mail", "", name);
if (!name.IsEmpty()) {
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"HKEY_LOCAL_MACHINE\\Software\\Clients\\Mail",
(char *)name.get());
if (NS_SUCCEEDED(rv)) {
nsCAutoString keyName("Software\\Clients\\Mail\\");
keyName += name.get();
keyName += "\\protocols\\mailto\\shell\\open\\command";
nsCAutoString appPath ;
GetRegistryKey(HKEY_LOCAL_MACHINE, keyName.get(), "", appPath);
if (!appPath.IsEmpty()) {
nsCAutoString stringName("HKEY_LOCAL_MACHINE\\");
stringName += keyName.get();
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
stringName.get(), (char *)appPath.get());
}
}
}
else
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"HKEY_LOCAL_MACHINE\\Software\\Clients\\Mail",
"");
return rv;
}
nsresult nsMapiRegistryUtils::saveUserDefaultMailClient()
{
nsresult rv;
nsCAutoString name ;
GetRegistryKey(HKEY_CURRENT_USER,"Software\\Clients\\Mail", "", name);
if (!name.IsEmpty()) {
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"HKEY_CURRENT_USER\\Software\\Clients\\Mail",
(char *)name.get());
}
else {
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"HKEY_CURRENT_USER\\Software\\Clients\\Mail",
"");
}
return rv;
}
/**
* Check whether it is a smart dll or not. Smart dll is the one installed by
* IE5 or Outlook Express which forwards the MAPI calls to the dll based on the
* registry key setttings.
* Returns TRUE if is a smart dll.
*/
typedef HRESULT (FAR PASCAL GetOutlookVersionFunc)();
PRBool nsMapiRegistryUtils::isSmartDll()
{
char buffer[MAX_PATH] = {0};
if (GetSystemDirectory(buffer, sizeof(buffer)) == 0)
return PR_FALSE;
PL_strcatn(buffer, sizeof(buffer), "\\Mapi32.dll");
HINSTANCE hInst;
GetOutlookVersionFunc *doesExist = nsnull;
hInst = LoadLibrary(buffer);
if (hInst == nsnull)
return PR_FALSE;
doesExist = (GetOutlookVersionFunc *) GetProcAddress (hInst, "GetOutlookVersion");
FreeLibrary(hInst);
return (doesExist != nsnull);
}
typedef HRESULT (FAR PASCAL GetMapiDllVersion)();
/**
* Checks whether mapi32.dll is installed by this app.
* Returns TRUE if it is.
*/
PRBool nsMapiRegistryUtils::isMozDll()
{
char buffer[MAX_PATH] = {0};
if (GetSystemDirectory(buffer, sizeof(buffer)) == 0)
return PR_FALSE;
PL_strcatn(buffer, sizeof(buffer), "\\Mapi32.dll");
HINSTANCE hInst;
GetMapiDllVersion *doesExist = nsnull;
hInst = LoadLibrary(buffer);
if (hInst == nsnull)
return PR_FALSE;
doesExist = (GetMapiDllVersion *) GetProcAddress (hInst, "GetMapiDllVersion");
FreeLibrary(hInst);
return (doesExist != nsnull);
}
/** Renames Mapi32.dl in system directory to Mapi32_moz_bak.dll
* copies the mozMapi32.dll from bin directory to the system directory
*/
nsresult nsMapiRegistryUtils::CopyMozMapiToWinSysDir()
{
nsresult rv;
char buffer[MAX_PATH] = {0};
if (GetSystemDirectory(buffer, sizeof(buffer)) == 0)
return NS_ERROR_FAILURE;
nsCAutoString filePath(buffer);
filePath.Append("\\Mapi32_moz_bak.dll");
nsCOMPtr<nsILocalFile> pCurrentMapiFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv) || !pCurrentMapiFile) return rv;
pCurrentMapiFile->InitWithPath(filePath.get());
nsCOMPtr<nsIFile> pMozMapiFile;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (!directoryService) return NS_ERROR_FAILURE;
rv = directoryService->Get(NS_OS_CURRENT_PROCESS_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(pMozMapiFile));
if (NS_FAILED(rv)) return rv;
pMozMapiFile->Append("mozMapi32.dll");
PRBool bExist;
rv = pMozMapiFile->Exists(&bExist);
if (NS_FAILED(rv) || !bExist) return rv;
rv = pCurrentMapiFile->Exists(&bExist);
if (NS_SUCCEEDED(rv) && bExist)
{
rv = pCurrentMapiFile->Remove(PR_FALSE);
}
if (NS_FAILED(rv)) return rv;
filePath.Assign(buffer);
filePath.Append("\\Mapi32.dll");
pCurrentMapiFile->InitWithPath(filePath.get());
rv = pCurrentMapiFile->Exists(&bExist);
if (NS_SUCCEEDED(rv) && bExist)
{
rv = pCurrentMapiFile->MoveTo(nsnull, "Mapi32_moz_bak.dll");
if (NS_FAILED(rv)) return rv;
nsCAutoString fullFilePath(buffer);
fullFilePath.Append("\\Mapi32_moz_bak.dll");
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"Mapi_backup_dll",
(char *)fullFilePath.get());
if (NS_FAILED(rv)) {
RestoreBackedUpMapiDll();
return rv;
}
}
NS_NAMED_LITERAL_STRING(fileName, "Mapi32.dll");
filePath.Assign(buffer);
pCurrentMapiFile->InitWithPath(filePath.get());
rv = pMozMapiFile->CopyToUnicode(pCurrentMapiFile, fileName.get());
if (NS_FAILED(rv))
RestoreBackedUpMapiDll();
return rv;
}
/** deletes the Mapi32.dll in system directory and renames Mapi32_moz_bak.dll
* to Mapi32.dll
*/
nsresult nsMapiRegistryUtils::RestoreBackedUpMapiDll()
{
nsresult rv;
char buffer[MAX_PATH] = {0};
if (GetSystemDirectory(buffer, sizeof(buffer)) == 0)
return NS_ERROR_FAILURE;
nsCAutoString filePath(buffer);
nsCAutoString previousFileName(buffer);
filePath.Append("\\Mapi32.dll");
previousFileName.Append("\\Mapi32_moz_bak.dll");
nsCOMPtr <nsILocalFile> pCurrentMapiFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv) || !pCurrentMapiFile) return NS_ERROR_FAILURE;
pCurrentMapiFile->InitWithPath(filePath.get());
nsCOMPtr<nsILocalFile> pPreviousMapiFile = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv) || !pPreviousMapiFile) return NS_ERROR_FAILURE;
pPreviousMapiFile->InitWithPath(previousFileName.get());
PRBool bExist;
rv = pCurrentMapiFile->Exists(&bExist);
if (NS_SUCCEEDED(rv) && bExist) {
rv = pCurrentMapiFile->Remove(PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
rv = pPreviousMapiFile->Exists(&bExist);
if (NS_SUCCEEDED(rv) && bExist)
rv = pPreviousMapiFile->MoveTo(nsnull, "Mapi32.dll");
if (NS_SUCCEEDED(rv))
DeleteRegistryValue(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"Mapi_backup_dll");
return rv;
}
/** Sets Mozilla as default Mail Client
*/
nsresult nsMapiRegistryUtils::setDefaultMailClient()
{
nsresult rv;
nsresult mailKeySet=NS_ERROR_FAILURE;
if (verifyRestrictedAccess()) return NS_ERROR_FAILURE;
if (!isSmartDll()) {
if (NS_FAILED(CopyMozMapiToWinSysDir())) return NS_ERROR_FAILURE;
}
rv = saveDefaultMailClient();
if (NS_FAILED(saveUserDefaultMailClient()) ||
NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsCAutoString keyName("Software\\Clients\\Mail\\");
nsCAutoString appName (NS_ConvertUCS2toUTF8(brandName()).get());
if (!appName.IsEmpty()) {
keyName.Append(appName.get());
nsCOMPtr<nsIStringBundle> bundle;
rv = MakeMapiStringBundle (getter_AddRefs (bundle)) ;
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString defaultMailTitle;
const PRUnichar *keyValuePrefixStr[] = { brandName(), versionNo() };
NS_NAMED_LITERAL_STRING(defaultMailTitleTag, "defaultMailDisplayTitle");
rv = bundle->FormatStringFromName(defaultMailTitleTag.get(),
keyValuePrefixStr, 2,
getter_Copies(defaultMailTitle));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(),
"", NS_CONST_CAST(char *, NS_ConvertUCS2toUTF8(defaultMailTitle).get()) ) ;
}
else
rv = NS_ERROR_FAILURE;
if (NS_SUCCEEDED(rv)) {
nsCAutoString thisApp (thisApplication()) ;
if (NS_FAILED(rv)) return rv ;
nsCAutoString dllPath (thisApp) ;
PRInt32 index = dllPath.RFind("\\");
if (index != kNotFound)
dllPath.Truncate(index + 1);
dllPath += "mozMapi32.dll";
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(), "DLLPath",
(char *)dllPath.get());
if (NS_SUCCEEDED(rv)) {
keyName.Append("\\protocols\\mailto");
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(),
"", "URL:MailTo Protocol");
if (NS_SUCCEEDED(rv)) {
nsCAutoString appPath (thisApp);
appPath += " \"%1\"";
keyName.Append("\\shell\\open\\command");
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(),
"", (char *)appPath.get());
if (NS_SUCCEEDED(rv)) {
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Clients\\Mail",
"", (char *)appName.get());
}
if (NS_SUCCEEDED(rv)) {
nsCAutoString mailAppPath(thisApp);
mailAppPath += " -mail";
nsCAutoString appKeyName ("Software\\Clients\\Mail\\");
appKeyName.Append(appName.get());
appKeyName.Append("\\shell\\open\\command");
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
appKeyName.get(),
"", (char *)mailAppPath.get());
}
if (NS_SUCCEEDED(rv)) {
nsCAutoString iconPath(thisApp);
iconPath += ",0";
nsCAutoString iconKeyName ("Software\\Clients\\Mail\\");
iconKeyName.Append(appName.get());
iconKeyName.Append("\\DefaultIcon");
mailKeySet = SetRegistryKey(HKEY_LOCAL_MACHINE,
iconKeyName.get(),
"", (char *)iconPath.get());
}
}
}
}
if (NS_SUCCEEDED(mailKeySet)) {
nsresult desktopKeySet = SetRegistryKey(HKEY_CURRENT_USER,
"Software\\Clients\\Mail",
"", (char *)appName.get());
if (NS_SUCCEEDED(desktopKeySet)) {
desktopKeySet = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"defaultMailHasBeenSet", "1");
}
::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)"Software\\Clients\\Mail");
RegisterServer(CLSID_CMapiImp, "Mozilla MAPI", "mozMapi", "mozMapi.1");
return desktopKeySet;
}
return mailKeySet;
}
/** Removes Mozilla as the default Mail client and restores the previous setting
*/
nsresult nsMapiRegistryUtils::unsetDefaultMailClient() {
nsresult result = NS_OK;
nsresult mailKeySet = NS_ERROR_FAILURE;
if (verifyRestrictedAccess()) return NS_ERROR_FAILURE;
if (!isSmartDll()) {
if (NS_FAILED(RestoreBackedUpMapiDll())) return NS_ERROR_FAILURE;
}
nsCAutoString name ;
GetRegistryKey(HKEY_LOCAL_MACHINE, "Software\\Mozilla\\Desktop",
"HKEY_LOCAL_MACHINE\\Software\\Clients\\Mail", name);
nsCAutoString appName (NS_ConvertUCS2toUTF8(brandName()).get());
if (!name.IsEmpty() && !appName.IsEmpty() && name.Equals(appName)) {
nsCAutoString keyName("HKEY_LOCAL_MACHINE\\Software\\Clients\\Mail\\");
keyName.Append(appName.get());
keyName.Append("\\protocols\\mailto\\shell\\open\\command");
nsCAutoString appPath ;
GetRegistryKey(HKEY_LOCAL_MACHINE, "Software\\Mozilla\\Desktop",
keyName.get(), appPath);
if (!appPath.IsEmpty()) {
keyName.Assign("Software\\Clients\\Mail\\");
keyName.Append(appName.get());
keyName.Append("\\protocols\\mailto\\shell\\open\\command");
result = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(),
"", (char *)appPath.get());
if (NS_SUCCEEDED(result)) {
PRInt32 index = appPath.RFind("\\");
if (index != kNotFound)
appPath.Truncate(index + 1);
appPath += "mozMapi32.dll";
keyName.Assign("Software\\Clients\\Mail\\");
keyName.Append(appName.get());
result = SetRegistryKey(HKEY_LOCAL_MACHINE,
keyName.get(),
"DLLPath", (char *) appPath.get());
}
}
}
if (!name.IsEmpty()) {
if (NS_SUCCEEDED(result)) {
mailKeySet = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Clients\\Mail",
"", (char *)name.get());
}
}
else
mailKeySet = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Clients\\Mail",
"", "");
if (NS_SUCCEEDED(mailKeySet)) {
nsCAutoString userAppName ;
GetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"HKEY_CURRENT_USER\\Software\\Clients\\Mail", userAppName);
nsresult desktopKeySet = NS_OK;
if (!userAppName.IsEmpty()) {
desktopKeySet = SetRegistryKey(HKEY_CURRENT_USER,
"Software\\Clients\\Mail",
"", (char *)userAppName.get());
}
else {
DeleteRegistryValue(HKEY_CURRENT_USER, "Software\\Clients\\Mail", "");
}
if (NS_SUCCEEDED(desktopKeySet)) {
desktopKeySet = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"defaultMailHasBeenSet", "0");
}
::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)"Software\\Clients\\Mail");
UnregisterServer(CLSID_CMapiImp, "mozMapi", "mozMapi.1");
return desktopKeySet;
}
return mailKeySet;
}
/** Returns FALSE if showMapiDialog is set to 0.
* Returns TRUE otherwise
* Also returns TRUE if the Mozilla has been set as the default mail client
* and some other application has changed that setting.
* This function gets called only if the current app is not the default mail
* client
*/
PRBool nsMapiRegistryUtils::getShowDialog() {
PRBool rv = PR_FALSE;
nsCAutoString showDialog ;
GetRegistryKey(HKEY_LOCAL_MACHINE, "Software\\Mozilla\\Desktop",
"showMapiDialog", showDialog);
// if the user has not selected the checkbox, show dialog
if (showDialog.IsEmpty() || showDialog.Equals("1"))
rv = PR_TRUE;
if (!rv) {
// even if the user has selected the checkbox
// show it if some other application has changed the
// default setting.
nsCAutoString setMailDefault ;
GetRegistryKey(HKEY_LOCAL_MACHINE,"Software\\Mozilla\\Desktop",
"defaultMailHasBeenSet", setMailDefault);
if (setMailDefault.Equals("1")) {
// need to reset the defaultMailHasBeenSet to "0"
// so that after the dialog is displayed once,
// we do not keep displaying this dialog after the user has
// selected the checkbox
rv = SetRegistryKey(HKEY_LOCAL_MACHINE,
"Software\\Mozilla\\Desktop",
"defaultMailHasBeenSet", "0");
rv = PR_TRUE;
}
}
return rv;
}
nsresult nsMapiRegistryUtils::MakeMapiStringBundle(nsIStringBundle ** aMapiStringBundle)
{
nsresult rv = NS_OK ;
if (m_mapiStringBundle)
{
*aMapiStringBundle = m_mapiStringBundle ;
NS_ADDREF(*aMapiStringBundle);
return rv ;
}
nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(
kStringBundleServiceCID, &rv));
if (NS_FAILED(rv) || !bundleService) return NS_ERROR_FAILURE;
rv = bundleService->CreateBundle(
MAPI_PROPERTIES_CHROME,
getter_AddRefs(m_mapiStringBundle));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
NS_ADDREF(*aMapiStringBundle = m_mapiStringBundle) ;
return rv ;
}
nsresult nsMapiRegistryUtils::ShowMapiErrorDialog()
{
nsresult rv;
nsCOMPtr<nsIPromptService> promptService(do_GetService(
"@mozilla.org/embedcomp/prompt-service;1", &rv));
if (NS_SUCCEEDED(rv) && promptService)
{
nsCOMPtr<nsIStringBundle> bundle;
rv = MakeMapiStringBundle (getter_AddRefs (bundle)) ;
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString dialogTitle;
const PRUnichar *brandStrings[] = { brandName() };
NS_NAMED_LITERAL_STRING(dialogTitlePropertyTag, "errorMessageTitle");
rv = bundle->FormatStringFromName(dialogTitlePropertyTag.get(),
brandStrings, 1,
getter_Copies(dialogTitle));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
nsXPIDLString dialogText;
NS_NAMED_LITERAL_STRING(dialogTextPropertyTag, "errorMessage");
rv = bundle->FormatStringFromName(dialogTextPropertyTag.get(),
brandStrings, 1,
getter_Copies(dialogText));
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
rv = promptService->Alert(nsnull, dialogTitle,
dialogText);
}
return rv;
}

View File

@@ -0,0 +1,112 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.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 ***** */
#ifndef nsmapiregistryutils_h____
#define nsmapiregistryutils_h____
#include <windows.h>
#include <string.h>
#include <winreg.h>
#include "Registry.h"
#include "nsString.h"
#include "nsIStringBundle.h"
class nsMapiRegistryUtils
{
private :
nsCAutoString m_thisApp ;
nsAutoString m_brand ;
nsAutoString m_versionNo ;
nsCOMPtr<nsIStringBundle> m_mapiStringBundle ;
public :
nsMapiRegistryUtils() ;
// returns TRUE if the Mapi32.dll is smart dll.
PRBool isSmartDll();
// returns TRUE if the Mapi32.dll is a Mozilla dll.
PRBool isMozDll();
// Returns the (fully-qualified) name of this executable.
const char * thisApplication() ;
// This returns the brand name for this application
const PRUnichar * brandName() ;
// This returns the version no for this application
const PRUnichar * versionNo() ;
// verifyRestrictedAccess - Returns PR_TRUE if this user only has restricted access
// to the registry keys we need to modify.
PRBool verifyRestrictedAccess() ;
// set the Windows registry key
nsresult SetRegistryKey(HKEY baseKey, const char * keyName,
const char * valueName, char * value);
// delete a registry key
nsresult DeleteRegistryValue(HKEY baseKey, const char * keyName,
const char * valueName);
// get a Windows registry key
void GetRegistryKey(HKEY baseKey, const char * keyName,
const char * valueName, nsCAutoString & value) ;
// Returns TRUE if the current application is default mail client.
PRBool IsDefaultMailClient();
// Sets Mozilla as default Mail Client
nsresult setDefaultMailClient() ;
// Removes Mozilla as the default Mail client and restores the previous setting
nsresult unsetDefaultMailClient() ;
// Saves the current setting of the default Mail Client in
// HKEY_LOCAL_MACHINE\\Software\\Mozilla\\Desktop
nsresult saveDefaultMailClient();
// Saves the current user setting of the default Mail Client in
// HKEY_LOCAL_MACHINE\\Software\\Mozilla\\Desktop
nsresult saveUserDefaultMailClient();
nsresult CopyMozMapiToWinSysDir();
nsresult RestoreBackedUpMapiDll();
// Returns FALSE if showMapiDialog is set to 0.
PRBool getShowDialog() ;
// create a string bundle for MAPI messages
nsresult MakeMapiStringBundle(nsIStringBundle ** aMapiStringBundle) ;
// display an error dialog for MAPI messages
nsresult ShowMapiErrorDialog() ;
} ;
#endif

View File

@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<!-- list all the packages being supplied by this jar -->
<RDF:Seq about="urn:mozilla:package:root">
<RDF:li resource="urn:mozilla:package:messenger-mapi"/>
</RDF:Seq>
<!-- package information -->
<RDF:Description about="urn:mozilla:package:messenger-mapi"
chrome:displayName="Messenger"
chrome:author="mozilla.org"
chrome:name="messenger-mapi"
chrome:localeVersion="0.9.7"
chrome:skinVersion="0.9.4">
</RDF:Description>
<!-- overlay information -->
<RDF:Seq about="urn:mozilla:overlays">
<RDF:li resource="chrome://messenger/content/pref-mailnews.xul"/>
</RDF:Seq>
<!-- mapi items for Mail And Newsgroups preferences pane -->
<RDF:Seq about="chrome://messenger/content/pref-mailnews.xul">
<RDF:li>chrome://messenger-mapi/content/pref-mailnewsOverlay.xul</RDF:li>
</RDF:Seq>
</RDF:RDF>

View File

@@ -0,0 +1,3 @@
messenger.jar:
content/messenger-mapi/pref-mailnewsOverlay.xul
content/messenger-mapi/contents.rdf

View File

@@ -0,0 +1,29 @@
#!nmake
#
# 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.com>
#
DEPTH=..\..\..\..
include <$(DEPTH)\config\rules.mak>
chrome::
$(REGCHROME) content messenger-mapi messenger.jar

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<RDF:RDF xmlns:chrome="http://www.mozilla.org/rdf/chrome#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!-- mapi items for mailnews preferences -->
<RDF:Seq about="urn:mozilla:overlays">
<RDF:li resource="chrome://messenger/content/pref-mailnews.xul"/>
</RDF:Seq>
<RDF:Seq about="chrome://messenger/content/pref-mailnews.xul">
<RDF:li>chrome://messenger/content/pref-mailnewsOverlay.xul</RDF:li>
</RDF:Seq>
</RDF:RDF>

View File

@@ -0,0 +1,104 @@
/*
* 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 mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Srilatha Moturi <srilatha@netscape.com>
*/
function mailnewsOverlayStartup() {
mailnewsOverlayInit();
parent.hPrefWindow.registerOKCallbackFunc(onOK);
if (!("mapiPref" in parent)) {
parent.mapiPref = new Object;
parent.mapiPref.isDefaultMailClient =
document.getElementById("mailnewsEnableMapi").checked;
}
else {
// when we switch between different panes
// set the checkbox based on the saved state
var mailnewsEnableMapi = document.getElementById("mailnewsEnableMapi");
if (parent.mapiPref.isDefaultMailClient)
mailnewsEnableMapi.setAttribute("checked", "true");
else
mailnewsEnableMapi.setAttribute("checked", "false");
}
}
function mailnewsOverlayInit() {
try {
var mapiRegistry = Components.classes[ "@mozilla.org/mapiregistry;1" ].
getService( Components.interfaces.nsIMapiRegistry );
}
catch(ex){
mapiRegistry = null;
}
const prefbase = "system.windows.lock_ui.";
var mailnewsEnableMapi = document.getElementById("mailnewsEnableMapi");
if (mapiRegistry) {
// initialise preference component.
// While the data is coming from the system registry, we use a set
// of parallel preferences to indicate if the ui should be locked.
try {
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService()
.QueryInterface(Components.interfaces.nsIPrefService);
var prefBranch = prefService.getBranch(prefbase);
if (prefBranch && prefBranch.prefIsLocked("default_mail_client")) {
if (prefBranch.getBoolPref("default_mail_client"))
mapiRegistry.setDefaultMailClient();
else
mapiRegistry.unsetDefaultMailClient();
mailnewsEnableMapi.setAttribute("disabled", "true");
}
}
catch(ex) {}
if (mapiRegistry.isDefaultMailClient)
mailnewsEnableMapi.setAttribute("checked", "true");
else
mailnewsEnableMapi.setAttribute("checked", "false");
}
else
mailnewsEnableMapi.setAttribute("disabled", "true");
}
function onEnableMapi() {
// save the state of the checkbox
if ("mapiPref" in parent)
parent.mapiPref.isDefaultMailClient =
document.getElementById("mailnewsEnableMapi").checked;
}
function onOK()
{
try {
var mapiRegistry = Components.classes[ "@mozilla.org/mapiregistry;1" ].
getService( Components.interfaces.nsIMapiRegistry );
}
catch(ex){
mapiRegistry = null;
}
if (mapiRegistry &&
("mapiPref" in parent) &&
(mapiRegistry.isDefaultMailClient != parent.mapiPref.isDefaultMailClient)) {
if (parent.mapiPref.isDefaultMailClient)
mapiRegistry.setDefaultMailClient();
else
mapiRegistry.unsetDefaultMailClient();
}
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0"?>
<!--
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/
oftware 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 mozilla.org code.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 2001 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s):
Srilatha Moturi <srilatha@netscape.com>
-->
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd" >
%brandDTD;
<!ENTITY % prefMailnewsOverlayDTD SYSTEM "chrome://messenger-mapi/locale/pref-mailnewsOverlay.dtd" >
%prefMailnewsOverlayDTD;
]>
<overlay id="prefMailnewsOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript">
<![CDATA[
_elementIDs.push("mailnewsEnableMapi");
]]>
</script>
<script type="application/x-javascript" src="chrome://messenger-mapi/content/pref-mailnewsOverlay.js"/>
<hbox autostretch="never" id="mapi">
<checkbox id="mailnewsEnableMapi" label="&enableMapi.label;"
accesskey="&enableMapi.accesskey;"
preftype="bool" prefstring="mailnews.default_mail_client" prefattribute="checked"/>
</hbox>
</overlay>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<!-- list all the skins being supplied by this package -->
<RDF:Seq about="urn:mozilla:locale:root">
<RDF:li resource="urn:mozilla:locale:en-US"/>
</RDF:Seq>
<!-- locale information -->
<RDF:Description about="urn:mozilla:locale:en-US">
<chrome:packages>
<RDF:Seq about="urn:mozilla:locale:en-US:packages">
<RDF:li resource="urn:mozilla:locale:en-US:messenger-mapi"/>
</RDF:Seq>
</chrome:packages>
</RDF:Description>
<!-- Version Information. State that we work only with major version of this
package. -->
<RDF:Description about="urn:mozilla:locale:en-US:messenger-mapi"
chrome:localeVersion="0.9.7"/>
</RDF:RDF>

View File

@@ -0,0 +1,4 @@
en-US.jar:
locale/en-US/messenger-mapi/pref-mailnewsOverlay.dtd
locale/en-US/messenger-mapi/mapi.properties
locale/en-US/messenger-mapi/contents.rdf

View File

@@ -0,0 +1,40 @@
#!nmake
#
# 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.com>
#
DEPTH=..\..\..\..\..
CHROME_DIR=locales\en-US
CHROME_L10N_DIR=messenger\locale
CHROME_L10N = \
.\pref-mailnewsOverlay.dtd \
.\mapi.properties \
.\contents.rdf \
$(NULL)
include <$(DEPTH)\config\rules.mak>
chrome::
$(REGCHROME) locale en-US/messenger-mapi en-US.jar

View File

@@ -0,0 +1,23 @@
# Mail Integration Dialog
dialogTitle=%S Mail
dialogText=Do you want to use %S as the default mail application?
checkboxText=Do not display this dialog again
# MAPI Messages
loginText=Please enter your password for %S:
loginTextwithName=Please enter your username and password
loginTitle=%S Mail
PasswordTitle=%S Mail
# MAPI Error Messages
errorMessage=%S Mail could not be set as the default mail application because a registry key could not be updated. Verify with your system administrator that you have write access to your system registry, and then try again.
errorMessageTitle=%S Mail
# MAPI Security Messages
mapiBlindSendWarning=Another application is attempting to send mail using your user profile. Are you sure you want to send mail?
mapiBlindSendDontShowAgain=Warn me whenever other applications try to send mail from me
#Default Mail Display String
# localization note, $1%S is the app name, $2%S is the version
defaultMailDisplayTitle=%S %S Mail

View File

@@ -0,0 +1,3 @@
<!ENTITY enableMapiTitle.label "When sending mail from other applications">
<!ENTITY enableMapi.label "Use &vendorShortName; Mail as the default mail application.">
<!ENTITY enableMapi.accesskey "u">

View File

@@ -0,0 +1,28 @@
#!nmake
#
# 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.com>
#
DEPTH=..\..\..\..
DIRS=en-US
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,27 @@
#
# 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2001 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Srilatha Moturi <srilatha@netscape.com>
#
DEPTH=..\..\..
DIRS=content locale
include <$(DEPTH)\config\rules.mak>

View File

@@ -1,3 +0,0 @@
<FilesMatch ^(.*localconfig.*)$>
deny from all
</FilesMatch>

View File

@@ -1,44 +0,0 @@
===Litmus Installation Instructions===
First of all, let me convince you that you in fact probbaly do not want
to install Litmus. Litmus is not 1.0 software. Litmus is not even 0.5
software. In fact, Litmus doesn't really do any of the things you would
expect it to do yet.
In summary, if you're not looking to install Litmus because you are or
want to be a Litmus developer, you'd best turn around and go back from
whence you came.
If at any point you find that you don't understand these installation
instructions, it's a good sign you want to turn back as well.
Required Perl Modules:
Class::DBI
Class::DBI::mysql
Template
Time::Piece
Time::Piece::mysql
Time::Seconds
Date::Manip
HTML::StripScripts
HTML::StripScripts::Parser
Text::Markdown
XML::XPath
Once you've got everything installed, run: mysql < createdb.sql to
create the Litmus database.
Then edit Litmus/Config.pm to give it the information it needs to
connect to the database.
Run ./populatedb.pl to create products, testgroups, subgroups, etc...
There is no UI at present for doing this.
Edit the newly created 'localconfig' file and provide your database
configuration.
Then just pop the whole thing into a directory where your web server can
get at it. Have fun!
Note: After upgrading Litmus, it's a good idea to run populatedb.pl
again to pick up any schema changes that may have occured.

View File

@@ -1,109 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
# Max Kanat-Alexander <mkanat@bugzilla.org>
#
# ***** END LICENSE BLOCK *****
=cut
# Global object store and function library for Litmus
package Litmus;
use strict;
use Litmus::Template;
use Litmus::Config;
use Litmus::Error;
use Litmus::Auth;
use Litmus::CGI;
our $_request_cache = {};
# each cgi _MUST_ call Litmus->init() prior to doing anything else.
# init() ensures that the installation has not been disabled, deals with pending
# login requests, and other essential tasks.
sub init() {
if ($Litmus::Config::disabled) {
my $c = new CGI();
print $c->header();
print "Litmus has been shutdown by the administrator. Please try again later.";
exit;
}
# check for pending logins:
my $c = cgi();
if ($c->param("login_type")) {
Litmus::Auth::processLoginForm();
}
}
# Global Template object
sub template() {
my $class = shift;
request_cache()->{template} ||= Litmus::Template->create();
return request_cache()->{template};
}
# Global CGI object
sub cgi() {
my $class = shift;
request_cache()->{cgi} ||= new Litmus::CGI();
return request_cache()->{cgi};
}
sub getCurrentUser {
return Litmus::Auth::getCurrentUser();
}
# cache of global variables for a single request only
# use me like: Litmus->request_cache->{'var'} = 'foo';
# entries here are guarenteed to get flushed when the request ends,
# even when running under mod_perl
# from Bugzilla.pm:
sub request_cache {
if ($ENV{MOD_PERL}) {
my $request = Apache->request();
my $cache = $request->pnotes();
# Sometimes mod_perl doesn't properly call DESTROY on all
# the objects in pnotes(), so we register a cleanup handler
# to make sure that this happens.
if (!$cache->{cleanup_registered}) {
$request->push_handlers(PerlCleanupHandler => sub {
my $r = shift;
foreach my $key (keys %{$r->pnotes}) {
delete $r->pnotes->{$key};
}
});
$cache->{cleanup_registered} = 1;
}
return $cache;
}
return $_request_cache;
}
1;

View File

@@ -1,555 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Auth;
use strict;
# IMPORTANT!
## You _must_ call Litmus::Auth methods before sending a Content-type
## header so that any required cookies can be sent.
require Exporter;
use Litmus::Error;
use Time::Piece;
use Time::Seconds;
use Litmus::DB::User;
use CGI;
our @ISA = qw(Exporter);
our @EXPORT = qw();
my $logincookiename = $Litmus::Config::user_cookiename;
my $cookie_expire_days = 7;
# Given a username and password, validate the login. Returns the
# Litmus::DB::User object associated with the username if the login
# is sucuessful. Returns false otherwise.
sub validate_login($$) {
my $username = shift;
my $password = shift;
return 0 if (!$username or $username eq '' or
!$password or $password eq '');
my ($userobj) = Litmus::DB::User->search(email => $username);
if (!$userobj) {
return 0;
}
if (!$userobj->enabled() || $userobj->enabled() == 0) {
die "Account ".$userobj->username()." has been disabled by the administrator";
}
# for security reasons, we use the real (correct) crypt'd passwd
# as the salt:
my $realPasswordCrypted = $userobj->getRealPasswd();
return 0 if (!$realPasswordCrypted or $realPasswordCrypted eq '');
my $enteredPasswordCrypted = crypt($password, $realPasswordCrypted);
if ($enteredPasswordCrypted eq $realPasswordCrypted) {
return $userobj;
} else {
return 0;
}
}
# Used by a CGI when a login is required to proceed beyond a certain point.
# requireLogin() will return a Litmus::User object to indicate that the user
# is logged in, or it will redirect to a login page to allow the login to be
# completed. Once the login is complete, the user will be redirected back to
# $return_to and any parameters in the current CGI.pm object will be passed
# to the new script.
#
sub requireLogin {
my $return_to = shift;
my $admin_login_required = shift;
my $cgi = Litmus->cgi();
# see if we are already logged in:
my $user = getCurrentUser();
return $user if $user; # well, that was easy...
my $vars = {
title => "Login",
return_to => $return_to,
adminrequired => $admin_login_required,
params => $cgi,
};
print $cgi->header();
Litmus->template()->process("auth/login.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
}
# Used by a CGI in much the same way as requireLogin() when the user must
# be an admin to proceed.
sub requireAdmin {
my $return_to = shift;
my $cgi = Litmus->cgi();
my $user = requireLogin($return_to, 1);
if (!$user || !$user->is_admin()) {
print $cgi->header();
basicError("You must be a Litmus administrator to perform this function.");
}
return $user;
}
# Returns the current Litmus::DB::Session object corresponding to the current
# logged-in user, or 0 if no valid session exists
sub getCurrentSession() {
my $c = Litmus->cgi();
# we're actually processing the login form right now, so the cookie hasn't
# been sent yet...
if (Litmus->request_cache->{'curSession'}) {
return Litmus->request_cache->{'curSession'};
}
my $sessionCookie = $c->cookie($logincookiename);
if (! $sessionCookie) {
return 0
}
my @sessions = Litmus::DB::Session->search(sessioncookie => $sessionCookie);
my $session = $sessions[0];
if (! $session) { return 0 }
# see if it's still valid and that the user hasn't been disabled
if (! $session->isValid()) { return 0 }
return $session;
}
# Returns the Litmus::User object corresponding to the current logged-in
# user, or 0 if no valid login cookie exists
sub getCurrentUser() {
my $session = getCurrentSession();
if ($session) {
return $session->user_id();
} else {
return 0;
}
}
#
# ONLY NON-PUBLIC API BEYOND THIS POINT
#
# Processes data from a login form (auth/login.html.tmpl) using data
# from the current Litmus::CGI object in use. When complete, returns the
# flow of control to the script the user wanted to reach before the login,
# setting a login cookie for the user.
sub processLoginForm {
my $c = Litmus->cgi();
my $type = $c->param("login_type");
if ($c->param("accountCreated") &&
$c->param("accountCreated") eq "true") {
# make sure they really are logged in and didn't just set
# the accountCreated flag:
requireLogin("index.cgi");
return; # we're done here
}
if ($type eq "litmus") {
my $username = $c->param("email");
my $password = $c->param("password");
my $user = validate_login($username, $password);
if (!$user) {
loginError($c, "Username/Password incorrect. Please try again.");
}
my $session = makeSession($user);
$c->storeCookie(makeCookie($session));
} elsif ($type eq "newaccount") {
my $email = $c->param("email");
my $name = $c->param("realname");
my $password = $c->param("password");
my $nickname = $c->param("irc_nickname");
# some basic form-field validation:
my $emailregexp = q:^[\\w\\.\\+\\-=]+@[\\w\\.\\-]+\\.[\\w\\-]+$:;
if (! $email || ! $email =~ /$emailregexp/) {
loginError($c, "You must enter a valid email address");
}
if (! $password eq $c->param("password_confirm")) {
loginError($c, "Passwords do not match. Please try again.");
}
my @users = Litmus::DB::User->search(email => $email);
if ($users[0]) {
loginError($c, "User ".$users[0]->email() ." already exists.");
}
if ($nickname and $nickname ne '') {
@users = Litmus::DB::User->search(irc_nickname => $nickname);
if ($users[0]) {
loginError($c, "An account with that IRC nickname already exists.");
}
} else {
$nickname = undef;
}
my $userobj =
Litmus::DB::User->create({email => $email,
password => bz_crypt($password),
bugzilla_uid => 0,
realname => $name,
enabled => 1,
is_admin => 0,
irc_nickname => $nickname
});
my $session = makeSession($userobj);
$c->storeCookie(makeCookie($session));
my $vars = {
title => "Account Created",
email => $email,
realname => $name,
return_to => $c->param("login_loc"),
params => $c
};
print $c->header();
Litmus->template()->process("auth/accountcreated.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
} elsif ($type eq "bugzilla") {
my $username = $c->param("username");
my $password = $c->param("password");
} elsif ($type eq "convert") {
# convert an old-school Litmus account (pre authentication system)
# to a new one with a password:
my $username = $c->param("email");
my @userobjs = Litmus::DB::User->search(email => $username);
my $userobj = $userobjs[0];
if (! $userobj || $userobj->email() ne $username) {
loginError($c, "User $username does not exist.");
}
if ($userobj->password() ne "") {
# already a new-style account
loginError($c, "User $username has already been updated.");
}
# display a "convert login" form to get the rest of the information
print $c->header();
my $return_to = $c->param("login_loc") || "";
unsetFields();
my $vars = {
title => "Update Login",
email => $username,
return_to => $return_to,
params => $c,
};
Litmus->template()->process("auth/convertaccount.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
} elsif ($type eq "reallyconvert") {
my $username = $c->param("email");
my $realname = $c->param("realname");
my $password = $c->param("password");
my $password_confirm = $c->param("password_confirm");
my $nickname = $c->param("irc_nickname");
if (! $password eq $password_confirm) {
loginError($c, "Passwords do not match. Please try again.");
}
my @userobjs = Litmus::DB::User->search(email => $username);
my $userobj = $userobjs[0];
# just to be safe:
if (! $userobj || $userobj->email() ne $username) {
loginError($c, "User $username does not exist.");
}
if ($userobj->password() ne "" && ($userobj->bugzilla_uid() == 0 ||
!$userobj->bugzilla_uid())) {
# already a new-style account
loginError($c, "User $username has already been updated.");
}
my ($nickname_exists) =
Litmus::DB::User->search(irc_nickname => $nickname);
if ($nickname_exists) {
loginError($c,
"An account with that IRC nickname already exists.",
"auth/convertaccount.html.tmpl",
"Update Login");
}
# do the upgrade:
$userobj->password(bz_crypt($password));
$userobj->bugzilla_uid("0");
$userobj->realname($realname);
$userobj->enabled(1);
# $userobj->is_admin(0);
$userobj->irc_nickname($nickname);
$userobj->update();
my $session = makeSession($userobj);
$c->storeCookie(makeCookie($session));
my $vars = {
title => "Account Created",
email => $username,
realname => $realname,
return_to => $c->param("login_loc"),
params => $c
};
print $c->header();
Litmus->template()->process("auth/accountcreated.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit;
} else {
internalError("Unknown login scheme attempted");
}
}
sub changePassword {
my $userobj = shift;
my $password = shift;
$userobj->password(bz_crypt($password));
$userobj->update();
my @sessions = $userobj->sessions();
foreach my $session (@sessions) {
$session->makeExpire();
}
}
# Given a userobj, process the login and return a session object
sub makeSession {
my $userobj = shift;
my $c = Litmus->cgi();
my $expires = localtime() + ONE_DAY * $cookie_expire_days;
my $sessioncookie = randomToken(64);
my $session = Litmus::DB::Session->create({
user_id => $userobj,
sessioncookie => $sessioncookie,
expires => $expires});
Litmus->request_cache->{'curSession'} = $session;
return $session;
}
# Given a session, create a login cookie to go with it
sub makeCookie {
my $session = shift;
my $cookie = Litmus->cgi()->cookie(
-name => $logincookiename,
-value => $session->sessioncookie(),
-domain => $main::ENV{"HTTP_HOST"},
-expires => $session->expires(),
);
return $cookie;
}
sub loginError {
my $c = shift;
my $message = shift;
my $template = shift;
my $title = shift;
if (!$template) {
$template = "auth/login.html.tmpl";
}
if (!$title) {
$title = "Login";
}
print $c->header();
my $return_to = $c->param("login_loc") || "";
my $email = $c->param("email") || "";
unsetFields();
my $vars = {
title => $title,
return_to => $return_to,
email => $email,
params => $c,
onload => "toggleMessage('failure','$message')",
};
Litmus->template()->process($template, $vars) ||
internalError(Litmus->template()->error());
exit;
}
sub unsetFields() {
my $c = Litmus->cgi();
# We need to unset some params in $c since otherwise we end up with
# a hidden form field set for "email" and friends and madness results:
$c->param('email', '');
$c->param('username', '');
$c->param('login_type', '');
$c->param('login_loc', '');
$c->param('realname', '');
$c->param('password', '');
$c->param('password_confirm', '');
}
# Like crypt(), but with a random salt. Thanks to Bugzilla for this.
sub bz_crypt {
my ($password) = @_;
# The list of characters that can appear in a salt. Salts and hashes
# are both encoded as a sequence of characters from a set containing
# 64 characters, each one of which represents 6 bits of the salt/hash.
# The encoding is similar to BASE64, the difference being that the
# BASE64 plus sign (+) is replaced with a forward slash (/).
my @saltchars = (0..9, 'A'..'Z', 'a'..'z', '.', '/');
# Generate the salt. We use an 8 character (48 bit) salt for maximum
# security on systems whose crypt uses MD5. Systems with older
# versions of crypt will just use the first two characters of the salt.
my $salt = '';
for ( my $i=0 ; $i < 8 ; ++$i ) {
$salt .= $saltchars[rand(64)];
}
# Crypt the password.
my $cryptedpassword = crypt($password, $salt);
# Return the crypted password.
return $cryptedpassword;
}
sub randomToken {
my $size = shift || 10; # default to 10 chars if nothing specified
return join("", map{ ('0'..'9','a'..'z','A'..'Z')[rand 62] } (1..$size));
}
# Deprecated:
# DO NOT USE
sub setCookie {
my $user = shift;
my $expires = shift;
my $user_id = 0;
if ($user) {
$user_id = $user->user_id();
}
if (!$expires or $expires eq '') {
$expires = '+3d';
}
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $logincookiename,
-value => $user_id,
-domain => $main::ENV{"HTTP_HOST"},
-expires => $expires,
);
return $cookie;
}
# Deprecated:
sub getCookie() {
return getCurrentUser();
}
sub istrusted($) {
my $userobj = shift;
return 0 if (!$userobj);
if ($userobj->istrusted()) {
return 1;
} else {
return 0;
}
}
sub canEdit($) {
my $userobj = shift;
return $userobj->istrusted();
}
#########################################################################
# logout()
#
# Unset the user's cookie
#########################################################################
sub logout() {
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $logincookiename,
-value => '',
-domain => $main::ENV{"HTTP_HOST"},
-expires => '-1d'
);
$c->storeCookie($cookie);
# invalidate the session behind the cookie as well:
my $session = getCurrentSession();
if ($session) { $session->makeExpire() }
}
1;

View File

@@ -1,59 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::BugzillaDBI;
use strict;
use warnings;
use Litmus::Config;
use Litmus::Error;
use Memoize;
use base 'Litmus::DBI';
BEGIN {
unless ($Litmus::Config::bugzilla_auth_enabled) {
return 1;
}
}
my $dsn = "dbi:mysql:$Litmus::Config::bugzilla_db:$Litmus::Config::bugzilla_host";
Litmus::BugzillaDBI->set_db('Main',
$dsn,
$Litmus::Config::bugzilla_user,
$Litmus::Config::bugzilla_pass);
1;

View File

@@ -1,72 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::CGI;
use strict;
use base 'CGI';
# Subclass of CGI.pm that can store cookies in advance and output them
# later when the header() method is called. This feature should probably
# be submitted as a patch to CGI.pm itself.
sub new {
my $class = shift;
my @args = @_;
my $self = $class->SUPER::new(@args);
$self->{'litmusCookieStore'} = [];
return $self;
}
# Stores a cookie to be set later by the header() method
sub storeCookie {
my $self = shift;
my $cookie = shift;
# "we're like kids in a candy shop"
my @cookieStore = @{$self->{'litmusCookieStore'}};
push(@cookieStore, $cookie);
$self->{'litmusCookieStore'} = \@cookieStore;
}
sub header {
my $self = shift;
my @args = @_;
foreach my $cur ($self->{'litmusCookieStore'}) {
push(@args, {-cookie => $cur});
}
$self->SUPER::header(@args);
}
1;

View File

@@ -1,125 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Cache;
use strict;
use Litmus;
use Data::JavaScript;
use Litmus::DB::Product;
our @ISA = qw(Exporter);
@Litmus::Cache::EXPORT = qw(
rebuildCache
);
# generate a new litmusconfig.js file because something has updated:
sub rebuildCache {
unless (-e "data") { system("mkdir", "data") }
open(CACHE, ">data/litmusconfig.js.new");
print CACHE "// Litmus configuration information\n";
print CACHE "// Do not edit this file directly. It is autogenerated from the database\n";
print CACHE "\n";
# we build up @litmusconfig, a big perl data structure, and spit the
# whole thing out as javascript with Data::JavaScript
# shield your eyes, we're in for a long trip
my @litmusconfig;
my @products = Litmus::DB::Product->search(enabled => 1);
my $prodcount = 0;
foreach my $curproduct (@products) {
my $prodrow = \%{$litmusconfig[$prodcount]};
$prodrow->{"name"} = $curproduct->name();
$prodrow->{"id"} = $curproduct->product_id();
my $brancharray = \@{$prodrow->{"branches"}};
my $branchcount = 0;
foreach my $curbranch ($curproduct->branches(enabled => 1)) {
my $branchrow = \%{$brancharray->[$branchcount]};
$branchrow->{"name"} = $curbranch->name();
$branchrow->{"id"} = $curbranch->branch_id();
$branchcount++;
}
my $platformarray = \@{$prodrow->{"platforms"}};
my $platformcount = 0;
foreach my $curplat (Litmus::DB::Platform->search_ByProduct($curproduct->product_id())) {
my $platrow = \%{$platformarray->[$platformcount]};
$platrow->{"name"} = $curplat->name();
$platrow->{"id"} = $curplat->platform_id();
my $opsysarray = \@{$platrow->{"opsyses"}};
my $opsyscount = 0;
foreach my $curopsys ($curplat->opsyses()) {
my $opsysrow = \%{$opsysarray->[$opsyscount]};
$opsysrow->{"name"} = $curopsys->name();
$opsysrow->{"id"} = $curopsys->opsys_id();
$opsyscount++;
}
$platformcount++;
}
my $grouparray = \@{$prodrow->{"testgroups"}};
my $groupcount = 0;
foreach my $curgroup ($curproduct->testgroups()) {
next if (!$curgroup->enabled);
my $grouprow = \%{$grouparray->[$groupcount]};
$grouprow->{"name"} = $curgroup->name();
$grouprow->{"id"} = $curgroup->testgroup_id();
$groupcount++;
my $subgrouparray = \@{$grouprow->{"subgroups"}};
my $subgroupcount = 0;
foreach my $cursubgroup (Litmus::DB::Subgroup->search_EnabledByTestgroup($curgroup->testgroup_id())) {
next if (!$cursubgroup->enabled);
my $subgrouprow = \%{$subgrouparray->[$subgroupcount]};
$subgrouprow->{"name"} = $cursubgroup->name();
$subgrouprow->{"id"} = $cursubgroup->subgroup_id();
$subgroupcount++;
}
}
$prodcount++;
}
my $data = jsdump('litmusconfig', \@litmusconfig);
$data =~ s/new Object;/new Array\(\);/g;
print CACHE $data;
close(CACHE);
system("mv", "data/litmusconfig.js.new", "data/litmusconfig.js");
#system("chmod", "-R", "755", "data/");
}
1;

View File

@@ -1,49 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Config;
use strict;
do 'localconfig';
our $version = "0.6";
# if true, then Litmus will not accept any requests
our $disabled = 0;
our $datadir = "data/";
# Set/unset this to display inline debugging value/code.
our $DEBUG = 0;
1;

View File

@@ -1,48 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Branch;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Branch->table('branches');
Litmus::DB::Branch->columns(All => qw/branch_id product_id name detect_regexp enabled/);
Litmus::DB::Branch->columns(Essential => qw/branch_id product_id name detect_regexp enabled/);
Litmus::DB::Branch->column_alias("product_id", "product");
Litmus::DB::Branch->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::Branch->has_a(product => "Litmus::DB::Product");
1;

View File

@@ -1,44 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::BugzillaUser;
use strict;
use base 'Litmus::BugzillaDBI';
Litmus::DB::BugzillaUser->table('profiles');
Litmus::DB::BugzillaUser->columns(All => qw/userid login_name cryptpassword realname
disabledtext mybugslink refreshed_when extern_id/);
1;

View File

@@ -1,44 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::BuildType;
use strict;
use base 'Litmus::DBI';
Litmus::DB::BuildType->table('build_type_lookup');
Litmus::DB::BuildType->columns(All => qw/build_type_id name/);
Litmus::DB::BuildType->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,53 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Comment;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
Litmus::DB::Comment->table('test_result_comments');
Litmus::DB::Comment->columns(All => qw/comment_id test_result_id last_updated submission_time user_id comment/);
Litmus::DB::Comment->column_alias("test_result_id", "test_result");
Litmus::DB::Comment->column_alias("user_id", "user");
Litmus::DB::Comment->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::Comment->has_a(user => "Litmus::DB::User");
Litmus::DB::Comment->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,44 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::ExitStatus;
use strict;
use base 'Litmus::DBI';
Litmus::DB::ExitStatus->table('exit_status_lookup');
Litmus::DB::ExitStatus->columns(All => qw/exit_status_id name/);
Litmus::DB::ExitStatus->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,46 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Format;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Format->table('test_format_lookup');
Litmus::DB::Format->columns(All => qw/format_id name/);
Litmus::DB::Format->column_alias("format_id", "formatid");
Litmus::DB::Format->has_many(testcases => "Litmus::DB::Testcase");
1;

View File

@@ -1,52 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Locale;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Locale->table('locale_lookup');
Litmus::DB::Locale->columns(All => qw/abbrev name/);
Litmus::DB::Locale->column_alias("abbrev", "locale");
Litmus::DB::Locale->has_many(test_results => "Litmus::DB::Testresult");
__PACKAGE__->set_sql(RetrieveAll => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
ORDER BY abbrev ASC
});
1;

View File

@@ -1,50 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Log;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Log->table('test_result_logs');
Litmus::DB::Log->columns(All => qw/log_id last_updated submission_time log_type_id log_text/);
Litmus::DB::Log->column_alias("test_results", "testresults");
Litmus::DB::Log->column_alias("log_type_id", "log_type");
Litmus::DB::Log->has_a(log_type => "Litmus::DB::LogType");
Litmus::DB::Log->has_many(test_results => ["Litmus::DB::LogTestresult" => 'test_result']);
Litmus::DB::Testresult->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,47 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::LogTestresult;
use strict;
use base 'Litmus::DBI';
Litmus::DB::LogTestresult->table('testresult_logs_join');
Litmus::DB::LogTestresult->columns(Primary => qw/test_result_id log_id/);
Litmus::DB::LogTestresult->column_alias("test_result_id", "test_result");
Litmus::DB::LogTestresult->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::LogTestresult->has_a(log_id => "Litmus::DB::Log");
1;

View File

@@ -1,44 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::LogType;
use strict;
use base 'Litmus::DBI';
Litmus::DB::LogType->table('log_type_lookup');
Litmus::DB::LogType->columns(All => qw/log_type_id name/);
Litmus::DB::LogType->has_many(test_result_logs => "Litmus::DB::Log");
1;

View File

@@ -1,48 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Opsys;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Opsys->table('opsyses');
Litmus::DB::Opsys->columns(All => qw/opsys_id platform_id name detect_regexp/);
Litmus::DB::Opsys->columns(Essential => qw/opsys_id platform_id name detect_regexp/);
Litmus::DB::Opsys->column_alias("platform_id", "platform");
Litmus::DB::Opsys->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::Opsys->has_a(platform => "Litmus::DB::Platform");
1;

View File

@@ -1,105 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Platform;
use strict;
use base 'Litmus::DBI';
use CGI;
Litmus::DB::Platform->table('platforms');
Litmus::DB::Platform->columns(All => qw/platform_id name detect_regexp iconpath/);
Litmus::DB::Platform->columns(Essential => qw/platform_id name detect_regexp iconpath/);
Litmus::DB::Platform->column_alias("platform_id", "platformid");
Litmus::DB::Platform->has_many(opsyses => "Litmus::DB::Opsys");
Litmus::DB::Platform->set_sql(ByProduct => qq{
SELECT pl.*
FROM platforms pl, platform_products plpr
WHERE plpr.product_id=? AND plpr.platform_id=pl.platform_id
});
Litmus::DB::Platform->set_sql(ByProductAndName => qq{
SELECT pl.*
FROM platforms pl, platform_products plpr
WHERE plpr.product_id=? AND plpr.platform_id=pl.platform_id
AND pl.name=?
});
#########################################################################
sub delete_from_products() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from platform_products WHERE platform_id=?";
my $rows = $dbh->do($sql,
undef,
$self->platform_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_products();
# XXX: How to handle opsyses?
return $self->delete;
}
#########################################################################
sub update_products() {
my $self = shift;
my $new_product_ids = shift;
if (scalar @$new_product_ids) {
# Failing to delete products is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_products();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO platform_products (platform_id,product_id) VALUES (?,?)";
foreach my $new_product_id (@$new_product_ids) {
my $rows = $dbh->do($sql,
undef,
$self->platform_id,
$new_product_id
);
}
}
}
1;

View File

@@ -1,108 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Product;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Product->table('products');
Litmus::DB::Product->columns(All => qw/product_id name iconpath enabled/);
Litmus::DB::Product->columns(Essential => qw/product_id name iconpath enabled/);
Litmus::DB::Product->column_alias("product_id", "productid");
Litmus::DB::Product->has_many(testcases => "Litmus::DB::Testcase",
{ order_by => 'testcase_id' });
Litmus::DB::Product->has_many(subgroups => "Litmus::DB::Subgroup",
{ order_by => 'name' });
Litmus::DB::Product->has_many(testgroups => "Litmus::DB::Testgroup",
{ order_by => 'name' });
Litmus::DB::Product->has_many(branches => "Litmus::DB::Branch",
{ order_by => 'name' });
__PACKAGE__->set_sql(ByPlatform => qq{
SELECT pr.*
FROM products pr, platform_products plpr
WHERE plpr.platform_id=? AND plpr.product_id=pr.product_id
ORDER BY pr.name ASC
});
#########################################################################
sub delete_from_platforms() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from platform_products WHERE product_id=?";
my $rows = $dbh->do($sql,
undef,
$self->product_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_platforms();
my $dbh = __PACKAGE__->db_Main();
my $sql = "UPDATE testgroups SET product_id=0,enabled=0 WHERE product_id=?";
my $rows = $dbh->do($sql,
undef,
$self->product_id
);
# Remove references to product in other entities.
# Disable those entities for good measure.
$sql = "UPDATE subgroups SET product_id=0,enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
$sql = "UPDATE testcases SET product_id=0,enabled=0,community_enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
$sql = "UPDATE branches SET product_id=0,enabled=0 WHERE product_id=?";
$rows = $dbh->do($sql,
undef,
$self->product_id
);
return $self->delete;
}
1;

View File

@@ -1,44 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::ResultStatus;
use strict;
use base 'Litmus::DBI';
Litmus::DB::ResultStatus->table('test_result_status_lookup');
Litmus::DB::ResultStatus->columns(All => qw/result_status_id name class_name/);
Litmus::DB::ResultStatus->has_many(test_results => "Litmus::DB::Testresult");
1;

View File

@@ -1,54 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Resultbug;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
Litmus::DB::Resultbug->table('test_result_bugs');
Litmus::DB::Resultbug->columns(Primary => qw/test_result_id bug_id/);
Litmus::DB::Resultbug->columns(All => qw/last_updated submission_time user_id/);
Litmus::DB::Resultbug->column_alias("test_result_id", "test_result");
Litmus::DB::Resultbug->column_alias("test_result_id", "testresult");
Litmus::DB::Resultbug->column_alias("user_id", "user");
Litmus::DB::Resultbug->has_a(test_result => "Litmus::DB::Testresult");
Litmus::DB::Resultbug->has_a(user => "Litmus::DB::User");
Litmus::DB::Resultbug->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,69 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Session;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
Litmus::DB::Session->table('sessions');
Litmus::DB::Session->columns(All => qw/session_id user_id sessioncookie expires/);
Litmus::DB::Session->has_a(user_id => "Litmus::DB::User");
Litmus::DB::Session->autoinflate(dates => 'Time::Piece');
# expire the current Session object
sub makeExpire {
my $self = shift;
$self->delete();
}
sub isValid {
my $self = shift;
if ($self->expires() <= localtime()) {
$self->makeExpire();
return 0;
}
if (!$self->user_id()->enabled() || $self->user_id()->enabled() == 0) {
$self->makeExpire();
return 0;
}
return 1;
}
1;

View File

@@ -1,306 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Subgroup;
use strict;
use base 'Litmus::DBI';
use Time::Piece::MySQL;
#use Litmus::DB::Testresult;
Litmus::DB::Subgroup->table('subgroups');
Litmus::DB::Subgroup->columns(All => qw/subgroup_id name testrunner_group_id enabled product_id/);
Litmus::DB::Subgroup->columns(Essential => qw/subgroup_id name testrunner_group_id enabled product_id/);
Litmus::DB::Subgroup->column_alias("subgroup_id", "subgroupid");
Litmus::DB::Subgroup->has_a(product => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledByTestgroup => qq{
SELECT sg.*
FROM subgroups sg, subgroup_testgroups sgtg
WHERE sgtg.testgroup_id=? AND sgtg.subgroup_id=sg.subgroup_id AND sg.enabled=1
ORDER BY sgtg.sort_order ASC
});
__PACKAGE__->set_sql(ByTestgroup => qq{
SELECT sg.*
FROM subgroups sg, subgroup_testgroups sgtg
WHERE sgtg.testgroup_id=? AND sgtg.subgroup_id=sg.subgroup_id
ORDER BY sgtg.sort_order ASC
});
__PACKAGE__->set_sql(NumEnabledTestcases => qq{
SELECT count(tc.testcase_id) as num_testcases
FROM testcases tc, testcase_subgroups tcsg
WHERE tcsg.subgroup_id=? AND tcsg.testcase_id=tc.testcase_id AND tc.enabled=1 AND tc.community_enabled=1
});
__PACKAGE__->set_sql(EnabledByTestcase => qq{
SELECT sg.*
FROM subgroups sg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sg.subgroup_id AND sg.enabled=1
ORDER by sg.name ASC
});
__PACKAGE__->set_sql(ByTestcase => qq{
SELECT sg.*
FROM subgroups sg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sg.subgroup_id
ORDER by sg.name ASC
});
#########################################################################
sub coverage() {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $community_only = shift;
my $user = shift;
my $sql = "SELECT COUNT(t.testcase_id) FROM testcase_subgroups tsg, testcases t WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1";
if ($community_only) {
$sql .= " AND t.community_enabled=1";
}
my $dbh = $self->db_Main();
my $sth = $dbh->prepare_cached($sql);
$sth->execute(
$self->{'subgroup_id'},
);
my ($num_testcases) = $sth->fetchrow_array;
$sth->finish;
if (!$num_testcases or
$num_testcases == 0) { return "N/A" }
$sql = "SELECT t.testcase_id, count(tr.testresult_id) AS num_results
FROM testcase_subgroups tsg JOIN testcases t ON (tsg.testcase_id=t.testcase_id) LEFT JOIN test_results tr ON (tr.testcase_id=t.testcase_id) JOIN opsyses o ON (tr.opsys_id=o.opsys_id)
WHERE tsg.subgroup_id=? AND tr.build_id=? AND tr.locale_abbrev=? AND o.platform_id=?";
if ($community_only) {
$sql .= " AND t.community_enabled=1";
}
if ($user) {
$sql .= " AND tr.user_id=" . $user->{'user_id'};
}
$sql .= " GROUP BY tr.testcase_id";
$sth = $dbh->prepare_cached($sql);
$sth->execute(
$self->{'subgroup_id'},
$build_id,
$locale,
$platform->{'platform_id'}
);
my @test_results = $self->sth_to_objects($sth);
$sth->finish;
if (@test_results == 0) { return "0" }
my $num_completed = 0;
foreach my $curtest (@test_results) {
if ($curtest->{'num_results'} > 0) {
$num_completed++;
}
}
my $result = $num_completed/($num_testcases) * 100;
unless ($result) {
return "0";
}
return sprintf("%d",$result);
}
#########################################################################
sub clone() {
my $self = shift;
my $new_subgroup = $self->copy;
if (!$new_subgroup) {
return undef;
}
# Propagate testgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) SELECT ?,testgroup_id,sort_order FROM subgroup_testgroups WHERE subgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$new_subgroup->subgroup_id,
$self->subgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
# What happens when we clone a subgroup that doesn't belong to
# any testgroups?
}
$sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) SELECT testcase_id,?,sort_order FROM testcase_subgroups WHERE subgroup_id=?";
$rows = $dbh->do($sql,
undef,
$new_subgroup->subgroup_id,
$self->subgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_subgroup;
}
#########################################################################
sub delete_from_testgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE subgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id
);
}
#########################################################################
sub delete_from_testgroup() {
my $self = shift;
my $testgroup_id = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE subgroup_id=? AND testgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id,
$testgroup_id
);
}
#########################################################################
sub delete_from_testcases() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE subgroup_id=?";
return $dbh->do($sql,
undef,
$self->subgroup_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_testgroups();
$self->delete_from_testcases();
return $self->delete;
}
#########################################################################
sub update_testgroups() {
my $self = shift;
my $new_testgroup_ids = shift;
if (scalar @$new_testgroup_ids) {
# Failing to delete testgroups is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_testgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,1)";
foreach my $new_testgroup_id (@$new_testgroup_ids) {
my $rows = $dbh->do($sql,
undef,
$self->subgroup_id,
$new_testgroup_id
);
}
}
}
#########################################################################
sub update_testgroup() {
my $self = shift;
my $testgroup_id = shift;
my $sort_order = shift;
# Sort order defaults to 1.
if (!$sort_order) {
$sort_order = 1;
}
my $rv = $self->delete_from_testgroup($testgroup_id);
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,?)";
return $dbh->do($sql,
undef,
$self->subgroup_id,
$testgroup_id,
$sort_order
);
}
#########################################################################
sub update_testcases() {
my $self = shift;
my $new_testcase_ids = shift;
if (scalar @$new_testcase_ids) {
# Failing to delete testcases is _not_ fatal when adding a new subgroup.
my $rv = $self->delete_from_testcases();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,?)";
my $sort_order = 1;
foreach my $new_testcase_id (@$new_testcase_ids) {
next if (!$new_testcase_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$new_testcase_id,
$self->subgroup_id,
$sort_order
);
};
if ($@) {
print STDERR $@;
}
$sort_order++;
}
}
}
1;

View File

@@ -1,61 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::TestRun;
use strict;
use base 'Litmus::DBI';
use Time::Piece;
use Time::Seconds;
Litmus::DB::TestRun->table('test_runs');
Litmus::DB::TestRun->columns(All => qw/test_run_id testgroup_id name description start_timestamp finish_timestamp enabled/);
Litmus::DB::TestRun->column_alias("testgroup_id", "testgroup");
Litmus::DB::TestRun->has_a(testgroup => "Litmus::DB::Testgroup");
Litmus::DB::TestRun->has_many(subgroups =>
[ "Litmus::DB::SubgroupTestgroup" => "testgroup" ]);
Litmus::DB::TestRun->autoinflate(dates => 'Time::Piece');
1;

View File

@@ -1,377 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testcase;
use strict;
use base 'Litmus::DBI';
use Date::Manip;
#use Litmus::DB::Testresult;
use Memoize;
#use Litmus::Error;
our $default_relevance_threshold = 1.0;
our $default_match_limit = 25;
our $default_num_days = 7;
Litmus::DB::Testcase->table('testcases');
Litmus::DB::Testcase->columns(Primary => qw/testcase_id/);
Litmus::DB::Testcase->columns(Essential => qw/summary details enabled community_enabled format_id regression_bug_id product_id steps expected_results author_id creation_date last_updated version testrunner_case_id testrunner_case_version/);
Litmus::DB::Testcase->column_alias("testcase_id", "testid");
Litmus::DB::Testcase->column_alias("testcase_id", "test_id");
Litmus::DB::Testcase->column_alias("testcase_id", "id");
Litmus::DB::Testcase->column_alias("community_enabled", "communityenabled");
Litmus::DB::Testcase->column_alias("format_id", "format");
Litmus::DB::Testcase->column_alias("author_id", "author");
Litmus::DB::Testcase->column_alias("product_id", "product");
Litmus::DB::Testcase->has_a("format" => "Litmus::DB::Format");
Litmus::DB::Testcase->has_a("author" => "Litmus::DB::User");
Litmus::DB::Testcase->has_a("product" => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(BySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE
tsg.subgroup_id=? AND
tsg.testcase_id=t.testcase_id
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(ByTestgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg, subgroup_testgroups sgtg
WHERE
tsg.testcase_id=t.testcase_id AND
tsg.subgroup_id=sgtg.subgroup_id AND
sgtg.testgroup_id = ?
ORDER BY tsg.sort_order ASC
});
__PACKAGE__->set_sql(CommunityEnabledBySubgroup => qq{
SELECT t.*
FROM testcases t, testcase_subgroups tsg
WHERE tsg.subgroup_id=? AND tsg.testcase_id=t.testcase_id AND t.enabled=1 AND t.community_enabled=1
ORDER BY tsg.sort_order ASC, t.testcase_id ASC
});
Litmus::DB::Testcase->has_many(test_results => "Litmus::DB::Testresult", {order_by => 'submission_time DESC'});
Litmus::DB::Testcase->has_many(subgroups =>
["Litmus::DB::TestcaseSubgroup" => 'subgroup']);
#########################################################################
# is_completed($$$$$)
#
# Check whether we have test results for the current test that correspond
# to the provided platform, build_id, and user(optional).
#########################################################################
memoize('is_completed');
sub is_completed {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $user = shift; # optional
my @results;
if ($user) {
@results = Litmus::DB::Testresult->search_CompletedByUser(
$self->{'testcase_id'},
$build_id,
$locale->{'abbrev'},
$platform->{'platform_id'},
$user->{'user_id'},
);
} else {
@results = Litmus::DB::Testresult->search_Completed(
$self->{'testcase_id'},
$build_id,
$locale->{'abbrev'},
$platform->{'platform_id'},
);
}
return @results;
}
#########################################################################
sub getFullTextMatches() {
my $self = shift;
my $text_snippet = shift;
my $match_limit = shift;
my $relevance_threshold = shift;
if (!$match_limit) {
$match_limit = $default_match_limit;
}
if (!$relevance_threshold) {
$relevance_threshold = $default_relevance_threshold
}
__PACKAGE__->set_sql(FullTextMatches => qq{
SELECT testcase_id, summary, creation_date, last_updated, MATCH (summary,steps,expected_results) AGAINST (?) AS relevance
FROM testcases
WHERE MATCH (summary,steps,expected_results) AGAINST (?) HAVING relevance > ?
ORDER BY relevance DESC, summary ASC
LIMIT $match_limit
});
return $self->search_FullTextMatches(
$text_snippet,
$text_snippet,
$relevance_threshold
);
}
#########################################################################
sub getNewTestcases() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(NewTestcases => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE creation_date>=?
ORDER BY creation_date DESC
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_NewTestcases($new_datestamp);
}
#########################################################################
sub getRecentlyUpdated() {
my $self = shift;
my $num_days = shift;
my $match_limit = shift;
if (!$num_days) {
$num_days = $default_num_days;
}
if (!$match_limit) {
$match_limit = $default_match_limit;
}
__PACKAGE__->set_sql(RecentlyUpdated => qq{
SELECT testcase_id, summary, creation_date, last_updated
FROM testcases
WHERE last_updated>=? AND last_updated>creation_date
ORDER BY last_updated DESC
LIMIT $match_limit
});
my $err;
my $new_datestamp=&UnixDate(DateCalc("now","- $num_days days"),"%q");
return $self->search_RecentlyUpdated($new_datestamp);
}
#########################################################################
sub getDefaultMatchLimit() {
return $default_match_limit;
}
#########################################################################
sub getDefaultRelevanceThreshold() {
return $default_relevance_threshold;
}
#########################################################################
sub getDefaultNumDays() {
return $default_num_days;
}
#########################################################################
sub clone() {
my $self = shift;
my $new_testcase = $self->copy;
if (!$new_testcase) {
return undef;
}
# Update dates to now.
my $now = &UnixDate("today","%q");
$new_testcase->creation_date($now);
$new_testcase->last_updated($now);
$new_testcase->update();
# Propagate subgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) SELECT ?,subgroup_id,sort_order FROM testcase_subgroups WHERE testcase_id=?";
my $rows = $dbh->do($sql,
undef,
$new_testcase->testcase_id,
$self->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
# What happens when we clone a testcase that doesn't belong to
# any subgroups?
}
$sql = "INSERT INTO related_testcases (testcase_id, related_testcase_id) VALUES (?,?)";
$rows = $dbh->do($sql,
undef,
$self->testcase_id,
$new_testcase->testcase_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_testcase;
}
#########################################################################
sub delete_from_subgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE testcase_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id
);
}
#########################################################################
sub delete_from_subgroup() {
my $self = shift;
my $subgroup_id = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from testcase_subgroups WHERE testcase_id=? AND subgroup_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id,
$subgroup_id
);
}
#########################################################################
sub delete_from_related() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from related_testcases WHERE testcase_id=? OR related_testcase_id=?";
return $dbh->do($sql,
undef,
$self->testcase_id,
$self->testcase_id
);
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_subgroups();
$self->delete_from_related();
return $self->delete;
}
#########################################################################
sub update_subgroups() {
my $self = shift;
my $new_subgroup_ids = shift;
if (scalar @$new_subgroup_ids) {
# Failing to delete subgroups is _not_ fatal when adding a new testcase.
my $rv = $self->delete_from_subgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,1)";
foreach my $new_subgroup_id (@$new_subgroup_ids) {
my $rows = $dbh->do($sql,
undef,
$self->testcase_id,
$new_subgroup_id
);
}
}
}
#########################################################################
sub update_subgroup() {
my $self = shift;
my $subgroup_id = shift;
my $sort_order = shift;
# Sort order defaults to 1.
if (!$sort_order) {
$sort_order = 1;
}
my $rv = $self->delete_from_subgroup($subgroup_id);
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testcase_subgroups (testcase_id,subgroup_id,sort_order) VALUES (?,?,?)";
return $dbh->do($sql,
undef,
$self->testcase_id,
$subgroup_id,
$sort_order
);
}
1;

View File

@@ -1,49 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::TestcaseSubgroup;
use strict;
use base 'Litmus::DBI';
Litmus::DB::TestcaseSubgroup->table('testcase_subgroups');
Litmus::DB::TestcaseSubgroup->columns(All => qw/testcase_id subgroup_id/);
Litmus::DB::TestcaseSubgroup->has_a(testcase_id => "Litmus::DB::Testcase");
Litmus::DB::TestcaseSubgroup->has_a(subgroup_id => "Litmus::DB::Subgroup");
Litmus::DB::TestcaseSubgroup->column_alias("testcase_id", "testcase");
Litmus::DB::TestcaseSubgroup->column_alias("testcase_id", "test");
Litmus::DB::TestcaseSubgroup->column_alias("subgroup_id", "subgroup");
1;

View File

@@ -1,260 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testgroup;
use strict;
use base 'Litmus::DBI';
Litmus::DB::Testgroup->table('testgroups');
Litmus::DB::Testgroup->columns(All => qw/testgroup_id product_id name enabled testrunner_plan_id/);
Litmus::DB::Testgroup->columns(Essential => qw/testgroup_id product_id name enabled testrunner_plan_id/);
Litmus::DB::Testgroup->column_alias("product_id", "product");
Litmus::DB::Testgroup->has_a(product => "Litmus::DB::Product");
__PACKAGE__->set_sql(EnabledByBranch => qq{
SELECT tg.*
FROM testgroups tg, testgroup_branches tgb
WHERE tgb.branch_id=? AND tgb.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(ByBranch => qq{
SELECT tg.*
FROM testgroups tg, testgroup_branches tgb
WHERE tgb.branch_id=? AND tgb.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
__PACKAGE__->set_sql(EnabledBySubgroup => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg
WHERE sgtg.subgroup_id=? AND sgtg.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(BySubgroup => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg
WHERE sgtg.subgroup_id=? AND sgtg.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
__PACKAGE__->set_sql(EnabledByTestcase => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tg.enabled=1 ORDER by tg.name ASC
});
__PACKAGE__->set_sql(ByTestcase => qq{
SELECT tg.*
FROM testgroups tg, subgroup_testgroups sgtg, testcase_subgroups tcsg
WHERE tcsg.testcase_id=? AND tcsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id ORDER by tg.name ASC
});
#########################################################################
sub coverage {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $locale = shift;
my $community_only = shift;
my $user = shift;
my $percent_completed = 0;
my @subgroups = Litmus::DB::Subgroup->search_EnabledByTestgroup($self->testgroup_id);
my $num_empty_subgroups = 0;
foreach my $subgroup (@subgroups) {
my $subgroup_percent = $subgroup->coverage(
$platform,
$build_id,
$locale,
$community_only,
$user,
);
if ($subgroup_percent eq "N/A") {
$num_empty_subgroups++;
} else {
$percent_completed += $subgroup_percent;
}
}
if (scalar(@subgroups) - $num_empty_subgroups == 0) {
return "N/A"
}
my $total_percentage = $percent_completed /
(scalar @subgroups - $num_empty_subgroups);
return sprintf("%d",$total_percentage);
}
#########################################################################
sub clone() {
my $self = shift;
my $new_testgroup = $self->copy;
if (!$new_testgroup) {
return undef;
}
# Propagate testgroup membership;
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) SELECT subgroup_id,?,sort_order FROM subgroup_testgroups WHERE testgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$new_testgroup->testgroup_id,
$self->testgroup_id
);
if (! $rows) {
# XXX: Do we need to throw a warning here?
}
return $new_testgroup;
}
#########################################################################
sub delete_from_subgroups() {
my $self = shift;
my $dbh = __PACKAGE__->db_Main();
my $sql = "DELETE from subgroup_testgroups WHERE testgroup_id=?";
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id
);
}
#########################################################################
sub delete_from_test_runs() {
my $self = shift;
# XXX: Placeholder for test runs.
return;
}
#########################################################################
sub delete_with_refs() {
my $self = shift;
$self->delete_from_subgroups();
$self->delete_from_test_runs();
return $self->delete;
}
#########################################################################
sub update_subgroups() {
my $self = shift;
my $new_subgroup_ids = shift;
if (scalar @$new_subgroup_ids) {
# Failing to delete subgroups is _not_ fatal when adding a new testgroup.
my $rv = $self->delete_from_subgroups();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO subgroup_testgroups (subgroup_id,testgroup_id,sort_order) VALUES (?,?,?)";
my $sort_order = 1;
foreach my $new_subgroup_id (@$new_subgroup_ids) {
next if (!$new_subgroup_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$new_subgroup_id,
$self->testgroup_id,
$sort_order
);
};
if ($@) {
print STDERR $@;
}
$sort_order++;
}
}
}
#########################################################################
sub update_branches() {
my $self = shift;
my $new_branch_ids = shift;
if (scalar @$new_branch_ids) {
# Failing to delete branches is _not_ fatal when adding a new testgroup.
my $rv = $self->delete_from_branches();
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testgroup_branches (testgroup_id,branch_id) VALUES (?,?)";
foreach my $new_branch_id (@$new_branch_ids) {
next if (!$new_branch_id);
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id,
$new_branch_id,
);
};
if ($@) {
print STDERR $@;
}
}
}
}
#########################################################################
sub add_branch() {
my $self = shift;
my $new_branch_id = shift;
# Failure to insert isn't fatal in the case of a collision, but we do want
# to log it.
my $dbh = __PACKAGE__->db_Main();
my $sql = "INSERT INTO testgroup_branches (testgroup_id,branch_id) VALUES (?,?)";
# Log any failures/duplicate keys to STDERR.
eval {
my $rows = $dbh->do($sql,
undef,
$self->testgroup_id,
$new_branch_id,
);
};
if ($@) {
print STDERR $@;
}
}
1;

View File

@@ -1,390 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::Testresult;
use strict;
use base 'Litmus::DBI';
use Date::Manip;
use Time::Piece;
use Time::Seconds;
use Memoize;
our $_num_results_default = 15;
Litmus::DB::Testresult->table('test_results');
Litmus::DB::Testresult->columns(All => qw/testresult_id testcase_id last_updated submission_time user_id opsys_id branch_id build_id user_agent result_status_id build_type_id machine_name exit_status_id duration_ms talkback_id valid vetted validated_by_user_id vetted_by_user_id validated_timestamp vetted_timestamp locale_abbrev is_automated_result/);
Litmus::DB::Testresult->column_alias("testcase_id", "testcase");
Litmus::DB::Testresult->column_alias("submission_time", "timestamp");
Litmus::DB::Testresult->column_alias("user_id", "user");
Litmus::DB::Testresult->column_alias("opsys_id", "opsys");
Litmus::DB::Testresult->column_alias("branch_id", "branch");
Litmus::DB::Testresult->column_alias("user_agent", "useragent");
Litmus::DB::Testresult->column_alias("result_status_id", "result_status");
Litmus::DB::Testresult->column_alias("build_type_id", "build_type");
Litmus::DB::Testresult->column_alias("exit_status_id", "exit_status");
Litmus::DB::Testresult->column_alias("validity_id", "validity");
Litmus::DB::Testresult->column_alias("vetting_status_id", "vetting_status");
Litmus::DB::Testresult->column_alias("locale_abbrev", "locale");
Litmus::DB::Testresult->column_alias("is_automated_result", "isAutomated");
Litmus::DB::Testresult->has_a(opsys => "Litmus::DB::Opsys");
Litmus::DB::Testresult->has_a(branch => "Litmus::DB::Branch");
Litmus::DB::Testresult->has_a(testcase => "Litmus::DB::Testcase");
Litmus::DB::Testresult->has_a(result_status => "Litmus::DB::ResultStatus");
Litmus::DB::Testresult->has_a(user => "Litmus::DB::User");
Litmus::DB::Testresult->has_a(useragent => "Litmus::UserAgentDetect");
Litmus::DB::Testresult->has_a(build_type => "Litmus::DB::BuildType");
Litmus::DB::Testresult->has_a(exit_status => "Litmus::DB::ExitStatus");
Litmus::DB::Testresult->has_a(locale => "Litmus::DB::Locale");
Litmus::DB::Testresult->has_a(platform =>
[ "Litmus::DB::Opsys" => "platform" ]);
Litmus::DB::Testresult->has_many(logs =>
["Litmus::DB::LogTestresult" => 'log_id']);
Litmus::DB::Testresult->has_many(comments => "Litmus::DB::Comment", {order_by => 'comment_id ASC, submission_time ASC'});
Litmus::DB::Testresult->has_many(bugs => "Litmus::DB::Resultbug", {order_by => 'bug_id ASC, submission_time DESC'});
Litmus::DB::Testresult->autoinflate(dates => 'Time::Piece');
Litmus::DB::Testresult->set_sql(DefaultTestResults => qq{
SELECT tr.testresult_id,tr.testcase_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email
FROM test_results tr, testcases t, platforms p, opsyses o, branches b, products pr, test_result_status_lookup trsl, testgroups tg, subgroups sg, users u, testcase_subgroups tcsg, subgroup_testgroups sgtg
WHERE tr.testcase_id=t.testcase_id AND tr.opsys_id=o.opsys_id AND o.platform_id=p.platform_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_status_id=trsl.result_status_id AND tcsg.testcase_id=tr.testcase_id AND tcsg.subgroup_id=sg.subgroup_id AND sg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id AND tr.valid=1
ORDER BY tr.submission_time DESC, t.testcase_id DESC
LIMIT $_num_results_default
});
Litmus::DB::Testresult->set_sql(CommonResults => qq{
SELECT COUNT(tr.testcase_id) AS num_results, tr.testcase_id, t.summary, MAX(tr.submission_time) AS most_recent, MAX(tr.testresult_id) AS max_id
FROM test_results tr, testcases t, test_result_status_lookup trsl
WHERE tr.testcase_id=t.testcase_id AND tr.result_status_id=trsl.result_status_id AND trsl.class_name=?
GROUP BY tr.testcase_id
ORDER BY num_results DESC, tr.testresult_id DESC
LIMIT 15
});
Litmus::DB::Testresult->set_sql(Completed => qq{
SELECT tr.*
FROM test_results tr, opsyses o
WHERE tr.testcase_id=? AND
tr.build_id=? AND
tr.locale_abbrev=? AND
tr.opsys_id=o.opsys_id AND
o.platform_id=?
ORDER BY tr.submission_time DESC
});
Litmus::DB::Testresult->set_sql(CompletedByUser => qq{
SELECT tr.*
FROM test_results tr, opsyses o
WHERE tr.testcase_id=? AND
tr.build_id=? AND
tr.locale_abbrev=? AND
tr.opsys_id=o.opsys_id AND
o.platform_id=? AND
tr.user_id=?
ORDER BY tr.submission_time DESC
});
#########################################################################
# for historical reasons, note() is a shorthand way of saying "the text of
# the first comment on this result if that comment was submitted by the
# result submitter"
#########################################################################
sub note {
my $self = shift;
my @comments = $self->comments();
if (@comments && $comments[0] &&
$comments[0]->user() == $self->user()) {
return $comments[0]->comment();
} else {
return undef;
}
}
#########################################################################
# is this test result from a trusted user?
#########################################################################
sub istrusted {
my $self = shift;
if ($self->user()->istrusted()) {
return 1;
} else {
return 0;
}
}
#########################################################################
# &getDefaultTestResults($)
#
#########################################################################
sub getDefaultTestResults($) {
my $self = shift;
my @rows = $self->search_DefaultTestResults();
my $criteria = "Default<br/>Ordered by Created<br/>Limit to $_num_results_default results";
return $criteria, \@rows;
}
#########################################################################
# &getTestResults($\@\@$)
#
#########################################################################
sub getTestResults($\@\@$) {
my ($self,$where_criteria,$order_by_criteria,$limit_value) = @_;
my $select = 'SELECT tr.testresult_id,tr.testcase_id,t.summary,tr.submission_time AS created,p.name AS platform_name,pr.name as product_name,trsl.name AS result_status,trsl.class_name AS result_status_class,b.name AS branch_name,tg.name AS test_group_name, tr.locale_abbrev, u.email';
my $from = 'FROM test_results tr, testcases t, platforms p, opsyses o, branches b, products pr, test_result_status_lookup trsl, testgroups tg, subgroups sg, users u, testcase_subgroups tcsg, subgroup_testgroups sgtg';
my $where = 'WHERE tr.testcase_id=t.testcase_id AND tr.opsys_id=o.opsys_id AND o.platform_id=p.platform_id AND tr.branch_id=b.branch_id AND b.product_id=pr.product_id AND tr.result_status_id=trsl.result_status_id AND tcsg.testcase_id=tr.testcase_id AND tcsg.subgroup_id=sg.subgroup_id AND sg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=tg.testgroup_id AND tr.user_id=u.user_id AND tr.valid=1';
my $limit = 'LIMIT ';
foreach my $criterion (@$where_criteria) {
$criterion->{'value'} =~ s/'/\'/g;
if ($criterion->{'field'} eq 'branch') {
$where .= " AND b.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'locale') {
$where .= " AND tr.locale_abbrev='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'product') {
$where .= " AND pr.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'platform') {
$where .= " AND p.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'test_group') {
$where .= " AND tg.name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'testcase_id') {
$where .= " AND tr.testcase_id='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'summary') {
$where .= ' AND t.summary LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'email') {
$where .= ' AND u.email LIKE \'%%' . $criterion->{'value'} . '%%\'';
} elsif ($criterion->{'field'} eq 'result_status') {
$where .= " AND trsl.class_name='" . $criterion->{'value'} . "'";
} elsif ($criterion->{'field'} eq 'trusted_only') {
if ($from !~ /users u/) {
$from .= ", users u";
}
$where .= " AND u.user_id=tr.user_id AND u.is_admin=1";
} elsif ($criterion->{'field'} eq 'start_date') {
my $start_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($start_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid start date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time>=$start_timestamp";
}
} elsif ($criterion->{'field'} eq 'end_date') {
my $end_timestamp = &Date::Manip::UnixDate(&Date::Manip::ParseDateString($criterion->{'value'}),"%q");
if ($end_timestamp !~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
print STDERR "Unable to parse a valid end date from '$criterion->{'value'},' ignoring.\n";
} else {
$where .= " AND tr.submission_time<=$end_timestamp";
}
} elsif ($criterion->{'field'} eq 'timespan') {
next if ($criterion->{'value'} eq 'all');
my $day_delta = $criterion->{'value'};
my $err;
my $timestamp =
&Date::Manip::UnixDate(&Date::Manip::DateCalc("now",
"$day_delta days",
\$err),
"%q");
$where .= " AND tr.submission_time>=$timestamp";
} elsif ($criterion->{'field'} eq 'search_field') {
($from,$where) = &_processSearchField($criterion,$from,$where);
} else {
# Skip unknown field
}
}
my $order_by = 'ORDER BY ';
foreach my $criterion (@$order_by_criteria) {
# Skip empty fields.
next if (!$criterion or !$criterion->{'field'});
if ($criterion->{'field'} eq 'created') {
$order_by .= "tr.submission_time $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'product') {
$order_by .= "pr.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'platform') {
$order_by .= "p.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'test_group') {
$order_by .= "tg.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'testcase_id') {
$order_by .= "tr.testcase_id $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'summary') {
$order_by .= "t.summary $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'result_status') {
$order_by .= "trsl.class_name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'branch') {
$order_by .= "b.name $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'locale') {
$order_by .= "tr.locale_abbrev $criterion->{'direction'},";
} elsif ($criterion->{'field'} eq 'email') {
$order_by .= "u.email $criterion->{'direction'},";
} else {
# Skip unknown field
}
}
if ($order_by eq 'ORDER BY ') {
$order_by .= 'tr.submission_time DESC';
} else {
chop($order_by);
}
if ($limit_value and $limit_value ne '') {
$limit .= "$limit_value";
} else {
$limit .= "$_num_results_default";
}
my $sql = "$select $from $where $order_by $limit";
#print $sql,"<br/>\n";
Litmus::DB::Testresult->set_sql(TestResults => qq{
$sql
});
my @rows = $self->search_TestResults();
return \@rows;
}
#########################################################################
# &_processSearchField(\%\$\$)
#
#########################################################################
sub _processSearchField(\%) {
my ($search_field,$from,$where) = @_;
my $table_field = "";
if ($search_field->{'search_field'} eq 'build_id') {
$table_field='tr.build_id';
} elsif ($search_field->{'search_field'} eq 'comments') {
$table_field='c.comment';
} elsif ($search_field->{'search_field'} eq 'locale') {
$table_field='tr.locale_abbrev';
} elsif ($search_field->{'search_field'} eq 'opsys') {
$table_field='o.name';
} elsif ($search_field->{'search_field'} eq 'platform') {
$table_field='p.name';
} elsif ($search_field->{'search_field'} eq 'product') {
$table_field='pr.name';
} elsif ($search_field->{'search_field'} eq 'result_status') {
$table_field='trsl.name';
} elsif ($search_field->{'search_field'} eq 'subgroup') {
$table_field='sg.name';
} elsif ($search_field->{'search_field'} eq 'email') {
if ($from !~ /users u/) {
$from .= ", users u";
$where .= " AND tr.user_id=u.user_id";
}
$table_field='u.email';
} elsif ($search_field->{'search_field'} eq 'summary') {
$table_field='t.summary';
} elsif ($search_field->{'search_field'} eq 'test_group') {
$table_field='tg.name';
} elsif ($search_field->{'search_field'} eq 'user_agent') {
$table_field='tr.user_agent';
} else {
return ($from,$where);
}
if ($search_field->{'match_criteria'} eq 'contains_all' or
$search_field->{'match_criteria'} eq 'contains_any' or
$search_field->{'match_criteria'} eq 'not_contain_any') {
my $join = "";
if ($search_field->{'match_criteria'} eq 'contains_all') {
$join = 'AND';
} else {
$join = 'OR';
}
my @words = split(/ /,$search_field->{'value'});
if ($search_field->{'match_criteria'} eq 'not_contain_any') {
$where .= " AND NOT (";
} else {
$where .= " AND (";
}
my $first_pass = 1;
foreach my $word (@words) {
if ( $first_pass ) {
$where .= "UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
$first_pass = 0;
} else {
$where .= " $join UPPER($table_field) LIKE UPPER('%%" . $word . "%%')";
}
}
$where .= ")";
} elsif ($search_field->{'match_criteria'} eq 'contains') {
$where .= " AND UPPER($table_field) LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'contains_case') {
$where .= " AND $table_field LIKE '%%" . $search_field->{'value'} . "%%'";
} elsif ($search_field->{'match_criteria'} eq 'not_contain') {
$where .= " AND UPPER($table_field) NOT LIKE UPPER('%%" . $search_field->{'value'} . "%%')";
} elsif ($search_field->{'match_criteria'} eq 'regexp') {
$where .= " AND $table_field REGEXP '" . $search_field->{'value'} . "'";
} elsif ($search_field->{'match_criteria'} eq 'not_regexp') {
$where .= " AND $table_field NOT REGEXP '" . $search_field->{'value'} . "'";
} else {
# Ignore unknown match criteria.
return ($from,$where);
}
return ($from,$where);
}
#########################################################################
#########################################################################
sub getCommonResults($$) {
my ($self,$status,$limit_value) = @_;
if (!$status) {
return undef;
}
if (!$limit_value) {
$limit_value = $_num_results_default;
}
my @rows = $self->search_CommonResults($status);
return \@rows;
}
1;

View File

@@ -1,119 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::User;
use strict;
use Litmus::Config;
use base 'Litmus::DBI';
Litmus::DB::User->table('users');
Litmus::DB::User->columns(All => qw/user_id bugzilla_uid email password realname irc_nickname enabled is_admin authtoken/);
Litmus::DB::User->column_alias("is_trusted", "istrusted");
Litmus::DB::User->column_alias("is_admin", "is_trusted");
Litmus::DB::User->has_many(test_results => "Litmus::DB::Testresult");
Litmus::DB::User->has_many(sessions => "Litmus::DB::Session");
# ZLL: only load BugzillaUser if Bugzilla Auth is actually enabled
if ($Litmus::Config::bugzilla_auth_enabled) {
Litmus::DB::User->has_a(bugzilla_uid => "Litmus::DB::BugzillaUser");
}
__PACKAGE__->set_sql(RetrieveAll => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
ORDER BY email ASC
});
__PACKAGE__->set_sql(TopTesters => qq{
SELECT users.user_id, users.email, count(*) AS num_results
FROM users, test_results
WHERE users.user_id=test_results.user_id
GROUP BY user_id
ORDER BY num_results DESC
LIMIT 15
});
# the COLLATE latin1_general_ci sillyness forces a case-insensitive match
# removed a LIMIT 300 to work around a mysql bug in the ancient version
# on rodan
__PACKAGE__->set_sql(FullTextMatches => q{
SELECT *
FROM __TABLE__
WHERE
email COLLATE latin1_general_ci like concat('%%',?,'%%') OR
irc_nickname COLLATE latin1_general_ci like concat('%%',?,'%%') OR
realname COLLATE latin1_general_ci like concat('%%',?,'%%')
ORDER BY email ASC
});
#########################################################################
# returns the crypt'd password from a linked Bugzilla account if it
# exists or the Litmus user account
sub getRealPasswd {
my $self = shift;
if ($self->bugzilla_uid()) {
return $self->bugzilla_uid()->cryptpassword();
} else {
return $self->password();
}
}
#########################################################################
sub getDisplayName() {
my $self = shift;
return $self->irc_nickname if ($self->irc_nickname and
$self->irc_nickname ne '');
return $self->realname if ($self->realname and
$self->realname ne '');
if ($self->email and
$self->email ne '') {
my $display_name = $self->email;
$display_name =~ s/\@.*$//g;
return $display_name
}
return undef;
}
1;

View File

@@ -1,130 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DBI;
require Apache::DBI;
use strict;
use warnings;
use Litmus::Config;
use Memoize;
use base 'Class::DBI::mysql';
our $dsn = "dbi:mysql:database=$Litmus::Config::db_name;host=$Litmus::Config::db_host;port=3306";
our %column_aliases;
Litmus::DBI->connection( $dsn,
$Litmus::Config::db_user,
$Litmus::Config::db_pass,
{AutoCommit=>1}
);
Litmus::DBI->autoupdate(1);
# In some cases, we have column names that make sense from a database perspective
# (i.e. subgroup_id), but that don't make sense from a class/object perspective
# (where subgroup would be more appropriate). To handle this, we allow for
# Litmus::DBI's subclasses to set column aliases with the column_alias() sub.
# Takes the database column name and the alias name.
sub column_alias {
my ($self, $db_name, $alias_name) = @_;
$column_aliases{$alias_name} = $db_name;
}
# here's where the actual work happens. We consult our alias list
# (as created by calls to column_alias()) and substitute the
# database column if we find a match
memoize('find_column');
sub find_column {
my $self = shift;
my $wanted = shift;
if (ref $self) {
$wanted =~ s/^.*::(\w+)$/$1/;
}
if ($column_aliases{$wanted}) {
return $column_aliases{$wanted};
} else {
# not an alias, so we use the normal
# find_column() from Class::DBI
$self->SUPER::find_column($wanted);
}
}
sub AUTOLOAD {
my $self = shift;
my @args = @_;
my $name = our $AUTOLOAD;
my $col = $self->find_column($name);
if (!$col) {
internalError("tried to call Litmus::DBI method $name which does not exist");
}
return $self->$col(@args);
}
sub _croak {
my ($self, $message, %info) = @_;
internalError($message);
return;
}
# Get Class::DBI's default dbh options
my $db_options = { __PACKAGE__->_default_attributes };
__PACKAGE__->_remember_handle('Main'); # so dbi_commit works
# override default to avoid using Ima::DBI closure
sub db_Main {
my $dbh;
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
$dbh = Apache->request()->pnotes('dbh');
}
if ( !$dbh ) {
$dbh = DBI->connect(
$dsn, $Litmus::Config::db_user,
$Litmus::Config::db_pass, $db_options
);
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
Apache->request()->pnotes( 'dbh', $dbh );
}
}
return $dbh;
}
1;

View File

@@ -1,275 +0,0 @@
# 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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
# Utility functions (based on those from Bugzilla's checksetup.pl to
# create new fields and indicies to the schema when upgrading an installation.
package Litmus::DBTools;
use strict;
#########################################################################
sub new {
my ($class, $dbh) = @_;
my $self = {};
$self->{'dbh'} = $dbh;
bless($self);
return $self;
}
#########################################################################
sub ChangeFieldType {
my ($self, $table, $field, $newtype) = @_;
my $ref = $self->GetFieldDef($table, $field);
#print "0: $$ref[0] 1: $$ref[1] 2: $$ref[2] 3: $$ref[3] 4: $$ref[4]\n";
my $oldtype = $ref->[1];
if (! $ref->[2]) {
$oldtype .= qq{ not null};
}
if ($ref->[4]) {
$oldtype .= qq{ default "$ref->[4]"};
}
if ($oldtype ne $newtype) {
print "Updating field type $field in table $table ...\n";
print "old: $oldtype\n";
print "new: $newtype\n";
# 'not null' should be passed as part of the call to ChangeFieldType()
# $newtype .= " NOT NULL" if $$ref[3];
$self->{'dbh'}->do("ALTER TABLE $table
CHANGE $field
$field $newtype");
}
}
#########################################################################
sub RenameTable {
my ($self, $table, $newname) = @_;
my $ref = $self->TableExists($table);
return unless $ref; # already renamed?
$self->{'dbh'}->do("ALTER TABLE $table
RENAME TO $newname");
}
#########################################################################
sub RenameField {
my ($self, $table, $field, $newname) = @_;
my $ref = $self->GetFieldDef($table, $field);
return unless $ref; # already fixed?
#print "0: $$ref[0] 1: $$ref[1] 2: $$ref[2] 3: $$ref[3] 4: $$ref[4]\n";
if ($$ref[1] ne $newname) {
print "Updating field $field in table $table ...\n";
my $type = $$ref[1];
$type .= " NOT NULL" if !$$ref[2];
$type .= " auto_increment" if $$ref[5] =~ /auto_increment/;
$self->{'dbh'}->do("ALTER TABLE $table
CHANGE $field
$newname $type");
}
}
#########################################################################
sub AddField {
my ($self, $table, $field, $definition) = @_;
my $ref = $self->GetFieldDef($table, $field);
return if $ref; # already added?
print "Adding new field $field to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD COLUMN $field $definition");
}
#########################################################################
sub AddKey {
my ($self, $table, $field, $definition) = @_;
my $ref = $self->GetIndexDef($table, $field);
return if $ref; # already added?
print "Adding new key $field to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD KEY $field $definition");
}
#########################################################################
sub AddUniqueKey {
my ($self, $table, $field, $definition) = @_;
my $ref = $self->GetIndexDef($table, $field);
return if $ref; # already added?
print "Adding new key $field to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD UNIQUE KEY $field $definition");
}
#########################################################################
sub AddFullText {
my ($self, $table, $index, $definition) = @_;
my $ref = $self->GetIndexDef($table, $index);
return if $ref; # already added?
print "Adding new fulltext $index to table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
ADD FULLTEXT $index $definition");
}
#########################################################################
sub DropField {
my ($self, $table, $field) = @_;
my $ref = $self->GetFieldDef($table, $field);
return unless $ref; # already dropped?
print "Deleting unused field $field from table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
DROP COLUMN $field");
}
#########################################################################
sub DropTable {
my ($self, $table, $field) = @_;
my $ref = $self->TableExists($table);
return unless $ref; # already dropped?
print "Deleting unused table $table ...\n";
$self->{'dbh'}->do("DROP TABLE $table");
}
#########################################################################
# this uses a mysql specific command.
sub TableExists {
my ($self, $table) = @_;
my @tables;
my $dbtable;
my $exists = 0;
my $sth = $self->{'dbh'}->prepare("SHOW TABLES");
$sth->execute;
while ( ($dbtable) = $sth->fetchrow_array ) {
if ($dbtable eq $table) {
$exists = 1;
}
}
$sth->finish;
return $exists;
}
#########################################################################
sub GetFieldDef {
my ($self, $table, $field) = @_;
my $sth = $self->{'dbh'}->prepare("SHOW COLUMNS FROM $table");
$sth->execute;
while (my $ref = $sth->fetchrow_arrayref) {
next if $$ref[0] ne $field;
$sth->finish;
return $ref;
}
}
#########################################################################
sub GetIndexDef {
my ($self, $table, $field) = @_;
my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table");
$sth->execute;
while (my $ref = $sth->fetchrow_arrayref) {
next if $$ref[2] ne $field;
$sth->finish;
return $ref;
}
}
#########################################################################
sub CountIndexes {
my ($self, $table) = @_;
my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table");
$sth->execute;
if ( $sth->rows == -1 ) {
$sth->finish;
die ("Unexpected response while counting indexes in $table:" .
" \$sth->rows == -1");
}
my $rows = $sth->rows;
$sth->finish;
return ($rows);
}
#########################################################################
sub DropIndex {
my ($self, $table, $index) = @_;
my $ref = $self->GetIndexDef($table, $index);
return unless $ref; # no matching index?
print "Removing index $index from table $table ...\n";
$self->{'dbh'}->do("ALTER TABLE $table
DROP INDEX $index");
}
#########################################################################
sub DropIndexes {
my ($self, $table) = @_;
my %SEEN;
# get the list of indexes
#
my $sth = $self->{'dbh'}->prepare("SHOW INDEX FROM $table");
$sth->execute;
# drop each index
#
while ( my $ref = $sth->fetchrow_arrayref) {
# note that some indexes are described by multiple rows in the
# index table, so we may have already dropped the index described
# in the current row.
#
next if exists $SEEN{$$ref[2]};
if ($$ref[2] eq 'PRIMARY') {
# The syntax for dropping a PRIMARY KEY is different
# from the normal DROP INDEX syntax.
$self->{'dbh'}->do("ALTER TABLE $table DROP PRIMARY KEY");
}
else {
$self->{'dbh'}->do("ALTER TABLE $table DROP INDEX $$ref[2]");
}
$SEEN{$$ref[2]} = 1;
}
$sth->finish;
}
1;

View File

@@ -1,84 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# General error reporting
package Litmus::Error;
use strict;
our @ISA = qw(Exporter);
@Litmus::Error::EXPORT = qw(
basicError
invalidInputError
internalError
lastDitchError
);
# just a general run of the mill error
sub basicError {
my $message = shift;
_doError($message);
exit;
}
# used to alert the user when an unexpected input value is found
sub invalidInputError($) {
my $message = shift;
_doError("Invalid Input - $message");
exit;
}
sub internalError($) {
my $message = shift;
_doError("Litmus has suffered an internal error - $message");
exit;
}
# an error type that does not use a template error message. Used if we
# can't even process the error template.
sub lastDitchError($) {
my $message = shift;
print "Error - Litmus has suffered a serious fatal internal error - $message";
exit;
}
sub _doError($) {
my $message = shift;
my $vars = {
message => $message,
};
Litmus->template()->process("error/error.html.tmpl", $vars) ||
lastDitchError(Litmus->template()->error());
}
1;

View File

@@ -1,342 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::FormWidget;
use strict;
BEGIN {
use Exporter ();
use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = 0.01;
@ISA = qw (Exporter);
#Give a hoot don't pollute, do not export more than needed by default
@EXPORT = qw ( getProducts );
@EXPORT_OK = qw ();
%EXPORT_TAGS = ();
}
use DBI;
use Litmus::DBI;
our $_dbh = Litmus::DBI->db_Main();
#########################################################################
=head1 NAME
Litmus::FormWidget - Create value lists to be used in HTML forms
=head1 SYNOPSIS
use Litmus::FormWidget
=head1 DESCRIPTION
Litmus::FormWidget creates value lists to be used in HTML forms.
=head1 USAGE
=head1 BUGS
=head1 SUPPORT
=head1 AUTHOR
Chris Cooper
CPAN ID: CCOOPER
Mozilla Corporation
ccooper@deadsquid.com
http://litmus.mozilla.org/
=head1 SEE ALSO
perl(1).
=cut
#########################################################################
#sub new
#{
# my ($class, %parameters) = @_;
# my $self = bless ({}, ref ($class) || $class);
# return ($self);
#}
#########################################################################
=head2 getProducts
Usage : How to use this function/method
Purpose : What it does
Returns : What it returns
Argument : What it wants to know
Throws : Exceptions and other anomolies
Comments : This is a sample subroutine header.
: It is polite to include more pod and fewer comments.
See Also :
=cut
#########################################################################
sub getProducts()
{
my $sql = "SELECT name, product_id FROM products ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getUniquePlatforms()
{
my $sql = "SELECT DISTINCT(name), platform_id FROM platforms ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getPlatforms()
{
my $sql = "SELECT platform_id, name from platforms ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getBranches()
{
my $sql = "SELECT name, branch_id FROM branches ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getUniqueBranches()
{
my $sql = "SELECT DISTINCT(name) FROM branches ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getOpsyses()
{
my $sql = "SELECT name, opsys_id FROM opsyses ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getUniqueOpsyses()
{
my $sql = "SELECT DISTINCT(name) FROM opsyses ORDER BY name ASC";
return _getValues($sql);
}
#########################################################################
sub getLogTypes()
{
my $sql = "SELECT DISTINCT(name) FROM log_type_lookup ORDER BY name";
return _getValues($sql);
}
#########################################################################
sub getTestStatuses()
{
my @TestStatuses = ({name => 'Enabled'},
{name => 'Disabled'});
return \@TestStatuses;
}
#########################################################################
sub getResultStatuses()
{
my $sql = "SELECT result_status_id,class_name FROM test_result_status_lookup ORDER BY result_status_id";
return _getValues($sql);
}
#########################################################################
sub getTestcaseIDs()
{
my $sql = "SELECT testcase_id FROM testcases ORDER BY testcase_id";
return _getValues($sql);
}
#########################################################################
sub getTestcases()
{
my $sql = "SELECT testcase_id, summary, product_id FROM testcases ORDER BY testcase_id";
return _getValues($sql);
}
#########################################################################
sub getSubgroups()
{
my $sql = "SELECT subgroup_id, name, product_id FROM subgroups ORDER BY name, subgroup_id";
return _getValues($sql);
}
#########################################################################
sub getTestgroups()
{
my $sql = "SELECT testgroup_id, name, product_id FROM testgroups ORDER BY name, testgroup_id";
return _getValues($sql);
}
#########################################################################
sub getLocales()
{
my @locales = Litmus::DB::Locale->retrieve_all();
return \@locales;
}
#########################################################################
sub getUsers()
{
my @users = Litmus::DB::User->retrieve_all();
return \@users;
}
#########################################################################
sub getAuthors()
{
my $sql = "SELECT user_id, email FROM users WHERE is_admin=1 ORDER BY email";
return _getValues($sql);
}
#########################################################################
sub getFields()
{
my @fields = (
{ name => 'build_id',
display_string => "Build ID", },
{ name => 'comment',
display_string => "Comments", },
{ name => 'locale',
display_string => "Locale", },
{ name => 'opsys',
display_string => "Operating System", },
{ name => 'platform',
display_string => "Platform", },
{ name => 'product',
display_string => "Product", },
{ name => 'result_status',
display_string => "Result Status", },
{ name => 'subgroup',
display_string => "Subgroup", },
{ name => 'email',
display_string => "Submitted By", },
{ name => 'summary',
display_string => "Summary", },
{ name => 'testgroup',
display_string => "Testgroup", },
{ name => 'user_agent',
display_string => "User Agent", },
);
return \@fields;
}
#########################################################################
sub getMatchCriteria()
{
my @match_criteria = (
{ name => "contains_all",
display_string => "contains all of the words/strings" },
{ name => "contains_any",
display_string => "contains any of the words/strings" },
{ name => "contains",
display_string => "contains the word/string" },
{ name => "contains_case",
display_string => "contains the word/string (exact case)" },
{ name => "not_contain",
display_string => "does not contains the word/string" },
{ name => "not_contain_any",
display_string => "does not contains any of the words/string" },
{ name => "regexp",
display_string => "matches the regexp" },
{ name => "not_regexp",
display_string => "does not match the regexp" },
);
return \@match_criteria;
}
#########################################################################
sub getSortFields()
{
my @sort_fields = (
{ name => "branch",
display_string => "Branch"},
{ name => "created",
display_string => "Date"},
{ name => "locale",
display_string => "Locale"},
{ name => "platform",
display_string => "Platform"},
{ name => "product",
display_string => "Product"},
{ name => "email",
display_string => "Submitted By"},
{ name => "summary",
display_string => "Summary"},
{ name => "result_status",
display_string => "Status"},
{ name => "testcase_id",
display_string => "Testcase ID#"},
{ name => "testgroup",
display_string => "Testgroup"},
);
return \@sort_fields;
}
#########################################################################
sub _getValues($)
{
my ($sql) = @_;
my $sth = $_dbh->prepare_cached($sql);
$sth->execute();
my @rows;
while (my $data = $sth->fetchrow_hashref) {
push @rows, $data;
}
return \@rows;
$sth->finish();
}
1;

View File

@@ -1,43 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::StripScripts;
use base qw(HTML::StripScripts::Parser);
# Override broken href validation code.
sub validate_href_attribute {
my ($self, $text) = @_;
$self->SUPER::validate_href_attribute or $text =~ m<^((https?|ftp|mailto)://[\w\-\.]{1,100}(?:\:\d{1,5})?(?:/(?:[\w\-.!~*|;:/?=+\$\,%#]|&amp;){0,100})?)$>x ? $1 : undef;
}
1;

View File

@@ -1,263 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::SysConfig;
use strict;
require Exporter;
use Litmus;
use Litmus::DB::Locale;
use Litmus::DB::Product;
use Litmus::Error;
use Litmus::Utils;
use CGI;
our @ISA = qw(Exporter);
our @EXPORT = qw();
my $configcookiename = $Litmus::Config::sysconfig_cookiename;
sub new {
my ($class, $product, $platform, $opsys, $branch, $build_id, $locale) = @_;
my $self = {};
bless($self);
$self->{"product"} = $product;
$self->{"platform"} = $platform;
$self->{"opsys"} = $opsys;
$self->{"branch"} = $branch;
$self->{"build_id"} = $build_id;
$self->{"locale"} = $locale;
return $self;
}
sub setCookie {
my $self = shift;
my %cookiedata;
my $c = Litmus->cgi();
my $cookie = $c->cookie(
-name => $configcookiename.'_'.$self->{"product"}->product_id(),
-value => join('|', $self->{"product"}->product_id(), $self->{"platform"}->platform_id(),
$self->{"opsys"}->opsys_id(), $self->{"branch"}->branch_id(), $self->{"build_id"}, $self->{"locale"}->abbrev()),
-domain => $main::ENV{"HTTP_HOST"},
);
return $cookie;
}
sub getCookie {
my $self = shift;
my $c = Litmus->cgi();
my $product = shift;
return Litmus::SysConfig->
realGetCookie($configcookiename.'_'.$product->product_id());
}
# returns sysconfig objects corresponding to all sysconfig cookies the user
# has set
sub getAllCookies {
my $self = shift;
my $c = Litmus->cgi();
my @cookies = ();
my @names = $c->cookie();
foreach my $cur (@names) {
if ($cur =~ /^\Q$configcookiename\E_/) {
push(@cookies, Litmus::SysConfig->realGetCookie($cur));
}
}
if (@cookies == 0) { push(@cookies, undef) }
return @cookies;
}
sub realGetCookie {
my $self = shift;
my $cookiename = shift;
my $c = Litmus->cgi();
my $cookie = $c->cookie($cookiename);
if (! $cookie) {
return;
}
my @sysconfig = split(/\|/, $cookie);
return new(undef,
Litmus::DB::Product->retrieve($sysconfig[0]),
Litmus::DB::Platform->retrieve($sysconfig[1]),
Litmus::DB::Opsys->retrieve($sysconfig[2]),
Litmus::DB::Branch->retrieve($sysconfig[3]),
$sysconfig[4],
Litmus::DB::Locale->retrieve($sysconfig[5])
);
}
sub product() {
my $self = shift;
return $self->{"product"};
}
sub platform() {
my $self = shift;
return $self->{"platform"};
}
sub opsys() {
my $self = shift;
return $self->{"opsys"};
}
sub branch() {
my $self = shift;
return $self->{"branch"};
}
sub build_id() {
my $self = shift;
return $self->{"build_id"};
}
sub locale() {
my $self = shift;
return $self->{"locale"};
}
# display the system configuration form
# optionally takes the product to configure for
# and requires a url to load when done. this
# url should call processForm() to
# set the sysconfig cookie and do
# error handling.
# optionaly, pass a CGI object and its
# data will be stored in the form so
# the receiving script can access it.
sub displayForm {
my $self = shift;
my $product = shift;
my $goto = shift;
my $c = shift;
my @products;
# if we already know the product, then just send it on:
if ($product) {
$products[0] = $product;
} else {
# we need to ask the user for the product then
@products = Litmus::DB::Product->retrieve_all();
}
my @locales = Litmus::DB::Locale->retrieve_all(
{ order_by => 'abbrev' }
);
my $vars = {
locales => \@locales,
products => \@products,
ua => Litmus::UserAgentDetect->new(),
"goto" => $goto,
cgidata => $c,
};
# if the user already has a cookie set for this product, then
# load those values as defaults:
if ($product && Litmus::SysConfig->getCookie($product)) {
my $sysconfig = Litmus::SysConfig->getCookie($product);
$vars->{"defaultplatform"} = $sysconfig->platform();
$vars->{"defaultopsys"} = $sysconfig->opsys();
$vars->{"defaultbranch"} = $sysconfig->branch();
$vars->{"defaultlocale"} = $sysconfig->locale();
}
# send a default build id if we have one:
my @cookies = Litmus::SysConfig->getAllCookies();
if ($cookies[0]) { $vars->{"defaultbuildid"} = $cookies[0]->build_id() }
my $cookie = Litmus::Auth::getCurrentUser();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{"title"} = "Run Tests";
Litmus->template()->process("runtests/sysconfig.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}
# process a form containing sysconfig information.
# takes a CGI object containing param data
sub processForm {
my $self = shift;
my $c = shift;
my $product = Litmus::DB::Product->retrieve($c->param("product"));
my $platform = Litmus::DB::Platform->retrieve($c->param("platform"));
my $opsys = Litmus::DB::Opsys->retrieve($c->param("opsys"));
my $branch = Litmus::DB::Branch->retrieve($c->param("branch"));
my $build_id = $c->param("build_id");
my $locale = Litmus::DB::Locale->retrieve($c->param("locale"));
requireField("product", $product);
requireField("platform", $platform);
requireField("opsys", $opsys);
requireField("branch", $branch);
requireField("build_id", $build_id);
requireField("locale", $locale);
# set a cookie with the user's testing details:
my $prod = Litmus::DB::Product->retrieve($c->param("product"));
my $sysconfig = Litmus::SysConfig->new(
$product,
$platform,
$opsys,
$branch,
$build_id,
$locale
);
return $sysconfig;
}
1;

View File

@@ -1,205 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
# Jacob Steenhagen <jake@bugzilla.org>
# Bradley Baetz <bbaetz@student.usyd.edu.au>
# Christopher Aillon <christopher@aillon.com>
# Tobias Burnus <burnus@net-b.de>
# Myk Melez <myk@mozilla.org>
# Max Kanat-Alexander <mkanat@bugzilla.org>
# Zach Lipton <zach@zachlipton.com>
# Chris Cooper <ccooper@deadsquid.com>
#
# ***** END LICENSE BLOCK *****
=cut
# This is mostly a placeholder. At some point in the future, we might
# want to be more like Bugzilla and support multiple languages and
# other fine features, so we keep this around now so that adding new
# things later won't require changing every source file.
package Litmus::Template;
use strict;
use Litmus::Config;
use Litmus::StripScripts;
use Text::Markdown;
use base qw(Template);
my $template_include_path;
$Template::Directive::WHILE_MAX = 30000;
# Returns the path to the templates based on the Accept-Language
# settings of the user and of the available languages
# If no Accept-Language is present it uses the defined default
sub getTemplateIncludePath () {
return "templates/en/default";
}
# Constants:
my %constants = {};
$constants{litmus_version} = $Litmus::Config::version;
# html tag stripper:
my $strip = Litmus::StripScripts->new(
{
AllowHref => 1,
AllowSrc => 1,
Context => 'Document'
},
strict_names => 1,
);
###############################################################################
# Templatization Code
# Use the Toolkit Template's Stash module to add utility pseudo-methods
# to template variables.
use Template::Stash;
# Add "contains***" methods to list variables that search for one or more
# items in a list and return boolean values representing whether or not
# one/all/any item(s) were found.
$Template::Stash::LIST_OPS->{ contains } =
sub {
my ($list, $item) = @_;
return grep($_ eq $item, @$list);
};
$Template::Stash::LIST_OPS->{ containsany } =
sub {
my ($list, $items) = @_;
foreach my $item (@$items) {
return 1 if grep($_ eq $item, @$list);
}
return 0;
};
# Allow us to still get the scalar if we use the list operation ".0" on it
$Template::Stash::SCALAR_OPS->{ 0 } =
sub {
return $_[0];
};
# Add a "substr" method to the Template Toolkit's "scalar" object
# that returns a substring of a string.
$Template::Stash::SCALAR_OPS->{ substr } =
sub {
my ($scalar, $offset, $length) = @_;
return substr($scalar, $offset, $length);
};
# Add a "truncate" method to the Template Toolkit's "scalar" object
# that truncates a string to a certain length.
$Template::Stash::SCALAR_OPS->{ truncate } =
sub {
my ($string, $length, $ellipsis) = @_;
$ellipsis ||= "";
return $string if !$length || length($string) <= $length;
my $strlen = $length - length($ellipsis);
my $newstr = substr($string, 0, $strlen) . $ellipsis;
return $newstr;
};
# Create the template object that processes templates and specify
# configuration parameters that apply to all templates.
sub create {
my $class = shift;
return $class->new({
INCLUDE_PATH => &getTemplateIncludePath,
CONSTANTS => \%constants,
PRE_PROCESS => "variables.none.tmpl",
POST_CHOMP => 1,
EVAL_PERL => 1,
COMPILE_DIR => $Litmus::Config::datadir,
FILTERS => {
# disallow all html in testcase data except for non-evil tags
testdata => sub {
my ($data) = @_;
$strip->parse($data);
$strip->eof();
return $strip->filtered_document;
},
# process the text with the markdown text processor
markdown => sub {
my ($data) = @_;
$data = Text::Markdown::markdown($data);
return $data;
},
# Returns the text with backslashes, single/double quotes,
# and newlines/carriage returns escaped for use in JS strings.
# thanks to bugzilla!
js => sub {
my ($var) = @_;
$var =~ s/([\\\'\"\/])/\\$1/g;
$var =~ s/\n/\\n/g;
$var =~ s/\r/\\r/g;
$var =~ s/\@/\\x40/g; # anti-spam for email addresses
return $var;
},
# anti-spam filtering of email addresses
email => sub {
my ($var) = @_;
$var =~ s/\@/\&#64;/g;
return $var;
},
# dummy filter when we don't actually need to filter anything
none => sub {
my ($var) = @_;
return $var;
},
},
});
}
# override the process() method to sneak defaultemail into all template
# variable spaces
sub process {
my ($self, $template, $vars, $outstream, @opts) = @_;
my %vars = %$vars;
$vars{defaultemail} = $vars{defaultemail} ? $vars{defaultemail} :
Litmus->getCurrentUser();
$vars{show_admin} = Litmus->getCurrentUser() ?
Litmus->getCurrentUser()->is_admin() : 0;
$self->SUPER::process($template, \%vars, $outstream, @opts);
}

View File

@@ -1,66 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::Testlist;
use strict;
use base qw(Exporter);
@Litmus::Testlist::EXPORT = qw(
makeHotlist
);
sub makeHotlist {
my $numtests = shift;
my $state = shift;
my @tests = @_;
my @potentialtests;
foreach my $curtest (@tests) {
if ($curtest->isrecent()) {
foreach my $curplat ($curtest->subgroup()->testgroup()->product()->platforms()) {
my $found;
my $curstate = $curtest->state($curplat);
if ($curstate && $curstate->resultid() == $state->resultid()) {
push(@potentialtests, $curtest);
$found++;
}
if ($found) {next}
}
}
}
@potentialtests = sort{$b->num_recent_results() <=> $a->num_recent_results()}
@potentialtests;
return @potentialtests;
}

View File

@@ -1,147 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# Handle detection of system information from the UA string
package Litmus::UserAgentDetect;
use strict;
require Exporter;
use Litmus;
use Litmus::DB::Platform;
use Litmus::DB::Opsys;
use Litmus::DB::Branch;
our @ISA = qw(Exporter);
our @EXPORT = qw(detectBuildID);
# define some SQL queries we will use:
Litmus::DB::Platform->set_sql(detectplatform => qq{
SELECT p.platform_id
FROM platforms p, platform_products pp
WHERE
? REGEXP detect_regexp AND
p.platform_id=pp.platform_id AND
pp.product_id LIKE ?
});
Litmus::DB::Branch->set_sql(detectbranch => qq{
SELECT __ESSENTIAL__
FROM __TABLE__
WHERE
? REGEXP detect_regexp AND
product_id LIKE ?
});
# constructor. Optionally you can pass a UA string
# and it will be used. Otherwise the default is the
# current useragent.
sub new {
my $self = {};
my $class = shift;
my $ua = shift;
bless($self);
$self->{ua} = $main::ENV{"HTTP_USER_AGENT"};
if ($ua) { $self->{ua} = $ua }
return $self;
}
# default stringification is to return the ua:
use overload
'""' => \&ua;
sub ua {
my $self = shift;
# we pad the UA with a space since some of our regexp matches expect
# to match things at the end of the string. This is quite possibly
# a bug.
return $self->{ua}." ";
}
sub build_id {
my $self = shift;
my $ua = $self->{ua};
# mozilla products only
unless ($ua =~ /Mozilla\/5\.0/) {
return undef;
}
$ua =~ /(200\d*)/;
return $1;
}
sub locale {
my $self = shift;
my $ua = $self->{ua};
# mozilla products only
unless ($ua =~ /Mozilla\/5\.0/) {
return undef;
}
# Format (e.g.):
# Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051111 Firefox/1.5
$ua =~ /Mozilla\/5\.0 \([^;]*; [^;]*; [^;]*; ([^;]*); [^;]*\)/;
return $1;
}
sub platform {
my $self = shift;
my $product = shift; # optionally, just lookup for one product
if (! $product) { $product = '%' }
my @platforms = Litmus::DB::Platform->search_detectplatform($self->ua, $product);
return @platforms;
}
sub branch {
my $self = shift;
my $product = shift; # optionally, just lookup for one branch
if (! $product) { $product = '%' }
my @branches = Litmus::DB::Branch->search_detectbranch($self->ua, $product);
return @branches;
}
# from the legacy API before we had an OO interface:
sub detectBuildId() {
my $self = Litmus::UserAgentDetect->new($main::ENV{"HTTP_USER_AGENT"});
return $self->build_id();
}
1;

View File

@@ -1,61 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
# General utility functions
package Litmus::Utils;
use strict;
use Litmus;
use Litmus::Error;
use CGI;
our @ISA = qw(Exporter);
@Litmus::Utils::EXPORT = qw(
requireField
);
# requireField - checks that $field contains data (other than ---) and throws
# an invalidInputError if it does not.
sub requireField {
my ($fieldname, $field) = @_;
unless($field && $field ne "---") {
my $c = Litmus->cgi();
print $c->header();
invalidInputError("You must make a valid selection for field ".$fieldname.".");
}
}
1;

View File

@@ -1,419 +0,0 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::XML;
# Litmus XML Interface
# For further details, see the web services specification at
# http://wiki.mozilla.org/Litmus:Web_Services
use strict;
use XML::XPath;
use XML::XPath::XMLParser;
use Litmus::DB::User;
use Litmus::UserAgentDetect;
use Date::Manip;
use CGI::Carp qw(set_message fatalsToBrowser);
# if we die for some reason, make sure we give a fatal error per spec
BEGIN {
set_message(sub {
print "Fatal error: internal server error\n";
});
}
no warnings;
no diagnostics;
sub new {
my $self = {};
bless($self);
return $self;
}
# process XML test result data as described by
# the spec at http://wiki.mozilla.org/Litmus:Web_Services
sub processResults {
my $self = shift;
my $data = shift;
$self->parseResultFile($data) ? 1 : return 0;
unless ($self->authenticate()) { return 0} # login failure
$self->validateResults() ? 1 : return 0;
# at this point, everything is valid, so if we're just validating the
# results, we can return an ok:
if ($self->{'action'} eq 'validate') {
unless ($self->{'response'}) { $self->respOk() }
return 1;
}
# add so-called 'global logs' that apply to all the results
# we save them in @globallogs so we can map them to the results later
my @globallogs;
foreach my $log (@{$self->{'logs'}}) {
# the submission time is the timestamp of the first testresult:
my $newlog = Litmus::DB::Log->create({
submission_time => $self->{'results'}->[0]->{'timestamp'},
log_type => $log->{'type'},
log_text => $log->{'data'},
});
push(@globallogs, $newlog);
}
# now actually add the new results to the db:
foreach my $result (@{$self->{'results'}}) {
my $newres = Litmus::DB::Testresult->create({
testcase => $result->{'testid'},
user_agent => new Litmus::UserAgentDetect($self->{'useragent'}),
user => $self->{'user'},
opsys => $self->{'sysconfig'}->{'opsys'},
branch => $self->{'sysconfig'}->{'branch'},
locale => $self->{'sysconfig'}->{'locale'},
build_id => $self->{'sysconfig'}->{'buildid'},
machine_name => $self->{'machinename'},
result_status => $result->{'resultstatus'},
timestamp => $result->{'timestamp'},
exit_status => $result->{'exitstatus'},
duration_ms => $result->{'duration'},
valid => 1,
isAutomated => $result->{'isAutomated'},
});
if (!$newres) { $self->respErrResult($result->{'testid'}); next; }
# add any bug ids:
foreach my $bug (@{$result->{'bugs'}}) {
my $newbug = Litmus::DB::Resultbug->create({
test_result_id => $newres,
bug_id => $bug,
submission_time => $result->{'timestamp'},
user => $self->{'user'},
});
}
# add any comments:
foreach my $comment (@{$result->{'comments'}}) {
my $newcomment = Litmus::DB::Comment->create({
test_result => $newres,
submission_time => $result->{'timestamp'},
user => $self->{'user'},
comment => $comment,
});
}
# add logs:
my @resultlogs;
push(@resultlogs, @globallogs); # all results get the global logs
foreach my $log (@{$result->{'logs'}}) {
my $newlog = Litmus::DB::Log->create({
submission_time => $result->{'timestamp'},
log_type => $log->{'type'},
log_text => $log->{'data'},
});
push(@resultlogs, $newlog);
}
# now we map the logs to the current result:
foreach my $log (@resultlogs) {
Litmus::DB::LogTestresult->create({
test_result => $newres,
log_id => $log,
});
}
}
unless ($self->{'response'}) { $self->respOk() }
#$self->{'response'} = $self->{'results'}->[0]->{'resultstatus'};
}
sub parseResultFile {
my $self = shift;
my $data = shift;
my $x = XML::XPath->new(xml => $data, standalone => 1);
$self->{'useragent'} = $x->findvalue('/litmusresults/@useragent');
$self->{'machinename'} = $x->findvalue('litmusresults/@machinename');
$self->{'action'} = $x->findvalue('/litmusresults/@action');
$self->{'user'}->{'username'} = $x->findvalue(
'/litmusresults/testresults/@username');
$self->{'user'}->{'token'} = $x->findvalue(
'/litmusresults/testresults/@authtoken');
$self->{'sysconfig'}->{'product'} = $x->findvalue('/litmusresults/testresults/@product');
$self->{'sysconfig'}->{'platform'} = $x->findvalue('/litmusresults/testresults/@platform');
$self->{'sysconfig'}->{'opsys'} = $x->findvalue('/litmusresults/testresults/@opsys');
$self->{'sysconfig'}->{'branch'} = $x->findvalue('/litmusresults/testresults/@branch');
$self->{'sysconfig'}->{'buildid'} = $x->findvalue('/litmusresults/testresults/@buildid');
$self->{'sysconfig'}->{'locale'} = $x->findvalue('/litmusresults/testresults/@locale');
my @glogs = $x->find('/litmusresults/testresults/log')->get_nodelist();
my $l_ct = 0;
foreach my $log (@glogs) {
my $type = $x->findvalue('@logtype', $log);
my $logdata = stripWhitespace($log->string_value());
$self->{'logs'}->[$l_ct]->{'type'} = $type;
$self->{'logs'}->[$l_ct]->{'data'} = $logdata;
$l_ct++;
}
my @results = $x->find('/litmusresults/testresults/result')->get_nodelist();
my $c = 0;
foreach my $result (@results) {
$self->{'results'}->[$c]->{'testid'} = $x->findvalue('@testid', $result);
$self->{'results'}->[$c]->{'isAutomated'} = $x->findvalue('@is_automated_result', $result);
$self->{'results'}->[$c]->{'resultstatus'} = $x->findvalue('@resultstatus', $result);
$self->{'results'}->[$c]->{'exitstatus'} = $x->findvalue('@exitstatus', $result);
$self->{'results'}->[$c]->{'duration'} = $x->findvalue('@duration', $result);
$self->{'results'}->[$c]->{'timestamp'} =
&Date::Manip::UnixDate($x->findvalue('@timestamp', $result), "%q");
my @comments = $x->find('comment', $result)->get_nodelist();
my $com_ct = 0;
foreach my $comment (@comments) {
$comment = stripWhitespace($comment->string_value());
$self->{'results'}->[$c]->{'comments'}->[$com_ct] = $comment;
$com_ct++;
}
my @bugs = $x->find('bugnumber', $result)->get_nodelist();
my $bug_ct = 0;
foreach my $bug (@bugs) {
$bug = stripWhitespace($bug->string_value());
$self->{'results'}->[$c]->{'bugs'}->[$bug_ct];
$bug_ct++;
}
my @logs = $x->find('log', $result)->get_nodelist();
my $log_ct = 0;
foreach my $log (@logs) {
my $type = $x->findvalue('@logtype', $log);
my $logdata = stripWhitespace($log->string_value());
$self->{'results'}->[$c]->{'logs'}->[$log_ct]->{'type'} = $type;
$self->{'results'}->[$c]->{'logs'}->[$log_ct]->{'data'} = $logdata;
$log_ct++;
}
$c++;
}
$self->{'x'} = $x;
}
# validate the result data, and resolve references to various tables
# the correct objects, looking up id numbers as needed
sub validateResults {
my $self = shift;
my $action = $self->{'action'};
if ($action ne 'submit' && $action ne 'validate') {
$self->respErrFatal("Action must be either 'submit' or 'validate'");
return 0;
}
my @users = Litmus::DB::User->search(email => $self->{'user'}->{'username'});
$self->{'user'} = $users[0];
unless ($self->{'useragent'}) {
$self->respErrFatal("You must specify a useragent");
return 0;
}
my @prods = Litmus::DB::Product->search(name => $self->{'sysconfig'}->{'product'});
unless ($prods[0]) {
$self->respErrFatal("Invalid product: ".$self->{'sysconfig'}->{'product'});
return 0;
}
$self->{'sysconfig'}->{'product'} = $prods[0];
my @platforms = Litmus::DB::Platform->search_ByProductAndName(
$self->{'sysconfig'}->{'product'},
$self->{'sysconfig'}->{'platform'});
unless ($platforms[0]) {
$self->respErrFatal("Invalid platform: ".$self->{'sysconfig'}->{'platform'});
return 0;
}
$self->{'sysconfig'}->{'platform'} = $platforms[0];
my @opsyses = Litmus::DB::Opsys->search(
name => $self->{'sysconfig'}->{'opsys'},
platform => $self->{'sysconfig'}->{'platform'});
unless ($opsyses[0]) {
$self->respErrFatal("Invalid opsys: ".$self->{'sysconfig'}->{'opsys'});
return 0;
}
$self->{'sysconfig'}->{'opsys'} = $opsyses[0];
my @branches = Litmus::DB::Branch->search(
name => $self->{'sysconfig'}->{'branch'},
product => $self->{'sysconfig'}->{'product'});
unless ($branches[0]) {
$self->respErrFatal("Invalid branch: ".$self->{'sysconfig'}->{'branch'});
return 0;
}
$self->{'sysconfig'}->{'branch'} = $branches[0];
unless ($self->{'sysconfig'}->{'buildid'}) {
$self->respErrFatal("Invalid build id: ".$self->{'sysconfig'}->{'buildid'});
return 0;
}
my @locales = Litmus::DB::Locale->search(
locale => $self->{'sysconfig'}->{'locale'});
unless ($locales[0]) {
$self->respErrFatal("Invalid locale: ".$self->{'sysconfig'}->{'locale'});
return 0;
}
$self->{'sysconfig'}->{'locale'} = $locales[0];
foreach my $log (@{$self->{'logs'}}) {
my @types = Litmus::DB::LogType->search(name => $log->{'type'});
unless ($types[0]) {
$self->respErrFatal("Invalid log type: ".$log->{'type'});
return 0;
}
$log->{'type'} = $types[0];
}
foreach my $result (@{$self->{'results'}}) {
my @tests = Litmus::DB::Testcase->search(
test_id => $result->{'testid'});
unless ($tests[0]) {
$self->respErrResult('unknown', "Invalid test id");
next;
}
$result->{'testid'} = $tests[0];
# assume it's an automated test result if not specified
($result->{'isAutomated'} eq '0' || $result->{'isAutomated'} ne undef) ?
$result->{'isAutomated'} = 0 : $result->{'isAutomated'} = 1;
my @results = Litmus::DB::ResultStatus->search(
name => $result->{'resultstatus'});
unless ($results[0]) {
$self->respErrResult($result->{'testid'}, "Invalid resultstatus");
next;
}
$result->{'resultstatus'} = $results[0];
my @es = Litmus::DB::ExitStatus->search(
name => $result->{'exitstatus'});
unless ($es[0]) {
$self->respErrResult($result->{'testid'}, "Invalid exitstatus");
next;
}
$result->{'exitstatus'} = $es[0];
# if there's no duration, then it's just 0:
unless ($result->{'duration'}) {
$result->{'duration'} = 0;
}
# if there's no timestamp, then it's now:
unless ($result->{'timestamp'}) {
$result->{'timestamp'} = &Date::Manip::UnixDate("now","%q");
}
foreach my $log (@{$result->{'logs'}}) {
my @types = Litmus::DB::LogType->search(name => $log->{'type'});
unless ($types[0]) {
$self->respErrResult($result->{'testid'},
"Invalid log type: ".$log->{'type'});
next;
}
$log->{'type'} = $types[0];
}
}
return 1;
}
sub response {
my $self = shift;
return $self->{'response'};
}
# ONLY NON-PUBLIC API BELOW THIS POINT
sub authenticate {
my $self = shift;
my @users = Litmus::DB::User->search(email => $self->{'user'}->{'username'});
my $user = $users[0];
unless ($user) { $self->respErrFatal("User does not exist"); return 0 }
unless ($user->enabled()) { $self->respErrFatal("User disabled"); return 0 }
if ($user->authtoken() ne $self->{'user'}->{'token'}) {
respErrFatal("Invalid authentication token for user ".
$self->{'user'}->{'username'});
return 0;
}
return 1;
}
sub respOk {
my $self = shift;
$self->{'response'} = 'ok';
}
sub respErrFatal {
my $self = shift;
my $error = shift;
$self->{'response'} = "Fatal error: $error\n";
}
sub respErrResult {
my $self = shift;
my $testid = shift;
my $error = shift;
$self->{'response'} .= "Error processing result for test $testid: $error\n";
}
# remove leading and trailing whitespace from logs and comments
sub stripWhitespace {
my $txt = shift;
$txt =~ s/^\s+//;
$txt =~ s/\s+$//;
return $txt;
}
1;

View File

@@ -1,56 +0,0 @@
# Litmus Makefile
PERL=perl
install: templates
$(PERL) populatedb.pl
# precompile all templates with the Template Toolkit
# to speed things up a good bit.
# This ought to be done in a more "makelike" way, but
# various difficulties prevent that unless we use a configure
# script to generate the Makefile, at which point we could have
# been done already...
%.tmpl:
$(PERL) -e " \
eval('use CGI qw(-no_debug)'); \
use Litmus::Template;use diagnostics; \
\$$template = Litmus::Template->create(); \
\$$template->context()->template('$@'); \
"
templates: index.html.tmpl
$(PERL) -e " \
use File::Find; \
find({ wanted => sub { \
\$$name = \$$File::Find::name; \
return if (-d \$$name); \
return if (\$$name =~ /\/CVS\//); \
return if (\$$name !~ /\.tmpl\$$/); \
\$$name =~ s/templates\/en\/default\///; \
if (-M 'templates/en/default/'.\$$name < -M 'data/templates/en/default/'.\$$name \
|| ! -e 'data/templates/en/default/'.\$$name \
|| -M 'Litmus/Template.pm' < -M 'data/templates/en/default/'.\$$name) { \
system("make", "\$$name"); \
} \
}, no_chdir => 1 }, 'templates/en/default'); \
"
# tags: generate ctags style hints for ease of editing
# requires Exuberant Ctags to be installed (http://ctags.sf.net/)
ctags:
`which ctags` --excmd=number --tag-relative=no --fields=+a+m+n+S -R `pwd`
tags: ctags
test:
$(PERL) runtests.pl
cache:
$(PERL) -MLitmus -MLitmus::Cache -e "Litmus::Cache::rebuildCache();"
@echo "Done";
clean:
rm -rf data
make install

View File

@@ -1,47 +0,0 @@
===Litmus===
If you're reading this, you've downloaded, received, or simply conjured
out of thin air, a copy of the Litmus testcase management system.
Presumably, you're reading this file because you have some sort of
question about Litmus. Hopefully, if we've done our job right, this file
ought to answer your questions.
Q: What is Litmus?
A: Litmus is a testcase management system. Its goal is to allow users to
enter software tests, run them, and view and manage the results. Along
the way, users can expect to be able to do queries and reports and have
access all the usual features they expect from a first-class web
application. The reality may be somewhat different than this goal.
Litmus is developed by mozilla.org.
Q: How do I install this dang thing?
A: You probably want the file called INSTALL.
Q: Where is the real documentation?
A: Hahahaha. What is this "documentation" you speak of? You might want
to check out the Litmus Wiki, which may or may not contain useful
information. See http://wiki.mozilla.org/Litmus.
Q: What needs to be done?
A: See http://wiki.mozilla.org/Litmus:Todo
Q: How much does it cost?
A: Nothing. Litmus is Free Software, licensed under the Mozilla Public
License.
Q: Wait. Isn't "testcase" two words?
A: Not here it isn't.
Q: Waaaaaaah. Why is Litmus written in Perl and not
PHP/Python/Java/Objective Pascal/Latin?
A: Because I know Perl. Duh. Also because Litmus uses some code from
Bugzilla, and it wouldn't be able to do this if it was written in some
other language. Camels are also some of the least buggy animals around,
as they swat flies away with their tails.
Q: I'm still confused. You didn't answer my question. I don't know what
to do. Help!
A: First of all, that's not a question. In any case, your best bet is
probably to email Zach Lipton <zach@zachlipton.com>, and if you ask
nicely and don't make too much of a pest of yourself, he'd be glad to
get you on the right track.

View File

@@ -1,246 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
# Hash refs for maintaining state in the search form.
my $defaults = undef;
my $order_bys = undef;
my $MAX_SORT_FIELDS = 10;
my $MAX_SEARCH_FIELDS = 10;
my $criteria = "Custom<br/>";
my $results;
my @where;
my @order_by;
my $limit;
my $where_criteria = "";
my $order_by_criteria = "";
my $limit_criteria = "";
if ($c->param) {
foreach my $param ($c->param) {
next if ($c->param($param) eq '');
if ($param =~ /sort_field(\d+)/) {
# We slot sort fields into the @order_by array based on their
# field_num. Empty array slots will be ignored when the SQL
# is built. We set an upper limit on the number of sort fields
# we can handle to prevent abuse.
my $field_num = $1;
next if ($field_num > $MAX_SORT_FIELDS);
my $sort_field = $c->param($param);
my $sort_order = 'ASC';
if ($c->param("sort_order$field_num")) {
$sort_order = $c->param("sort_order$field_num");
}
$order_by[$field_num] = { field => $sort_field,
direction => $sort_order};
} elsif ($param =~ /search_field(\d+)/) {
# We set an upper limit on the number of search fields
# we can handle to prevent abuse.
my $field_num = $1;
next if ($field_num > $MAX_SEARCH_FIELDS);
my $search_field = $c->param($param);
my $match_criteria = $c->param("match_criteria$field_num");
my $value = $c->param("search_value$field_num");
push @where, { 'field' => 'search_field',
'search_field' => $search_field,
'match_criteria' => $match_criteria,
'value' => $value};
$where_criteria .= "$search_field $match_criteria '$value'<br/>";
} elsif ($param eq 'start_date') {
my $start_date = $c->param($param);
$start_date =~ s/[^0-9A-Za-z ]/ /g;
my $end_date;
# Use 'now' as the default end date.
if ($c->param('end_date') and $c->param('end_date') ne '') {
$end_date = $c->param('end_date');
$end_date =~ s/[^0-9A-Za-z ]/ /g;
} else {
$end_date = 'Now';
}
push @where, { field => 'start_date',
value => $start_date};
push @where, { field => 'end_date',
value => $end_date};
$where_criteria .= "Date between '$start_date' and '$end_date'<br/>";
} elsif ($param eq 'trusted_only') {
push @where, {field => 'trusted_only',
value => 1};
$limit_criteria .= "Display trusted results only<br/>";
} elsif ($param eq "limit") {
$limit = $c->param($param);
next if ($limit == $Litmus::DB::Testresult::_num_results_default);
$limit_criteria .= "Limit to $limit results<br/>";
} elsif ($param eq 'branch') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Branch is \'".$c->param($param)."\'<br/>";
$defaults->{branch} = $c->param($param);
} elsif ($param eq 'locale') {
my $value = $c->param($param);
push @where, {field => 'locale',
value => $value};
$where_criteria .= "Locale is \'".$c->param($param)."\'<br/>";
$defaults->{locale} = $c->param($param);
} elsif ($param eq 'email') {
my $value = $c->param($param);
push @where, {field => 'email',
value => $value};
$where_criteria .= "Submitted By is \'".$c->param($param)."\'<br/>";
$defaults->{locale} = $c->param($param);
} elsif ($param eq 'product') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Product is \'".$c->param($param)."\'<br/>";
$defaults->{product} = $c->param($param);
} elsif ($param eq 'platform') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Platform is \'".$c->param($param)."\'<br/>";
$defaults->{platform} = $c->param($param);
} elsif ($param eq 'test_group') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Test group is \'".$c->param($param)."\'<br/>";
$defaults->{test_group} = $c->param($param);
} elsif ($param eq 'test_id') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Testcase ID# is \'".$c->param($param)."\'<br/>";
$defaults->{test_id} = $c->param($param);
} elsif ($param eq 'summary') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Summary like \'".$c->param($param)."\'<br/>";
$defaults->{summary} = $c->param($param);
} elsif ($param eq 'result_status') {
my $value = $c->param($param);
push @where, {field => $param,
value => $value};
$where_criteria .= "Status is \'".$c->param($param)."\'<br/>";
$defaults->{result_status} = $c->param($param);
} else {
# Skip unknown field
}
}
if ($where_criteria eq '' and
scalar(@order_by) == 0 and
$limit_criteria eq '') {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
} else {
foreach my $order_by_field (@order_by) {
next if (!$order_by_field);
$order_by_criteria .= "Order by $order_by_field->{field} $order_by_field->{direction}<br/>";
}
$criteria .= $where_criteria . $order_by_criteria . $limit_criteria;
$criteria =~ s/_/ /g;
$results = Litmus::DB::Testresult->getTestResults(\@where,
\@order_by,
$limit);
}
} else {
($criteria,$results) =
Litmus::DB::Testresult->getDefaultTestResults;
}
# Populate each of our form widgets for select/input.
# Set a default value as appropriate.
my $products = Litmus::FormWidget->getProducts;
my $platforms = Litmus::FormWidget->getUniquePlatforms;
my $test_groups = Litmus::FormWidget->getTestgroups;
my $testcases = Litmus::FormWidget->getTestcaseIDs;
my $result_statuses = Litmus::FormWidget->getResultStatuses;
my $branches = Litmus::FormWidget->getBranches;
my $locales = Litmus::FormWidget->getLocales;
my $users = Litmus::FormWidget->getUsers;
my $fields = Litmus::FormWidget->getFields;
my $match_criteria = Litmus::FormWidget->getMatchCriteria;
my $sort_fields = Litmus::FormWidget->getSortFields;
my $title = 'Advanced Search';
my $vars = {
title => $title,
criteria => $criteria,
products => $products,
platforms => $platforms,
test_groups => $test_groups,
testcases => $testcases,
result_statuses => $result_statuses,
branches => $branches,
locales => $locales,
users => $users,
fields => $fields,
match_criteria => $match_criteria,
sort_fields => $sort_fields,
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
Litmus->template()->process("reporting/advanced_search.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit 0;

View File

@@ -1,92 +0,0 @@
#!/usr/bin/perl -w
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.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 Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
use strict;
$|++;
use Litmus;
use Litmus::Auth;
use Litmus::Error;
use Litmus::DB::Testresult;
use Litmus::FormWidget;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
my $results;
if ($c->param and $c->param('status')) {
if ($c->param('status') =~ /pass/i or
$c->param('status') =~ /fail/i or
$c->param('status') =~ /unclear/i) {
$results = Litmus::DB::Testresult->getCommonResults($c->param('status'));
} else {
internalError("You must provide a valid status type: pass|fail|unclear");
exit 1;
}
} else {
internalError("You must provide a status type: pass|fail|unclear");
exit 1;
}
my $title;
if ($c->param('status') eq 'pass') {
$title = "Most Commonly Passed Testcases";
} elsif ($c->param('status') eq 'fail') {
$title = "Most Common Failures";
} elsif ($c->param('status') eq 'unclear') {
$title = "Testcases Most Frequently Marked As Unclear";
}
my $vars = {
title => $title,
status => $c->param('status'),
};
# Only include results if we have them.
if ($results and scalar @$results > 0) {
$vars->{results} = $results;
}
$vars->{"defaultemail"} = Litmus::Auth::getCookie();
Litmus->template()->process("reporting/common_results.tmpl", $vars) ||
internalError(Litmus->template()->error());
exit 0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

File diff suppressed because it is too large Load Diff

View File

@@ -1,105 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# 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 Litmus.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::DB::TestcaseSubgroup;
use Litmus::Auth;
use Litmus::Utils;
use CGI;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
# obviously, you need to be an admin to edit users...
Litmus::Auth::requireAdmin('edit_users.cgi');
if ($c->param('search_string')) {
# search for users:
my $users = Litmus::DB::User->search_FullTextMatches(
$c->param('search_string'),
$c->param('search_string'),
$c->param('search_string'));
my $vars = {
users => $users,
};
print $c->header();
Litmus->template()->process("admin/edit_users/search_results.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} elsif ($c->param('id')) {
# lookup a given user
my $uid = $c->param('id');
my $user = Litmus::DB::User->retrieve($uid);
print $c->header();
if (! $user) {
invalidInputError("Invalid user id: $uid");
}
my $vars = {
user => $user,
};
Litmus->template()->process("admin/edit_users/edit_user.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} elsif ($c->param('user_id')) {
# process changes to a user:
my $user = Litmus::DB::User->retrieve($c->param('user_id'));
print $c->header();
if (! $user) {
invalidInputError("Invalid user id: " . $c->param('user_id'));
}
$user->bugzilla_uid($c->param('bugzilla_uid'));
$user->email($c->param('edit_email'));
if ($c->param('edit_password') ne 'unchanged') {
# they changed the password, so let the auth folks know:
Litmus::Auth::changePassword($user, $c->param('edit_password'));
}
$user->realname($c->param('realname'));
$user->irc_nickname($c->param('irc_nickname'));
if ($c->param('enabled')) {
$user->enabled(1);
}
if ($c->param('is_admin')) {
$user->is_admin(1);
}
$user->authtoken($c->param('authtoken'));
$user->update();
my $vars = {
user => $user,
};
Litmus->template()->process("admin/edit_users/user_edited.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} else {
# we're here for the first time, so display the search form
my $vars = {
};
print $c->header();
Litmus->template()->process("admin/edit_users/search_users.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}

View File

@@ -1,82 +0,0 @@
#!/usr/bin/perl -w
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# 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 Litmus.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::DB::TestcaseSubgroup;
use Litmus::Auth;
use Litmus::Utils;
use CGI;
use Time::Piece::MySQL;
use Date::Manip;
Litmus->init();
my $c = Litmus->cgi();
# for the moment, you must be an admin to enter tests:
Litmus::Auth::requireAdmin('enter_test.cgi');
# if we're here for the first time, display the enter testcase form,
# otherwise, process the results:
if (! $c->param('enteringTestcase')) {
my $vars = {
};
print $c->header();
Litmus->template()->process("enter/enter.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
} else {
requireField('product', $c->param('product'));
requireField('test group', $c->param('testgroup'));
requireField('subgroup', $c->param('subgroup'));
requireField('summary', $c->param('summary'));
my $newtest = Litmus::DB::Testcase->create({
product => $c->param('product'),
summary => $c->param('summary'),
steps => $c->param('steps') ? $c->param('steps') : '',
expected_results => $c->param('expectedResults') ?
$c->param('expectedResults') : '',
author => Litmus::Auth::getCurrentUser(),
creation_date => &Date::Manip::UnixDate("now","%q"),
version => 1,
});
my $newtsg = Litmus::DB::TestcaseSubgroup->create({
test => $newtest,
subgroup => $c->param('subgroup'),
});
my $vars = {
test => $newtest,
};
print $c->header();
Litmus->template()->process("enter/enterComplete.html.tmpl", $vars) ||
internalError(Litmus->template()->error());
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Some files were not shown because too many files have changed in this diff Show More