Compare commits
3 Commits
IPC_BRANCH
...
Bugzilla_P
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b52a1dc48a | ||
|
|
48b5f960fd | ||
|
|
73bf11394f |
@@ -1,31 +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 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):
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = common daemon testmodule public src extensions build test
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,12 +0,0 @@
|
||||
DAEMON ONLY DIRECTORIES:
|
||||
daemon/
|
||||
testmodule/
|
||||
|
||||
CLIENT ONLY DIRECTORIES:
|
||||
public/
|
||||
src/
|
||||
build/
|
||||
test/
|
||||
|
||||
SHARED CODE DIRECTORY:
|
||||
common/
|
||||
@@ -1,76 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
LIBRARY_NAME = ipc
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = ipc
|
||||
REQUIRES = xpcom \
|
||||
string \
|
||||
necko \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = ipcModule.cpp
|
||||
EXPORTS = ipcCID.h
|
||||
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
$(DIST)/lib/$(LIB_PREFIX)ipc_s.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)ipccom_s.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)ipclock_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../src \
|
||||
-I$(srcdir)/../common \
|
||||
-I$(srcdir)/../extensions/lock/src \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(LIBS_DIR) \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,69 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcCID_h__
|
||||
#define ipcCID_h__
|
||||
|
||||
#define IPC_SERVICE_CLASSNAME \
|
||||
"ipcService"
|
||||
#define IPC_SERVICE_CONTRACTID \
|
||||
"@mozilla.org/ipc/service;1"
|
||||
#define IPC_SERVICE_CID \
|
||||
{ /* 9f12676a-5168-4a08-beb8-edf8a593a1ca */ \
|
||||
0x9f12676a, \
|
||||
0x5168, \
|
||||
0x4a08, \
|
||||
{0xbe, 0xb8, 0xed, 0xf8, 0xa5, 0x93, 0xa1, 0xca} \
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// extensions
|
||||
|
||||
// XXX replace CID with one from botbot
|
||||
#define IPC_LOCKSERVICE_CLASSNAME \
|
||||
"ipcLockService"
|
||||
#define IPC_LOCKSERVICE_CONTRACTID \
|
||||
"@mozilla.org/ipc/lock-service;1"
|
||||
#define IPC_LOCKSERVICE_CID \
|
||||
{ /* 7aaeaceb-b207-4b45-bbde-a13276401fc2 */ \
|
||||
0x7aaeaceb, \
|
||||
0xb207, \
|
||||
0x4b45, \
|
||||
{0xbb, 0xde, 0xa1, 0x32, 0x76, 0x40, 0x1f, 0xc2} \
|
||||
}
|
||||
|
||||
#endif // !ipcCID_h__
|
||||
@@ -1,141 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "nsIGenericFactory.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "ipcService.h"
|
||||
#include "ipcCID.h"
|
||||
#include "ipcConfig.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Define the contructor function for the objects
|
||||
//
|
||||
// NOTE: This creates an instance of objects by using the default constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcService, Init)
|
||||
|
||||
#if 0
|
||||
NS_METHOD
|
||||
ipcServiceRegisterProc(nsIComponentManager *aCompMgr,
|
||||
nsIFile *aPath,
|
||||
const char *registryLocation,
|
||||
const char *componentType,
|
||||
const nsModuleComponentInfo *info)
|
||||
{
|
||||
//
|
||||
// add ipcService to the XPCOM startup category
|
||||
//
|
||||
nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
|
||||
if (catman) {
|
||||
nsXPIDLCString prevEntry;
|
||||
catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcService",
|
||||
IPC_SERVICE_CONTRACTID, PR_TRUE, PR_TRUE,
|
||||
getter_Copies(prevEntry));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
ipcServiceUnregisterProc(nsIComponentManager *aCompMgr,
|
||||
nsIFile *aPath,
|
||||
const char *registryLocation,
|
||||
const nsModuleComponentInfo *info)
|
||||
{
|
||||
nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
|
||||
if (catman)
|
||||
catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID,
|
||||
IPC_SERVICE_CONTRACTID, PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include "ipcSocketProviderUnix.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(ipcSocketProviderUnix)
|
||||
|
||||
#define IPC_SOCKETPROVIDER_CLASSNAME \
|
||||
"ipcSocketProvider"
|
||||
#define IPC_SOCKETPROVIDER_CID \
|
||||
{ /* b888f500-ab5d-459c-aab0-bc61e844a503 */ \
|
||||
0xb888f500, \
|
||||
0xab5d, \
|
||||
0x459c, \
|
||||
{0xaa, 0xb0, 0xbc, 0x61, 0xe8, 0x44, 0xa5, 0x03} \
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// extensions
|
||||
|
||||
#include "ipcLockService.h"
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Define a table of CIDs implemented by this module along with other
|
||||
// information like the function to create an instance, contractid, and
|
||||
// class name.
|
||||
//-----------------------------------------------------------------------------
|
||||
static const nsModuleComponentInfo components[] = {
|
||||
{ IPC_SERVICE_CLASSNAME,
|
||||
IPC_SERVICE_CID,
|
||||
IPC_SERVICE_CONTRACTID,
|
||||
ipcServiceConstructor },
|
||||
/*
|
||||
ipcServiceRegisterProc,
|
||||
ipcServiceUnregisterProc },
|
||||
*/
|
||||
#ifdef XP_UNIX
|
||||
{ IPC_SOCKETPROVIDER_CLASSNAME,
|
||||
IPC_SOCKETPROVIDER_CID,
|
||||
NS_NETWORK_SOCKET_CONTRACTID_PREFIX IPC_SOCKET_TYPE,
|
||||
ipcSocketProviderUnixConstructor, },
|
||||
#endif
|
||||
//
|
||||
// extensions go here:
|
||||
//
|
||||
{ IPC_LOCKSERVICE_CLASSNAME,
|
||||
IPC_LOCKSERVICE_CID,
|
||||
IPC_LOCKSERVICE_CONTRACTID,
|
||||
ipcLockServiceConstructor },
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Implement the NSGetModule() exported function for your module
|
||||
// and the entire implementation of the module object.
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMPL_NSGETMODULE(ipcModule, components)
|
||||
@@ -1,70 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
LIBRARY_NAME = ipccom_s
|
||||
EXPORT_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
MODULE_NAME = ipc
|
||||
|
||||
REQUIRES = \
|
||||
xpcom \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
ipcLog.cpp \
|
||||
ipcConfig.cpp \
|
||||
ipcMessage.cpp \
|
||||
ipcMessagePrimitives.cpp \
|
||||
ipcStringList.cpp \
|
||||
ipcIDList.cpp \
|
||||
ipcm.cpp
|
||||
|
||||
EXPORTS = \
|
||||
ipcMessage.h \
|
||||
ipcMessageQ.h \
|
||||
ipcm.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,75 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ***** */
|
||||
|
||||
#ifdef XP_WIN
|
||||
#else
|
||||
#include <string.h>
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "prenv.h"
|
||||
#include "plstr.h"
|
||||
|
||||
static const char kDefaultSocketPrefix[] = "/tmp/.mozilla";
|
||||
static const char kDefaultSocketSuffix[] = "-ipc/ipcd";
|
||||
|
||||
void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen)
|
||||
{
|
||||
const char *logName;
|
||||
int len;
|
||||
|
||||
PL_strncpyz(buf, kDefaultSocketPrefix, bufLen);
|
||||
buf += (sizeof(kDefaultSocketPrefix) - 1);
|
||||
bufLen -= (sizeof(kDefaultSocketPrefix) - 1);
|
||||
|
||||
logName = PR_GetEnv("LOGNAME");
|
||||
if (!logName || !logName[0]) {
|
||||
logName = PR_GetEnv("USER");
|
||||
if (!logName || !logName[0]) {
|
||||
LOG(("could not determine username from environment\n"));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
PL_strncpyz(buf, logName, bufLen);
|
||||
len = strlen(logName);
|
||||
buf += len;
|
||||
bufLen -= len;
|
||||
|
||||
end:
|
||||
PL_strncpyz(buf, kDefaultSocketSuffix, bufLen);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcProto_h__
|
||||
#define ipcProto_h__
|
||||
|
||||
#if defined(XP_WIN)
|
||||
//
|
||||
// use WM_COPYDATA messages
|
||||
//
|
||||
#include "prprf.h"
|
||||
|
||||
#define IPC_WINDOW_CLASS "Mozilla:IPCWindowClass"
|
||||
#define IPC_WINDOW_NAME "Mozilla:IPCWindow"
|
||||
#define IPC_CLIENT_WINDOW_CLASS "Mozilla:IPCAppWindowClass"
|
||||
#define IPC_CLIENT_WINDOW_NAME_PREFIX "Mozilla:IPCAppWindow:"
|
||||
#define IPC_SYNC_EVENT_NAME "Local\\MozillaIPCSyncEvent"
|
||||
#define IPC_DAEMON_APP_NAME "mozipcd.exe"
|
||||
#define IPC_PATH_SEP_CHAR '\\'
|
||||
#define IPC_MODULES_DIR "ipc\\modules"
|
||||
|
||||
#define IPC_CLIENT_WINDOW_NAME_MAXLEN (sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20)
|
||||
|
||||
// writes client name into buf. buf must be at least
|
||||
// IPC_CLIENT_WINDOW_NAME_MAXLEN bytes in length.
|
||||
inline void IPC_GetClientWindowName(PRUint32 pid, char *buf)
|
||||
{
|
||||
PR_snprintf(buf, IPC_CLIENT_WINDOW_NAME_MAXLEN, "%s%u",
|
||||
IPC_CLIENT_WINDOW_NAME_PREFIX, pid);
|
||||
}
|
||||
|
||||
#else
|
||||
#include "prtypes.h"
|
||||
//
|
||||
// use UNIX domain socket
|
||||
//
|
||||
#define IPC_PORT 0
|
||||
#define IPC_SOCKET_TYPE "ipc"
|
||||
#define IPC_DAEMON_APP_NAME "mozipcd"
|
||||
#define IPC_PATH_SEP_CHAR '/'
|
||||
#define IPC_MODULES_DIR "ipc/modules"
|
||||
|
||||
void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // !ipcProto_h__
|
||||
@@ -1,62 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "ipcIDList.h"
|
||||
|
||||
ipcIDNode *
|
||||
ipcIDList::FindNode(ipcIDNode *node, const nsID &id)
|
||||
{
|
||||
while (node) {
|
||||
if (node->Equals(id))
|
||||
return node;
|
||||
node = node->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipcIDNode *
|
||||
ipcIDList::FindNodeBefore(ipcIDNode *node, const nsID &id)
|
||||
{
|
||||
ipcIDNode *prev = NULL;
|
||||
while (node) {
|
||||
if (node->Equals(id))
|
||||
return prev;
|
||||
prev = node;
|
||||
node = node->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcIDList_h__
|
||||
#define ipcIDList_h__
|
||||
|
||||
#include "nsID.h"
|
||||
#include "ipcList.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsID node
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcIDNode
|
||||
{
|
||||
public:
|
||||
ipcIDNode(const nsID &id)
|
||||
: mID(id)
|
||||
{ }
|
||||
|
||||
const nsID &Value() const { return mID; }
|
||||
|
||||
PRBool Equals(const nsID &id) const { return mID.Equals(id); }
|
||||
|
||||
class ipcIDNode *mNext;
|
||||
private:
|
||||
nsID mID;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// singly-linked list of nsIDs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcIDList : public ipcList<ipcIDNode>
|
||||
{
|
||||
public:
|
||||
typedef ipcList<ipcIDNode> Super;
|
||||
|
||||
void Prepend(const nsID &id)
|
||||
{
|
||||
Super::Prepend(new ipcIDNode(id));
|
||||
}
|
||||
|
||||
void Append(const nsID &id)
|
||||
{
|
||||
Super::Append(new ipcIDNode(id));
|
||||
}
|
||||
|
||||
const ipcIDNode *Find(const nsID &id) const
|
||||
{
|
||||
return FindNode(mHead, id);
|
||||
}
|
||||
|
||||
void FindAndDelete(const nsID &id)
|
||||
{
|
||||
ipcIDNode *node = FindNodeBefore(mHead, id);
|
||||
if (node)
|
||||
DeleteAfter(node);
|
||||
else
|
||||
DeleteFirst();
|
||||
}
|
||||
|
||||
private:
|
||||
static ipcIDNode *FindNode (ipcIDNode *head, const nsID &id);
|
||||
static ipcIDNode *FindNodeBefore(ipcIDNode *head, const nsID &id);
|
||||
};
|
||||
|
||||
#endif // !ipcIDList_h__
|
||||
@@ -1,176 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcList_h__
|
||||
#define ipcList_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// simple list of singly-linked objects. class T must have the following
|
||||
// structure:
|
||||
//
|
||||
// class T {
|
||||
// ...
|
||||
// public:
|
||||
// T *mNext;
|
||||
// };
|
||||
//
|
||||
// objects added to the list must be allocated with operator new.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
class ipcList
|
||||
{
|
||||
public:
|
||||
ipcList()
|
||||
: mHead(NULL)
|
||||
, mTail(NULL)
|
||||
{ }
|
||||
~ipcList() { DeleteAll(); }
|
||||
|
||||
//
|
||||
// prepends obj at the beginning of the list.
|
||||
//
|
||||
void Prepend(T *obj)
|
||||
{
|
||||
obj->mNext = mHead;
|
||||
mHead = obj;
|
||||
if (!mTail)
|
||||
mTail = mHead;
|
||||
}
|
||||
|
||||
//
|
||||
// appends obj to the end of the list.
|
||||
//
|
||||
void Append(T *obj)
|
||||
{
|
||||
obj->mNext = NULL;
|
||||
if (mTail) {
|
||||
mTail->mNext = obj;
|
||||
mTail = obj;
|
||||
}
|
||||
else
|
||||
mTail = mHead = obj;
|
||||
}
|
||||
|
||||
//
|
||||
// inserts b into the list after a.
|
||||
//
|
||||
void InsertAfter(T *a, T *b)
|
||||
{
|
||||
b->mNext = a->mNext;
|
||||
a->mNext = b;
|
||||
if (mTail == a)
|
||||
mTail = b;
|
||||
}
|
||||
|
||||
//
|
||||
// removes first element w/o deleting it
|
||||
//
|
||||
void RemoveFirst()
|
||||
{
|
||||
if (mHead)
|
||||
AdvanceHead();
|
||||
}
|
||||
|
||||
//
|
||||
// removes element after the given element w/o deleting it
|
||||
//
|
||||
void RemoveAfter(T *obj)
|
||||
{
|
||||
T *rej = obj->mNext;
|
||||
if (rej) {
|
||||
obj->mNext = rej->mNext;
|
||||
if (rej == mTail)
|
||||
mTail = obj;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deletes first element
|
||||
//
|
||||
void DeleteFirst()
|
||||
{
|
||||
T *first = mHead;
|
||||
if (first) {
|
||||
AdvanceHead();
|
||||
delete first;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deletes element after the given element
|
||||
//
|
||||
void DeleteAfter(T *obj)
|
||||
{
|
||||
T *rej = obj->mNext;
|
||||
if (rej) {
|
||||
RemoveAfter(obj);
|
||||
delete rej;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deletes all elements
|
||||
//
|
||||
void DeleteAll()
|
||||
{
|
||||
while (mHead)
|
||||
DeleteFirst();
|
||||
}
|
||||
|
||||
const T *First() const { return mHead; }
|
||||
T *First() { return mHead; }
|
||||
const T *Last() const { return mTail; }
|
||||
T *Last() { return mTail; }
|
||||
|
||||
PRBool IsEmpty() const { return mHead == NULL; }
|
||||
|
||||
protected:
|
||||
void AdvanceHead()
|
||||
{
|
||||
mHead = mHead->mNext;
|
||||
if (!mHead)
|
||||
mTail = NULL;
|
||||
}
|
||||
|
||||
T *mHead;
|
||||
T *mTail;
|
||||
};
|
||||
|
||||
#endif // !ipcList_h__
|
||||
@@ -1,115 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "ipcLog.h"
|
||||
|
||||
#ifdef IPC_LOGGING
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "prenv.h"
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
|
||||
PRBool ipcLogEnabled = PR_FALSE;
|
||||
char ipcLogPrefix[10] = {0};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// UNIX
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef XP_UNIX
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static inline PRUint32
|
||||
WritePrefix(char *buf, PRUint32 bufLen)
|
||||
{
|
||||
return PR_snprintf(buf, bufLen, "[%u] %s ",
|
||||
(unsigned) getpid(),
|
||||
ipcLogPrefix);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
|
||||
static inline PRUint32
|
||||
WritePrefix(char *buf, PRUint32 bufLen)
|
||||
{
|
||||
return PR_snprintf(buf, bufLen, "[%u:%u] %s ",
|
||||
GetCurrentProcessId(),
|
||||
GetCurrentThreadId(),
|
||||
ipcLogPrefix);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// logging API impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
IPC_InitLog(const char *prefix)
|
||||
{
|
||||
if (PR_GetEnv("IPC_LOG_ENABLE")) {
|
||||
ipcLogEnabled = PR_TRUE;
|
||||
PL_strncpyz(ipcLogPrefix, prefix, sizeof(ipcLogPrefix));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPC_Log(const char *fmt, ... )
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
PRUint32 nb = 0;
|
||||
char buf[512];
|
||||
|
||||
if (ipcLogPrefix[0])
|
||||
nb = WritePrefix(buf, sizeof(buf));
|
||||
|
||||
PR_vsnprintf(buf + nb, sizeof(buf) - nb, fmt, ap);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
fwrite(buf, strlen(buf), 1, stdout);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcLog_h__
|
||||
#define ipcLog_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
#define IPC_LOGGING
|
||||
#ifdef IPC_LOGGING
|
||||
|
||||
extern PRBool ipcLogEnabled;
|
||||
extern void IPC_InitLog(const char *prefix);
|
||||
extern void IPC_Log(const char *fmt, ...);
|
||||
|
||||
#define IPC_LOG(_args) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (ipcLogEnabled) \
|
||||
IPC_Log _args; \
|
||||
PR_END_MACRO
|
||||
|
||||
#define LOG(args) IPC_LOG(args)
|
||||
#define LOG_ENABLED() ipcLogEnabled
|
||||
|
||||
#else
|
||||
#define IPC_InitLog(prefix)
|
||||
#define LOG(args)
|
||||
#define LOG_ENABLED() (0)
|
||||
#endif
|
||||
|
||||
#endif // !ipcLog_h__
|
||||
@@ -1,245 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prlog.h"
|
||||
#include "ipcMessage.h"
|
||||
|
||||
ipcMessage::~ipcMessage()
|
||||
{
|
||||
if (mMsgHdr)
|
||||
free(mMsgHdr);
|
||||
}
|
||||
|
||||
void
|
||||
ipcMessage::Reset()
|
||||
{
|
||||
if (mMsgHdr) {
|
||||
free(mMsgHdr);
|
||||
mMsgHdr = NULL;
|
||||
}
|
||||
|
||||
mMsgOffset = 0;
|
||||
mMsgComplete = PR_FALSE;
|
||||
}
|
||||
|
||||
ipcMessage *
|
||||
ipcMessage::Clone() const
|
||||
{
|
||||
ipcMessage *clone = new ipcMessage();
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
// copy buf if non-null
|
||||
if (mMsgHdr) {
|
||||
clone->mMsgHdr = (ipcMessageHeader *) malloc(mMsgHdr->mLen);
|
||||
memcpy(clone->mMsgHdr, mMsgHdr, mMsgHdr->mLen);
|
||||
}
|
||||
else
|
||||
clone->mMsgHdr = NULL;
|
||||
|
||||
clone->mMsgOffset = mMsgOffset;
|
||||
clone->mMsgComplete = mMsgComplete;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
PRStatus
|
||||
ipcMessage::Init(const nsID &target, const char *data, PRUint32 dataLen)
|
||||
{
|
||||
if (mMsgHdr)
|
||||
free(mMsgHdr);
|
||||
mMsgComplete = PR_FALSE;
|
||||
|
||||
// allocate message data
|
||||
PRUint32 msgLen = IPC_MSG_HEADER_SIZE + dataLen;
|
||||
mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
|
||||
if (!mMsgHdr) {
|
||||
mMsgHdr = NULL;
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
// fill in message data
|
||||
mMsgHdr->mLen = msgLen;
|
||||
mMsgHdr->mVersion = IPC_MSG_VERSION;
|
||||
mMsgHdr->mFlags = 0;
|
||||
mMsgHdr->mTarget = target;
|
||||
|
||||
if (data)
|
||||
SetData(0, data, dataLen);
|
||||
|
||||
mMsgComplete = PR_TRUE;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
PRStatus
|
||||
ipcMessage::SetData(PRUint32 offset, const char *data, PRUint32 dataLen)
|
||||
{
|
||||
PR_ASSERT(mMsgHdr != NULL);
|
||||
|
||||
if (offset + dataLen > DataLen())
|
||||
return PR_FAILURE;
|
||||
|
||||
memcpy((char *) Data() + offset, data, dataLen);
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
PRBool
|
||||
ipcMessage::Equals(const nsID &target, const char *data, PRUint32 dataLen) const
|
||||
{
|
||||
return mMsgComplete &&
|
||||
mMsgHdr->mTarget.Equals(target) &&
|
||||
DataLen() == dataLen &&
|
||||
memcmp(Data(), data, dataLen) == 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
ipcMessage::Equals(const ipcMessage *msg) const
|
||||
{
|
||||
PRUint32 msgLen = MsgLen();
|
||||
return mMsgComplete && msg->mMsgComplete &&
|
||||
msgLen == msg->MsgLen() &&
|
||||
memcmp(MsgBuf(), msg->MsgBuf(), msgLen) == 0;
|
||||
}
|
||||
|
||||
PRStatus
|
||||
ipcMessage::WriteTo(char *buf,
|
||||
PRUint32 bufLen,
|
||||
PRUint32 *bytesWritten,
|
||||
PRBool *complete)
|
||||
{
|
||||
if (!mMsgComplete)
|
||||
return PR_FAILURE;
|
||||
|
||||
if (mMsgOffset == MsgLen()) {
|
||||
*bytesWritten = 0;
|
||||
*complete = PR_TRUE;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
PRUint32 count = MsgLen() - mMsgOffset;
|
||||
if (count > bufLen)
|
||||
count = bufLen;
|
||||
|
||||
memcpy(buf, MsgBuf() + mMsgOffset, count);
|
||||
mMsgOffset += count;
|
||||
|
||||
*bytesWritten = count;
|
||||
*complete = (mMsgOffset == MsgLen());
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
PRStatus
|
||||
ipcMessage::ReadFrom(const char *buf,
|
||||
PRUint32 bufLen,
|
||||
PRUint32 *bytesRead,
|
||||
PRBool *complete)
|
||||
{
|
||||
*bytesRead = 0;
|
||||
|
||||
if (mMsgComplete) {
|
||||
*complete = PR_TRUE;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
if (mMsgHdr) {
|
||||
// appending data to buffer
|
||||
if (mMsgOffset < sizeof(PRUint32)) {
|
||||
// we haven't learned the message length yet
|
||||
if (mMsgOffset + bufLen < sizeof(PRUint32)) {
|
||||
// we still don't know the length of the message!
|
||||
memcpy((char *) mMsgHdr + mMsgOffset, buf, bufLen);
|
||||
mMsgOffset += bufLen;
|
||||
*bytesRead = bufLen;
|
||||
*complete = PR_FALSE;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
// we now have enough data to determine the message length
|
||||
PRUint32 count = sizeof(PRUint32) - mMsgOffset;
|
||||
memcpy((char *) MsgBuf() + mMsgOffset, buf, count);
|
||||
mMsgOffset += count;
|
||||
buf += count;
|
||||
bufLen -= count;
|
||||
*bytesRead = count;
|
||||
|
||||
if (MsgLen() > IPC_MSG_GUESSED_SIZE) {
|
||||
// realloc message buffer to the correct size
|
||||
mMsgHdr = (ipcMessageHeader *) realloc(mMsgHdr, MsgLen());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (bufLen < sizeof(PRUint32)) {
|
||||
// not enough data available in buffer to determine allocation size
|
||||
// allocate a partial buffer
|
||||
PRUint32 msgLen = IPC_MSG_GUESSED_SIZE;
|
||||
mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
|
||||
if (!mMsgHdr)
|
||||
return PR_FAILURE;
|
||||
memcpy(mMsgHdr, buf, bufLen);
|
||||
mMsgOffset = bufLen;
|
||||
*bytesRead = bufLen;
|
||||
*complete = PR_FALSE;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
PRUint32 msgLen = *(PRUint32 *) buf;
|
||||
mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
|
||||
if (!mMsgHdr)
|
||||
return PR_FAILURE;
|
||||
mMsgHdr->mLen = msgLen;
|
||||
mMsgOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// have mMsgHdr at this point
|
||||
|
||||
PRUint32 count = MsgLen() - mMsgOffset;
|
||||
if (count > bufLen)
|
||||
count = bufLen;
|
||||
|
||||
memcpy((char *) mMsgHdr + mMsgOffset, buf, count);
|
||||
mMsgOffset += count;
|
||||
*bytesRead += count;
|
||||
|
||||
*complete = mMsgComplete = (mMsgOffset == MsgLen());
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcMessage_h__
|
||||
#define ipcMessage_h__
|
||||
|
||||
#include "nsID.h"
|
||||
|
||||
//
|
||||
// ipc message format:
|
||||
//
|
||||
// +------------------------------------+
|
||||
// | DWORD : length |
|
||||
// +------------------+-----------------+
|
||||
// | WORD : version | WORD : flags |
|
||||
// +------------------+-----------------+
|
||||
// | nsID : target |
|
||||
// +------------------------------------+
|
||||
// | data |
|
||||
// +------------------------------------+
|
||||
//
|
||||
// header is 24 bytes. flags are defined below. default value of flags is
|
||||
// zero. protocol implementations should ignore unrecognized flags. target
|
||||
// is a 16 byte UUID indicating the intended receiver of this message.
|
||||
//
|
||||
|
||||
struct ipcMessageHeader
|
||||
{
|
||||
PRUint32 mLen;
|
||||
PRUint16 mVersion;
|
||||
PRUint16 mFlags;
|
||||
nsID mTarget;
|
||||
};
|
||||
|
||||
#define IPC_MSG_VERSION (0x1)
|
||||
#define IPC_MSG_HEADER_SIZE (sizeof(ipcMessageHeader))
|
||||
#define IPC_MSG_GUESSED_SIZE (IPC_MSG_HEADER_SIZE + 64)
|
||||
|
||||
//
|
||||
// the IPC message protocol supports synchronous messages. these messages can
|
||||
// only be sent from a client to the daemon. a daemon module cannot send a
|
||||
// synchronous message. the client sets the SYNC_QUERY flag to indicate that
|
||||
// it is expecting a response with the SYNC_REPLY flag set.
|
||||
//
|
||||
#define IPC_MSG_FLAG_SYNC_QUERY (0x1)
|
||||
#define IPC_MSG_FLAG_SYNC_REPLY (0x2)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcMessage
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcMessage
|
||||
{
|
||||
public:
|
||||
ipcMessage()
|
||||
: mNext(NULL)
|
||||
, mMsgHdr(NULL)
|
||||
, mMsgOffset(0)
|
||||
, mMsgComplete(PR_FALSE)
|
||||
{ }
|
||||
ipcMessage(const nsID &target, const char *data, PRUint32 dataLen)
|
||||
: mNext(NULL)
|
||||
, mMsgHdr(NULL)
|
||||
, mMsgOffset(0)
|
||||
{ Init(target, data, dataLen); }
|
||||
~ipcMessage();
|
||||
|
||||
//
|
||||
// reset message to uninitialized state
|
||||
//
|
||||
void Reset();
|
||||
|
||||
//
|
||||
// create a copy of this message
|
||||
//
|
||||
ipcMessage *Clone() const;
|
||||
|
||||
//
|
||||
// initialize message
|
||||
//
|
||||
// param:
|
||||
// topic - message topic string
|
||||
// data - message data (may be null to leave data uninitialized)
|
||||
// dataLen - message data len
|
||||
//
|
||||
PRStatus Init(const nsID &target, const char *data, PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// copy data into the message's data section, starting from offset. this
|
||||
// function can be used to write only a portion of the message's data.
|
||||
//
|
||||
// param:
|
||||
// offset - destination offset
|
||||
// data - data to write
|
||||
// dataLen - number of bytes to write
|
||||
//
|
||||
PRStatus SetData(PRUint32 offset, const char *data, PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// access message flags
|
||||
//
|
||||
void SetFlag(PRUint16 flag) { mMsgHdr->mFlags |= flag; }
|
||||
void ClearFlag(PRUint16 flag) { mMsgHdr->mFlags &= ~flag; }
|
||||
PRBool TestFlag(PRUint16 flag) const { return mMsgHdr->mFlags & flag; }
|
||||
|
||||
//
|
||||
// if true, the message is complete and the members of the message
|
||||
// can be accessed.
|
||||
//
|
||||
PRBool IsComplete() const { return mMsgComplete; }
|
||||
|
||||
//
|
||||
// readonly accessors
|
||||
//
|
||||
const ipcMessageHeader *Header() const { return mMsgHdr; }
|
||||
const nsID &Target() const { return mMsgHdr->mTarget; }
|
||||
const char *Data() const { return (char *) mMsgHdr + IPC_MSG_HEADER_SIZE; }
|
||||
PRUint32 DataLen() const { return mMsgHdr->mLen - IPC_MSG_HEADER_SIZE; }
|
||||
const char *MsgBuf() const { return (char *) mMsgHdr; }
|
||||
PRUint32 MsgLen() const { return mMsgHdr->mLen; }
|
||||
|
||||
//
|
||||
// message comparison functions
|
||||
//
|
||||
// param:
|
||||
// topic - message topic (may be null)
|
||||
// data - message data (must not be null)
|
||||
// dataLen - message data length
|
||||
//
|
||||
PRBool Equals(const nsID &target, const char *data, PRUint32 dataLen) const;
|
||||
PRBool Equals(const ipcMessage *msg) const;
|
||||
|
||||
//
|
||||
// write the message to a buffer segment; segment need not be large
|
||||
// enough to hold entire message. called repeatedly.
|
||||
//
|
||||
PRStatus WriteTo(char *buf,
|
||||
PRUint32 bufLen,
|
||||
PRUint32 *bytesWritten,
|
||||
PRBool *complete);
|
||||
|
||||
//
|
||||
// read the message from a buffer segment; segment need not contain
|
||||
// the entire messgae. called repeatedly.
|
||||
//
|
||||
PRStatus ReadFrom(const char *buf,
|
||||
PRUint32 bufLen,
|
||||
PRUint32 *bytesRead,
|
||||
PRBool *complete);
|
||||
|
||||
//
|
||||
// a message can be added to a singly-linked list.
|
||||
//
|
||||
class ipcMessage *mNext;
|
||||
|
||||
private:
|
||||
ipcMessageHeader *mMsgHdr;
|
||||
|
||||
// XXX document me
|
||||
PRUint32 mMsgOffset;
|
||||
PRPackedBool mMsgComplete;
|
||||
};
|
||||
|
||||
#endif // !ipcMessage_h__
|
||||
@@ -1,58 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <string.h>
|
||||
#include "ipcMessagePrimitives.h"
|
||||
|
||||
ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target,
|
||||
PRUint32 first,
|
||||
const char *second)
|
||||
{
|
||||
int sLen = strlen(second);
|
||||
Init(target, NULL, sizeof(first) + sLen + 1);
|
||||
SetData(0, (char *) &first, sizeof(first));
|
||||
SetData(sizeof(first), second, sLen + 1);
|
||||
}
|
||||
|
||||
ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target,
|
||||
PRUint32 first,
|
||||
const nsID &second)
|
||||
{
|
||||
Init(target, NULL, sizeof(first) + sizeof(nsID));
|
||||
SetData(0, (char *) &first, sizeof(first));
|
||||
SetData(sizeof(first), (char *) &second, sizeof(nsID));
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcMessagePrimitives_h__
|
||||
#define ipcMessagePrimitives_h__
|
||||
|
||||
#include "ipcMessage.h"
|
||||
|
||||
class ipcMessage_DWORD : public ipcMessage
|
||||
{
|
||||
public:
|
||||
ipcMessage_DWORD(const nsID &target, PRUint32 first)
|
||||
{
|
||||
Init(target, (char *) &first, sizeof(first));
|
||||
}
|
||||
|
||||
PRUint32 First() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[0];
|
||||
}
|
||||
};
|
||||
|
||||
class ipcMessage_DWORD_DWORD : public ipcMessage
|
||||
{
|
||||
public:
|
||||
ipcMessage_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second)
|
||||
{
|
||||
PRUint32 data[2] = { first, second };
|
||||
Init(target, (char *) data, sizeof(data));
|
||||
}
|
||||
|
||||
PRUint32 First() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[0];
|
||||
}
|
||||
|
||||
PRUint32 Second() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[1];
|
||||
}
|
||||
};
|
||||
|
||||
class ipcMessage_DWORD_STR : public ipcMessage
|
||||
{
|
||||
public:
|
||||
ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second);
|
||||
|
||||
PRUint32 First() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[0];
|
||||
}
|
||||
|
||||
const char *Second() const
|
||||
{
|
||||
return Data() + sizeof(PRUint32);
|
||||
}
|
||||
};
|
||||
|
||||
class ipcMessage_DWORD_ID : public ipcMessage
|
||||
{
|
||||
public:
|
||||
ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second);
|
||||
|
||||
PRUint32 First() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[0];
|
||||
}
|
||||
|
||||
const nsID &Second() const
|
||||
{
|
||||
return * (const nsID *) (Data() + sizeof(PRUint32));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !ipcMessagePrimitives_h__
|
||||
@@ -1,46 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcMessageQ_h__
|
||||
#define ipcMessageQ_h__
|
||||
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcList.h"
|
||||
|
||||
typedef ipcList<ipcMessage> ipcMessageQ;
|
||||
|
||||
#endif // !ipcMessageQ_h__
|
||||
@@ -1,66 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcMessageUtils_h__
|
||||
#define ipcMessageUtils_h__
|
||||
|
||||
class ipcMessage;
|
||||
|
||||
//
|
||||
// given code like this:
|
||||
//
|
||||
// const ipcmMessageClientID *msg = (const ipcmMessageClientID *) rawMsg;
|
||||
//
|
||||
// we can write:
|
||||
//
|
||||
// ipcMessageCast<ipcmMessageClientID> msg(rawMsg);
|
||||
//
|
||||
// XXX ipcMessageCast is probably not the best name for this class.
|
||||
//
|
||||
template<class T>
|
||||
class ipcMessageCast
|
||||
{
|
||||
public:
|
||||
ipcMessageCast() : mPtr(NULL) {}
|
||||
ipcMessageCast(const ipcMessage *ptr) : mPtr((const T *) ptr) {}
|
||||
void operator=(const ipcMessage *ptr) { mPtr = (const T *) ptr; }
|
||||
const T *operator->() { return mPtr; }
|
||||
private:
|
||||
const T *mPtr;
|
||||
};
|
||||
|
||||
#endif // !ipcMessageUtils_h__
|
||||
@@ -1,80 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "ipcStringList.h"
|
||||
|
||||
void *
|
||||
ipcStringNode::operator new(size_t size, const char *str) CPP_THROW_NEW
|
||||
{
|
||||
int len = strlen(str);
|
||||
|
||||
size += len;
|
||||
|
||||
ipcStringNode *node = (ipcStringNode *) ::operator new(size);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
node->mNext = NULL;
|
||||
memcpy(node->mData, str, len);
|
||||
node->mData[len] = '\0';
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
ipcStringNode *
|
||||
ipcStringList::FindNode(ipcStringNode *node, const char *str)
|
||||
{
|
||||
while (node) {
|
||||
if (node->Equals(str))
|
||||
return node;
|
||||
node = node->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipcStringNode *
|
||||
ipcStringList::FindNodeBefore(ipcStringNode *node, const char *str)
|
||||
{
|
||||
ipcStringNode *prev = NULL;
|
||||
while (node) {
|
||||
if (node->Equals(str))
|
||||
return prev;
|
||||
prev = node;
|
||||
node = node->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcStringList_h__
|
||||
#define ipcStringList_h__
|
||||
|
||||
#include <string.h>
|
||||
#include "plstr.h"
|
||||
#include "ipcList.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// string node
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcStringNode
|
||||
{
|
||||
public:
|
||||
ipcStringNode() {}
|
||||
|
||||
const char *Value() const { return mData; }
|
||||
|
||||
PRBool Equals(const char *val) const { return strcmp(mData, val) == 0; }
|
||||
PRBool EqualsIgnoreCase(const char *val) const { return PL_strcasecmp(mData, val) == 0; }
|
||||
|
||||
class ipcStringNode *mNext;
|
||||
private:
|
||||
void *operator new(size_t size, const char *str) CPP_THROW_NEW;
|
||||
|
||||
// this is actually bigger
|
||||
char mData[1];
|
||||
|
||||
friend class ipcStringList;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// singly-linked list of strings
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcStringList : public ipcList<ipcStringNode>
|
||||
{
|
||||
public:
|
||||
typedef ipcList<ipcStringNode> Super;
|
||||
|
||||
void Prepend(const char *str)
|
||||
{
|
||||
Super::Prepend(new (str) ipcStringNode());
|
||||
}
|
||||
|
||||
void Append(const char *str)
|
||||
{
|
||||
Super::Append(new (str) ipcStringNode());
|
||||
}
|
||||
|
||||
const ipcStringNode *Find(const char *str) const
|
||||
{
|
||||
return FindNode(mHead, str);
|
||||
}
|
||||
|
||||
void FindAndDelete(const char *str)
|
||||
{
|
||||
ipcStringNode *node = FindNodeBefore(mHead, str);
|
||||
if (node)
|
||||
DeleteAfter(node);
|
||||
else
|
||||
DeleteFirst();
|
||||
}
|
||||
|
||||
private:
|
||||
static ipcStringNode *FindNode (ipcStringNode *head, const char *str);
|
||||
static ipcStringNode *FindNodeBefore(ipcStringNode *head, const char *str);
|
||||
};
|
||||
|
||||
#endif // !ipcStringList_h__
|
||||
@@ -1,277 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <string.h>
|
||||
#include "ipcm.h"
|
||||
#include "prlog.h"
|
||||
|
||||
const nsID IPCM_TARGET =
|
||||
{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */
|
||||
0x753ca8ff,
|
||||
0xc8c2,
|
||||
0x4601,
|
||||
{0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50}
|
||||
};
|
||||
|
||||
//
|
||||
// MSG_TYPE values
|
||||
//
|
||||
const PRUint32 ipcmMessagePing::MSG_TYPE = IPCM_MSG_TYPE_PING;
|
||||
const PRUint32 ipcmMessageError::MSG_TYPE = IPCM_MSG_TYPE_ERROR;
|
||||
const PRUint32 ipcmMessageClientHello::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_HELLO;
|
||||
const PRUint32 ipcmMessageClientID::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ID;
|
||||
const PRUint32 ipcmMessageClientInfo::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_INFO;
|
||||
const PRUint32 ipcmMessageClientAddName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_NAME;
|
||||
const PRUint32 ipcmMessageClientDelName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_NAME;
|
||||
const PRUint32 ipcmMessageClientAddTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_TARGET;
|
||||
const PRUint32 ipcmMessageClientDelTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_TARGET;
|
||||
const PRUint32 ipcmMessageQueryClientByName::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME;
|
||||
const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO;
|
||||
const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD;
|
||||
|
||||
//
|
||||
// CLIENT_INFO message
|
||||
//
|
||||
// +-----------------------------------------+
|
||||
// | DWORD : MSG_TYPE |
|
||||
// +--------------------+--------------------+
|
||||
// | DWORD : clientID |
|
||||
// +--------------------+--------------------+
|
||||
// | WORD : nameStart | WORD : nameCount |
|
||||
// +--------------------+--------------------+
|
||||
// | WORD : targetStart | WORD : targetCount |
|
||||
// +--------------------+--------------------+
|
||||
// | name[0] | (null byte) |
|
||||
// +--------------------+--------------------+
|
||||
// . . .
|
||||
// . . .
|
||||
// +--------------------+--------------------+
|
||||
// | name[count - 1] | (null byte) |
|
||||
// +--------------------+--------------------+
|
||||
// | target[0] |
|
||||
// +-----------------------------------------+
|
||||
// . . .
|
||||
// . . .
|
||||
// +-----------------------------------------+
|
||||
// | target[count - 1] |
|
||||
// +-----------------------------------------+
|
||||
//
|
||||
|
||||
struct ipcmClientInfoHeader
|
||||
{
|
||||
PRUint32 mType;
|
||||
PRUint32 mID;
|
||||
PRUint16 mNameStart;
|
||||
PRUint16 mNameCount;
|
||||
PRUint16 mTargetStart;
|
||||
PRUint16 mTargetCount;
|
||||
};
|
||||
|
||||
ipcmMessageClientInfo::ipcmMessageClientInfo(PRUint32 cID, const char *names[], const nsID *targets[])
|
||||
{
|
||||
ipcmClientInfoHeader hdr = {0};
|
||||
|
||||
hdr.mType = MSG_TYPE;
|
||||
hdr.mID = cID;
|
||||
hdr.mNameStart = sizeof(hdr);
|
||||
|
||||
PRUint32 i, namesLen = 0;
|
||||
|
||||
i = 0;
|
||||
while (names[i]) {
|
||||
namesLen += (strlen(names[i]) + 1);
|
||||
++hdr.mNameCount;
|
||||
++i;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (targets[i]) {
|
||||
++hdr.mTargetCount;
|
||||
++i;
|
||||
}
|
||||
|
||||
//
|
||||
// compute target array starting offset
|
||||
//
|
||||
hdr.mTargetStart = hdr.mNameStart + namesLen;
|
||||
|
||||
//
|
||||
// compute message length
|
||||
//
|
||||
PRUint32 dataLen = sizeof(hdr) + namesLen + hdr.mTargetCount * sizeof(nsID);
|
||||
|
||||
Init(IPCM_TARGET, NULL, dataLen);
|
||||
|
||||
//
|
||||
// write message data
|
||||
//
|
||||
SetData(0, (const char *) &hdr, sizeof(hdr));
|
||||
|
||||
PRUint32 offset = sizeof(hdr);
|
||||
|
||||
for (i = 0; names[i]; ++i) {
|
||||
PRUint32 len = strlen(names[i]) + 1;
|
||||
SetData(offset, names[i], len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
for (i = 0; targets[i]; ++i) {
|
||||
PRUint32 len = sizeof(nsID);
|
||||
SetData(offset, (const char *) targets[i], len);
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
ipcmMessageClientInfo::ClientID() const
|
||||
{
|
||||
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
|
||||
return hdr->mID;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
ipcmMessageClientInfo::NameCount() const
|
||||
{
|
||||
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
|
||||
return hdr->mNameCount;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
ipcmMessageClientInfo::TargetCount() const
|
||||
{
|
||||
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
|
||||
return hdr->mTargetCount;
|
||||
}
|
||||
|
||||
const char *
|
||||
ipcmMessageClientInfo::NextName(const char *name) const
|
||||
{
|
||||
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
|
||||
|
||||
if (!name)
|
||||
return (const char *) hdr + hdr->mNameStart;
|
||||
|
||||
name += strlen(name) + 1;
|
||||
if (name == (const char *) hdr + hdr->mTargetStart)
|
||||
name = NULL;
|
||||
return name;
|
||||
}
|
||||
|
||||
const nsID *
|
||||
ipcmMessageClientInfo::NextTarget(const nsID *target) const
|
||||
{
|
||||
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
|
||||
|
||||
if (!target)
|
||||
return (const nsID *) (Data() + hdr->mTargetStart);
|
||||
|
||||
if (++target == (const nsID *) (MsgBuf() + MsgLen()))
|
||||
target = NULL;
|
||||
return target;
|
||||
}
|
||||
|
||||
//
|
||||
// FORWARD message
|
||||
//
|
||||
// +-------------------------+
|
||||
// | DWORD : MSG_TYPE |
|
||||
// +-------------------------+
|
||||
// | clientID |
|
||||
// +-------------------------+
|
||||
// | innerMsgHeader |
|
||||
// +-------------------------+
|
||||
// | innerMsgData |
|
||||
// +-------------------------+
|
||||
//
|
||||
|
||||
ipcmMessageForward::ipcmMessageForward(PRUint32 cID,
|
||||
const nsID &target,
|
||||
const char *data,
|
||||
PRUint32 dataLen)
|
||||
{
|
||||
int len = sizeof(MSG_TYPE) + // MSG_TYPE
|
||||
sizeof(cID) + // cID
|
||||
IPC_MSG_HEADER_SIZE + // innerMsgHeader
|
||||
dataLen; // innerMsgData
|
||||
|
||||
Init(IPCM_TARGET, NULL, len);
|
||||
|
||||
SetData(0, (char *) &MSG_TYPE, sizeof(MSG_TYPE));
|
||||
SetData(4, (char *) &cID, sizeof(cID));
|
||||
|
||||
ipcMessageHeader hdr;
|
||||
hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen;
|
||||
hdr.mVersion = IPC_MSG_VERSION;
|
||||
hdr.mFlags = 0;
|
||||
hdr.mTarget = target;
|
||||
|
||||
SetData(8, (char *) &hdr, IPC_MSG_HEADER_SIZE);
|
||||
if (data)
|
||||
SetInnerData(0, data, dataLen);
|
||||
}
|
||||
|
||||
void
|
||||
ipcmMessageForward::SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen)
|
||||
{
|
||||
SetData(8 + IPC_MSG_HEADER_SIZE + offset, data, dataLen);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
ipcmMessageForward::DestClientID() const
|
||||
{
|
||||
return ((PRUint32 *) Data())[1];
|
||||
}
|
||||
|
||||
const nsID &
|
||||
ipcmMessageForward::InnerTarget() const
|
||||
{
|
||||
ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8);
|
||||
return hdr->mTarget;
|
||||
}
|
||||
|
||||
const char *
|
||||
ipcmMessageForward::InnerData() const
|
||||
{
|
||||
return Data() + 8 + IPC_MSG_HEADER_SIZE;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
ipcmMessageForward::InnerDataLen() const
|
||||
{
|
||||
ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8);
|
||||
return hdr->mLen - IPC_MSG_HEADER_SIZE;
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcm_h__
|
||||
#define ipcm_h__
|
||||
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcMessagePrimitives.h"
|
||||
|
||||
//
|
||||
// IPCM (IPC Manager) protocol support
|
||||
//
|
||||
|
||||
extern const nsID IPCM_TARGET;
|
||||
|
||||
enum {
|
||||
IPCM_MSG_TYPE_PING,
|
||||
IPCM_MSG_TYPE_ERROR,
|
||||
IPCM_MSG_TYPE_CLIENT_HELLO,
|
||||
IPCM_MSG_TYPE_CLIENT_ID,
|
||||
IPCM_MSG_TYPE_CLIENT_INFO,
|
||||
IPCM_MSG_TYPE_CLIENT_ADD_NAME,
|
||||
IPCM_MSG_TYPE_CLIENT_DEL_NAME,
|
||||
IPCM_MSG_TYPE_CLIENT_ADD_TARGET,
|
||||
IPCM_MSG_TYPE_CLIENT_DEL_TARGET,
|
||||
IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME,
|
||||
IPCM_MSG_TYPE_QUERY_CLIENT_INFO,
|
||||
// IPCM_MSG_TYPE_QUERY_MODULE, // check if module exists
|
||||
IPCM_MSG_TYPE_FORWARD,
|
||||
IPCM_MSG_TYPE_UNKNOWN // unknown message type
|
||||
};
|
||||
|
||||
//
|
||||
// returns IPCM message type.
|
||||
//
|
||||
static inline int
|
||||
IPCM_GetMsgType(const ipcMessage *msg)
|
||||
{
|
||||
return ((const ipcMessage_DWORD *) msg)->First();
|
||||
}
|
||||
|
||||
//
|
||||
// NOTE: this file declares some helper classes that simplify construction
|
||||
// and parsing of IPCM messages. each class subclasses ipcMessage, but
|
||||
// adds no additional member variables. operator new should be used
|
||||
// to allocate one of the IPCM helper classes, e.g.:
|
||||
//
|
||||
// ipcMessage *msg = new ipcmMessageClientHello("foo");
|
||||
//
|
||||
// given an arbitrary ipcMessage, it can be parsed using logic similar
|
||||
// to the following:
|
||||
//
|
||||
// void func(const ipcMessage *unknown)
|
||||
// {
|
||||
// if (unknown->Topic().Equals(IPCM_TARGET)) {
|
||||
// if (IPCM_GetMsgType(unknown) == IPCM_MSG_TYPE_CLIENT_ID) {
|
||||
// ipcMessageCast<ipcmMessageClientID> msg(unknown);
|
||||
// printf("Client ID: %u\n", msg->ClientID());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// in other words, these classes are very very lightweight.
|
||||
//
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_PING
|
||||
//
|
||||
// this message may be sent from either the client or the daemon.
|
||||
// if the daemon receives this message, then it will respond by
|
||||
// sending back a PING to the client.
|
||||
//
|
||||
class ipcmMessagePing : public ipcMessage_DWORD
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessagePing()
|
||||
: ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {}
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_ERROR
|
||||
//
|
||||
// this message may be sent from the daemon in place of an expected
|
||||
// result. e.g., if a query fails, the daemon will send an error
|
||||
// message to indicate the failure.
|
||||
//
|
||||
class ipcmMessageError : public ipcMessage_DWORD_DWORD
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageError(PRUint32 reason)
|
||||
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, reason) {}
|
||||
|
||||
PRUint32 Reason() const { return Second(); }
|
||||
};
|
||||
|
||||
enum {
|
||||
IPCM_ERROR_CLIENT_NOT_FOUND = 1
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_HELLO
|
||||
//
|
||||
// this message is always the first message sent from a client to register
|
||||
// itself with the daemon. the daemon responds to this message by sending
|
||||
// the client a CLIENT_ID message informing the client of its client ID.
|
||||
//
|
||||
// XXX may want to pass other information here.
|
||||
//
|
||||
class ipcmMessageClientHello : public ipcMessage_DWORD
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientHello()
|
||||
: ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {}
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_ID
|
||||
//
|
||||
// this message is sent from the daemon to identify a client's ID.
|
||||
//
|
||||
class ipcmMessageClientID : public ipcMessage_DWORD_DWORD
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientID(PRUint32 clientID)
|
||||
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {}
|
||||
|
||||
PRUint32 ClientID() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_INFO
|
||||
//
|
||||
// this message is sent from the daemon to provide the list of names
|
||||
// and targets for a particular client.
|
||||
//
|
||||
class ipcmMessageClientInfo : public ipcMessage
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientInfo(PRUint32 clientID, const char **names, const nsID **targets);
|
||||
|
||||
PRUint32 ClientID() const;
|
||||
PRUint32 NameCount() const;
|
||||
PRUint32 TargetCount() const;
|
||||
|
||||
const char *NextName(const char *name) const;
|
||||
const nsID *NextTarget(const nsID *target) const;
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_ADD_NAME
|
||||
//
|
||||
class ipcmMessageClientAddName : public ipcMessage_DWORD_STR
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientAddName(const char *name)
|
||||
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
|
||||
|
||||
const char *Name() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_DEL_NAME
|
||||
//
|
||||
class ipcmMessageClientDelName : public ipcMessage_DWORD_STR
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientDelName(const char *name)
|
||||
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
|
||||
|
||||
const char *Name() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_ADD_TARGET
|
||||
//
|
||||
class ipcmMessageClientAddTarget : public ipcMessage_DWORD_ID
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientAddTarget(const nsID &target)
|
||||
: ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {}
|
||||
|
||||
const nsID &Target() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_CLIENT_DEL_TARGET
|
||||
//
|
||||
class ipcmMessageClientDelTarget : public ipcMessage_DWORD_ID
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageClientDelTarget(const nsID &target)
|
||||
: ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {}
|
||||
|
||||
const nsID &Target() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME
|
||||
//
|
||||
// this message is sent from a client to the daemon to request the ID of the
|
||||
// client corresponding to the given name. in response the daemon will either
|
||||
// send a CLIENT_ID or ERROR message.
|
||||
//
|
||||
class ipcmMessageQueryClientByName : public ipcMessage_DWORD_STR
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageQueryClientByName(const char *name)
|
||||
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
|
||||
|
||||
const char *Name() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_QUERY_CLIENT_INFO
|
||||
//
|
||||
// thie message is sent from a client to the daemon to request complete
|
||||
// information about the client corresponding to the given client ID. in
|
||||
// response the daemon will either send a CLIENT_INFO or ERROR message.
|
||||
//
|
||||
class ipcmMessageQueryClientInfo : public ipcMessage_DWORD_DWORD
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
ipcmMessageQueryClientInfo(PRUint32 clientID)
|
||||
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {}
|
||||
|
||||
PRUint32 ClientID() const { return Second(); }
|
||||
};
|
||||
|
||||
//
|
||||
// IPCM_MSG_TYPE_FORWARD
|
||||
//
|
||||
// this message is only sent from the client to the daemon. the daemon
|
||||
// will forward the contained message to the specified client. there
|
||||
// is no guarantee that the message will be forwarded, and no error will
|
||||
// be sent to the sender on failure.
|
||||
//
|
||||
class ipcmMessageForward : public ipcMessage
|
||||
{
|
||||
public:
|
||||
static const PRUint32 MSG_TYPE;
|
||||
|
||||
//
|
||||
// params:
|
||||
// clientID - the client to which the message should be forwarded
|
||||
// target - the message target
|
||||
// data - the message data
|
||||
// dataLen - the message data length
|
||||
//
|
||||
ipcmMessageForward(PRUint32 clientID,
|
||||
const nsID &target,
|
||||
const char *data,
|
||||
PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// set inner message data, constrained to the data length passed
|
||||
// to this class's constructor.
|
||||
//
|
||||
void SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
|
||||
|
||||
PRUint32 DestClientID() const;
|
||||
const nsID &InnerTarget() const;
|
||||
const char *InnerData() const;
|
||||
PRUint32 InnerDataLen() const;
|
||||
};
|
||||
|
||||
#endif // !ipcm_h__
|
||||
@@ -1,86 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
REQUIRES = \
|
||||
xpcom \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
ipcd.cpp \
|
||||
ipcClient.cpp \
|
||||
ipcModuleReg.cpp \
|
||||
ipcCommandModule.cpp
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
CPPSRCS += ipcdWin.cpp
|
||||
else
|
||||
CPPSRCS += ipcdUnix.cpp
|
||||
endif
|
||||
|
||||
PROGRAM = mozipcd$(BIN_SUFFIX)
|
||||
|
||||
EXPORTS = \
|
||||
ipcModule.h \
|
||||
ipcModuleUtil.h \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../common \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
LIBS = \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)ipccom_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# For fruncate
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
DEFINES += -D_BSD_SOURCE
|
||||
endif
|
||||
@@ -1,233 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "ipcLog.h"
|
||||
#include "ipcClient.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcd.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include "prio.h"
|
||||
#endif
|
||||
|
||||
PRUint32 ipcClient::gLastID = 0;
|
||||
|
||||
//
|
||||
// called to initialize this client context
|
||||
//
|
||||
// assumptions:
|
||||
// - object's memory has already been zero'd out.
|
||||
//
|
||||
void
|
||||
ipcClient::Init()
|
||||
{
|
||||
mID = ++gLastID;
|
||||
|
||||
// every client must be able to handle IPCM messages.
|
||||
mTargets.Append(IPCM_TARGET);
|
||||
|
||||
// although it is tempting to fire off the NotifyClientUp event at this
|
||||
// time, we must wait until the client sends us a CLIENT_HELLO event.
|
||||
// see ipcCommandModule::OnClientHello.
|
||||
}
|
||||
|
||||
//
|
||||
// called when this client context is going away
|
||||
//
|
||||
void
|
||||
ipcClient::Finalize()
|
||||
{
|
||||
IPC_NotifyClientDown(this);
|
||||
|
||||
mNames.DeleteAll();
|
||||
mTargets.DeleteAll();
|
||||
|
||||
#ifdef XP_UNIX
|
||||
mInMsg.Reset();
|
||||
mOutMsgQ.DeleteAll();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ipcClient::AddName(const char *name)
|
||||
{
|
||||
LOG(("adding client name: %s\n", name));
|
||||
|
||||
if (HasName(name))
|
||||
return;
|
||||
|
||||
mNames.Append(name);
|
||||
}
|
||||
|
||||
void
|
||||
ipcClient::DelName(const char *name)
|
||||
{
|
||||
LOG(("deleting client name: %s\n", name));
|
||||
|
||||
mNames.FindAndDelete(name);
|
||||
}
|
||||
|
||||
void
|
||||
ipcClient::AddTarget(const nsID &target)
|
||||
{
|
||||
LOG(("adding client target\n"));
|
||||
|
||||
if (HasTarget(target))
|
||||
return;
|
||||
|
||||
mTargets.Append(target);
|
||||
}
|
||||
|
||||
void
|
||||
ipcClient::DelTarget(const nsID &target)
|
||||
{
|
||||
LOG(("deleting client target\n"));
|
||||
|
||||
//
|
||||
// cannot remove the IPCM target
|
||||
//
|
||||
if (!target.Equals(IPCM_TARGET))
|
||||
mTargets.FindAndDelete(target);
|
||||
}
|
||||
|
||||
#ifdef XP_UNIX
|
||||
|
||||
//
|
||||
// called to process a client socket
|
||||
//
|
||||
// params:
|
||||
// fd - the client socket
|
||||
// poll_flags - the state of the client socket
|
||||
//
|
||||
// return:
|
||||
// 0 - to end session with this client
|
||||
// PR_POLL_READ - to wait for the client socket to become readable
|
||||
// PR_POLL_WRITE - to wait for the client socket to become writable
|
||||
//
|
||||
int
|
||||
ipcClient::Process(PRFileDesc *fd, int inFlags)
|
||||
{
|
||||
if (inFlags & (PR_POLL_ERR | PR_POLL_HUP |
|
||||
PR_POLL_EXCEPT | PR_POLL_NVAL)) {
|
||||
LOG(("client socket appears to have closed\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// expect to wait for more data
|
||||
int outFlags = PR_POLL_READ;
|
||||
|
||||
if (inFlags & PR_POLL_READ) {
|
||||
LOG(("client socket is now readable\n"));
|
||||
|
||||
char buf[1024]; // XXX make this larger?
|
||||
PRInt32 n;
|
||||
|
||||
// find out how much data is available for reading...
|
||||
// n = PR_Available(fd);
|
||||
|
||||
n = PR_Read(fd, buf, sizeof(buf));
|
||||
if (n <= 0)
|
||||
return 0; // cancel connection
|
||||
|
||||
const char *ptr = buf;
|
||||
while (n) {
|
||||
PRUint32 nread;
|
||||
PRBool complete;
|
||||
|
||||
if (mInMsg.ReadFrom(ptr, PRUint32(n), &nread, &complete) == PR_FAILURE) {
|
||||
LOG(("message appears to be malformed; dropping client connection\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
IPC_DispatchMsg(this, &mInMsg);
|
||||
mInMsg.Reset();
|
||||
}
|
||||
|
||||
n -= nread;
|
||||
ptr += nread;
|
||||
}
|
||||
}
|
||||
|
||||
if (inFlags & PR_POLL_WRITE) {
|
||||
LOG(("client socket is now writable\n"));
|
||||
|
||||
if (mOutMsgQ.First())
|
||||
WriteMsgs(fd);
|
||||
}
|
||||
|
||||
if (mOutMsgQ.First())
|
||||
outFlags |= PR_POLL_WRITE;
|
||||
|
||||
return outFlags;
|
||||
}
|
||||
|
||||
//
|
||||
// called to write out any messages from the outgoing queue.
|
||||
//
|
||||
int
|
||||
ipcClient::WriteMsgs(PRFileDesc *fd)
|
||||
{
|
||||
while (mOutMsgQ.First()) {
|
||||
const char *buf = (const char *) mOutMsgQ.First()->MsgBuf();
|
||||
PRInt32 bufLen = (PRInt32) mOutMsgQ.First()->MsgLen();
|
||||
|
||||
if (mSendOffset) {
|
||||
buf += mSendOffset;
|
||||
bufLen -= mSendOffset;
|
||||
}
|
||||
|
||||
PRInt32 nw = PR_Write(fd, buf, bufLen);
|
||||
if (nw <= 0)
|
||||
break;
|
||||
|
||||
LOG(("wrote %d bytes\n", nw));
|
||||
|
||||
if (nw == bufLen) {
|
||||
mOutMsgQ.DeleteFirst();
|
||||
mSendOffset = 0;
|
||||
}
|
||||
else
|
||||
mSendOffset += nw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcClientUnix_h__
|
||||
#define ipcClientUnix_h__
|
||||
|
||||
#include "prio.h"
|
||||
#include "ipcMessageQ.h"
|
||||
#include "ipcStringList.h"
|
||||
#include "ipcIDList.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcClient
|
||||
//
|
||||
// NOTE: this class is an implementation detail of the IPC daemon. IPC daemon
|
||||
// modules (other than the built-in IPCM module) must not access methods on
|
||||
// this class directly. use the API provided via ipcd.h instead.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcClient
|
||||
{
|
||||
public:
|
||||
void Init();
|
||||
void Finalize();
|
||||
|
||||
PRUint32 ID() const { return mID; }
|
||||
|
||||
void AddName(const char *name);
|
||||
void DelName(const char *name);
|
||||
PRBool HasName(const char *name) const { return mNames.Find(name) != NULL; }
|
||||
|
||||
void AddTarget(const nsID &target);
|
||||
void DelTarget(const nsID &target);
|
||||
PRBool HasTarget(const nsID &target) const { return mTargets.Find(target) != NULL; }
|
||||
|
||||
// list iterators
|
||||
const ipcStringNode *Names() const { return mNames.First(); }
|
||||
const ipcIDNode *Targets() const { return mTargets.First(); }
|
||||
|
||||
// returns primary client name (the one specified in the "client hello" message)
|
||||
const char *PrimaryName() const { return mNames.First() ? mNames.First()->Value() : NULL; }
|
||||
|
||||
void SetExpectsSyncReply(PRBool val) { mExpectsSyncReply = val; }
|
||||
PRBool GetExpectsSyncReply() const { return mExpectsSyncReply; }
|
||||
|
||||
#ifdef XP_WIN
|
||||
PRUint32 PID() const { return mPID; }
|
||||
void SetPID(PRUint32 pid) { mPID = pid; }
|
||||
|
||||
HWND Hwnd() const { return mHwnd; }
|
||||
void SetHwnd(HWND hwnd) { mHwnd = hwnd; }
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
//
|
||||
// called to process a client file descriptor. the value of pollFlags
|
||||
// indicates the state of the socket.
|
||||
//
|
||||
// returns:
|
||||
// 0 - to cancel client connection
|
||||
// PR_POLL_READ - to poll for a readable socket
|
||||
// PR_POLL_WRITE - to poll for a writable socket
|
||||
// (both flags) - to poll for either a readable or writable socket
|
||||
//
|
||||
// the socket is non-blocking.
|
||||
//
|
||||
int Process(PRFileDesc *sockFD, int pollFlags);
|
||||
|
||||
//
|
||||
// on success or failure, this function takes ownership of |msg| and will
|
||||
// delete it when appropriate.
|
||||
//
|
||||
void EnqueueOutboundMsg(ipcMessage *msg) { mOutMsgQ.Append(msg); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
static PRUint32 gLastID;
|
||||
|
||||
PRUint32 mID;
|
||||
ipcStringList mNames;
|
||||
ipcIDList mTargets;
|
||||
PRBool mExpectsSyncReply;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// on windows, we store the PID of the client process to help us determine
|
||||
// the client from which a message originated. each message has the PID
|
||||
// encoded in it.
|
||||
PRUint32 mPID;
|
||||
|
||||
// the hwnd of the client's message window.
|
||||
HWND mHwnd;
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
ipcMessage mInMsg; // buffer for incoming message
|
||||
ipcMessageQ mOutMsgQ; // outgoing message queue
|
||||
|
||||
// keep track of the amount of the first message sent
|
||||
PRUint32 mSendOffset;
|
||||
|
||||
// utility function for writing out messages.
|
||||
int WriteMsgs(PRFileDesc *fd);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // !ipcClientUnix_h__
|
||||
@@ -1,257 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ipcLog.h"
|
||||
#include "ipcCommandModule.h"
|
||||
#include "ipcModule.h"
|
||||
#include "ipcClient.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcMessageUtils.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcd.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
struct ipcCommandModule
|
||||
{
|
||||
typedef void (* MsgHandler)(ipcClient *, const ipcMessage *);
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
|
||||
static char **
|
||||
BuildStringArray(const ipcStringNode *nodes)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
const ipcStringNode *node;
|
||||
|
||||
for (node = nodes; node; node = node->mNext)
|
||||
count++;
|
||||
|
||||
char **strs = (char **) calloc(count + 1, sizeof(char *));
|
||||
if (!strs)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (node = nodes; node; node = node->mNext, ++count)
|
||||
strs[count] = (char *) node->Value();
|
||||
|
||||
return strs;
|
||||
}
|
||||
|
||||
static nsID **
|
||||
BuildIDArray(const ipcIDNode *nodes)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
const ipcIDNode *node;
|
||||
|
||||
for (node = nodes; node; node = node->mNext)
|
||||
count++;
|
||||
|
||||
nsID **ids = (nsID **) calloc(count + 1, sizeof(nsID *));
|
||||
if (!ids)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (node = nodes; node; node = node->mNext, ++count)
|
||||
ids[count] = (nsID *) &node->Value();
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
//
|
||||
// message handlers
|
||||
//
|
||||
|
||||
static void
|
||||
OnPing(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got PING\n"));
|
||||
|
||||
IPC_SendMsg(client, new ipcmMessagePing());
|
||||
}
|
||||
|
||||
static void
|
||||
OnClientHello(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got CLIENT_HELLO\n"));
|
||||
|
||||
IPC_SendMsg(client, new ipcmMessageClientID(client->ID()));
|
||||
|
||||
//
|
||||
// NOTE: it would almost make sense for this notification to live
|
||||
// in the transport layer code. however, clients expect to receive
|
||||
// a CLIENT_ID as the first message following a CLIENT_HELLO, so we
|
||||
// must not allow modules to see a client until after we have sent
|
||||
// the CLIENT_ID message.
|
||||
//
|
||||
IPC_NotifyClientUp(client);
|
||||
}
|
||||
|
||||
static void
|
||||
OnClientAddName(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got CLIENT_ADD_NAME\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageClientAddName> msg(rawMsg);
|
||||
const char *name = msg->Name();
|
||||
if (name)
|
||||
client->AddName(name);
|
||||
}
|
||||
|
||||
static void
|
||||
OnClientDelName(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got CLIENT_DEL_NAME\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageClientDelName> msg(rawMsg);
|
||||
const char *name = msg->Name();
|
||||
if (name)
|
||||
client->DelName(name);
|
||||
}
|
||||
|
||||
static void
|
||||
OnClientAddTarget(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got CLIENT_ADD_TARGET\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageClientAddTarget> msg(rawMsg);
|
||||
client->AddTarget(msg->Target());
|
||||
}
|
||||
|
||||
static void
|
||||
OnClientDelTarget(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got CLIENT_DEL_TARGET\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageClientDelTarget> msg(rawMsg);
|
||||
client->DelTarget(msg->Target());
|
||||
}
|
||||
|
||||
static void
|
||||
OnQueryClientByName(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got QUERY_CLIENT_BY_NAME\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageQueryClientByName> msg(rawMsg);
|
||||
ipcClient *result = IPC_GetClientByName(msg->Name());
|
||||
if (result) {
|
||||
LOG((" client exists w/ ID = %u\n", result->ID()));
|
||||
IPC_SendMsg(client, new ipcmMessageClientID(result->ID()));
|
||||
}
|
||||
else {
|
||||
LOG((" client does not exist\n"));
|
||||
IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_CLIENT_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got QUERY_CLIENT_INFO\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageQueryClientInfo> msg(rawMsg);
|
||||
ipcClient *result = IPC_GetClientByID(msg->ClientID());
|
||||
if (result) {
|
||||
char **names = BuildStringArray(result->Names());
|
||||
nsID **targets = BuildIDArray(result->Targets());
|
||||
|
||||
IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(),
|
||||
(const char **) names,
|
||||
(const nsID **) targets));
|
||||
|
||||
free(names);
|
||||
free(targets);
|
||||
}
|
||||
else {
|
||||
LOG((" client does not exist\n"));
|
||||
IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_CLIENT_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
OnForward(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("got FORWARD\n"));
|
||||
|
||||
ipcMessageCast<ipcmMessageForward> msg(rawMsg);
|
||||
|
||||
ipcClient *dest = IPC_GetClientByID(msg->DestClientID());
|
||||
if (!dest) {
|
||||
LOG((" destination client not found!\n"));
|
||||
return;
|
||||
}
|
||||
ipcMessage *newMsg = new ipcMessage(msg->InnerTarget(),
|
||||
msg->InnerData(),
|
||||
msg->InnerDataLen());
|
||||
IPC_SendMsg(dest, newMsg);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg)
|
||||
{
|
||||
static ipcCommandModule::MsgHandler handlers[] =
|
||||
{
|
||||
ipcCommandModule::OnPing,
|
||||
NULL, // ERROR
|
||||
ipcCommandModule::OnClientHello,
|
||||
NULL, // CLIENT_ID
|
||||
NULL, // CLIENT_INFO
|
||||
ipcCommandModule::OnClientAddName,
|
||||
ipcCommandModule::OnClientDelName,
|
||||
ipcCommandModule::OnClientAddTarget,
|
||||
ipcCommandModule::OnClientDelTarget,
|
||||
ipcCommandModule::OnQueryClientByName,
|
||||
ipcCommandModule::OnQueryClientInfo,
|
||||
ipcCommandModule::OnForward,
|
||||
};
|
||||
|
||||
int type = IPCM_GetMsgType(rawMsg);
|
||||
LOG(("IPCM_HandleMsg [type=%d]\n", type));
|
||||
|
||||
if (type < IPCM_MSG_TYPE_UNKNOWN) {
|
||||
if (handlers[type]) {
|
||||
ipcCommandModule::MsgHandler handler = handlers[type];
|
||||
handler(client, rawMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcCommandModule_h__
|
||||
#define ipcCommandModule_h__
|
||||
|
||||
#include "ipcm.h" // for IPCM_TARGET
|
||||
|
||||
class ipcClient;
|
||||
class ipcMessage;
|
||||
|
||||
void IPCM_HandleMsg(ipcClient *, const ipcMessage *);
|
||||
|
||||
#endif // !ipcCommandModule_h__
|
||||
@@ -1,242 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcModule_h__
|
||||
#define ipcModule_h__
|
||||
|
||||
#include "nsID.h"
|
||||
|
||||
class ipcMessage;
|
||||
|
||||
//
|
||||
// a client handle is used to efficiently reference a client instance object
|
||||
// used by the daemon to represent a connection with a particular client app.
|
||||
//
|
||||
// modules should treat it as an opaque type.
|
||||
//
|
||||
typedef class ipcClient *ipcClientHandle;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// interface implemented by the module:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// the version of ipcModuleMethods data structure.
|
||||
//
|
||||
#define IPC_MODULE_METHODS_VERSION (1<<16) // 1.0
|
||||
|
||||
//
|
||||
// each module defines the following structure:
|
||||
//
|
||||
struct ipcModuleMethods
|
||||
{
|
||||
//
|
||||
// this field holds the version of the data structure, which is always the
|
||||
// value of IPC_MODULE_METHODS_VERSION against which the module was built.
|
||||
//
|
||||
PRUint32 version;
|
||||
|
||||
//
|
||||
// called after this module is registered.
|
||||
//
|
||||
void (* init) (void);
|
||||
|
||||
//
|
||||
// called when this module will no longer be accessed.
|
||||
//
|
||||
void (* shutdown) (void);
|
||||
|
||||
//
|
||||
// called when a new message arrives for this module.
|
||||
//
|
||||
// params:
|
||||
// client - an opaque "handle" to an object representing the client that
|
||||
// sent the message. modules should not store the value of this
|
||||
// beyond the duration fo this function call. (e.g., the handle
|
||||
// may be invalid after this function call returns.) modules
|
||||
// wishing to hold onto a reference to a "client" should store
|
||||
// the client's ID (see IPC_GetClientID).
|
||||
// target - message target
|
||||
// data - message data
|
||||
// dataLen - message data length
|
||||
//
|
||||
void (* handleMsg) (ipcClientHandle client,
|
||||
const nsID &target,
|
||||
const void *data,
|
||||
PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// called when a new client connects to the IPC daemon.
|
||||
//
|
||||
void (* clientUp) (ipcClientHandle client);
|
||||
|
||||
//
|
||||
// called when a client disconnects from the IPC daemon.
|
||||
//
|
||||
void (* clientDown) (ipcClientHandle client);
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// interface implemented by the daemon:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// the version of ipcDaemonMethods data structure.
|
||||
//
|
||||
#define IPC_DAEMON_METHODS_VERSION (1<<16) // 1.0
|
||||
|
||||
//
|
||||
// enumeration functions may return FALSE to stop enumeration.
|
||||
//
|
||||
typedef PRBool (* ipcClientEnumFunc) (void *closure, ipcClientHandle client, PRUint32 clientID);
|
||||
typedef PRBool (* ipcClientNameEnumFunc) (void *closure, ipcClientHandle client, const char *name);
|
||||
typedef PRBool (* ipcClientTargetEnumFunc) (void *closure, ipcClientHandle client, const nsID &target);
|
||||
|
||||
//
|
||||
// the daemon provides the following structure:
|
||||
//
|
||||
struct ipcDaemonMethods
|
||||
{
|
||||
PRUint32 version;
|
||||
|
||||
//
|
||||
// called to send a message to another module.
|
||||
//
|
||||
// params:
|
||||
// client - identifies the client from which this message originated.
|
||||
// target - message target
|
||||
// data - message data
|
||||
// dataLen - message data length
|
||||
//
|
||||
// returns:
|
||||
// PR_SUCCESS if message was dispatched.
|
||||
// PR_FAILURE if message could not be dispatched (possibly because
|
||||
// no module is registered for the given message target).
|
||||
//
|
||||
PRStatus (* dispatchMsg) (ipcClientHandle client,
|
||||
const nsID &target,
|
||||
const void *data,
|
||||
PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// called to send a message to a particular client or to broadcast a
|
||||
// message to all clients.
|
||||
//
|
||||
// params:
|
||||
// client - if null, then broadcast message to all clients. otherwise,
|
||||
// send message to the client specified.
|
||||
// target - message target
|
||||
// data - message data
|
||||
// dataLen - message data length
|
||||
//
|
||||
// returns:
|
||||
// PR_SUCCESS if message was sent (or queued up to be sent later).
|
||||
// PR_FAILURE if message could not be sent (possibly because the client
|
||||
// does not have a registered observer for the msg's target).
|
||||
//
|
||||
PRStatus (* sendMsg) (ipcClientHandle client,
|
||||
const nsID &target,
|
||||
const void *data,
|
||||
PRUint32 dataLen);
|
||||
|
||||
//
|
||||
// called to lookup a client handle given its client ID. each client has
|
||||
// a unique ID.
|
||||
//
|
||||
ipcClientHandle (* getClientByID) (PRUint32 clientID);
|
||||
|
||||
//
|
||||
// called to lookup a client by name or alias. names are not necessary
|
||||
// unique to individual clients. this function returns the client first
|
||||
// registered under the given name.
|
||||
//
|
||||
ipcClientHandle (* getClientByName) (const char *name);
|
||||
|
||||
//
|
||||
// called to enumerate all clients.
|
||||
//
|
||||
void (* enumClients) (ipcClientEnumFunc func, void *closure);
|
||||
|
||||
//
|
||||
// returns the client ID of the specified client.
|
||||
//
|
||||
PRUint32 (* getClientID) (ipcClientHandle client);
|
||||
|
||||
//
|
||||
// functions for inspecting the names and targets defined for a particular
|
||||
// client instance.
|
||||
//
|
||||
PRBool (* clientHasName) (ipcClientHandle client, const char *name);
|
||||
PRBool (* clientHasTarget) (ipcClientHandle client, const nsID &target);
|
||||
void (* enumClientNames) (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure);
|
||||
void (* enumClientTargets) (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure);
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// interface exported by a DSO implementing one or more modules:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ipcModuleEntry
|
||||
{
|
||||
//
|
||||
// identifies the message target of this module.
|
||||
//
|
||||
nsID target;
|
||||
|
||||
//
|
||||
// module methods
|
||||
//
|
||||
ipcModuleMethods *methods;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define IPC_EXPORT extern "C" NS_EXPORT
|
||||
|
||||
//
|
||||
// IPC_EXPORT int IPC_GetModules(const ipcDaemonMethods *, const ipcModuleEntry **);
|
||||
//
|
||||
// params:
|
||||
// methods - the daemon's methods
|
||||
// entries - the module entries defined by the DSO
|
||||
//
|
||||
// returns:
|
||||
// length of the |entries| array.
|
||||
//
|
||||
typedef int (* ipcGetModulesFunc) (const ipcDaemonMethods *methods, const ipcModuleEntry **entries);
|
||||
|
||||
#endif // !ipcModule_h__
|
||||
@@ -1,244 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "prlink.h"
|
||||
#include "prio.h"
|
||||
#include "prlog.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcModule.h"
|
||||
#include "ipcCommandModule.h"
|
||||
#include "ipcd.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ipcModuleRegEntry
|
||||
{
|
||||
nsID target;
|
||||
ipcModuleMethods *methods;
|
||||
PRLibrary *lib;
|
||||
};
|
||||
|
||||
#define IPC_MAX_MODULE_COUNT 64
|
||||
|
||||
static ipcModuleRegEntry ipcModules[IPC_MAX_MODULE_COUNT];
|
||||
static int ipcModuleCount = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static PRStatus
|
||||
AddModule(const nsID &target, ipcModuleMethods *methods, const char *libPath)
|
||||
{
|
||||
if (ipcModuleCount == IPC_MAX_MODULE_COUNT) {
|
||||
LOG(("too many modules!\n"));
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
if (!methods) {
|
||||
PR_NOT_REACHED("null module methods");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
//
|
||||
// each ipcModuleRegEntry holds a reference to a PRLibrary, and on
|
||||
// shutdown, each PRLibrary reference will be released. this ensures
|
||||
// that the library will not be unloaded until all of the modules in
|
||||
// that library are shutdown.
|
||||
//
|
||||
ipcModules[ipcModuleCount].target = target;
|
||||
ipcModules[ipcModuleCount].methods = methods;
|
||||
ipcModules[ipcModuleCount].lib = PR_LoadLibrary(libPath);
|
||||
|
||||
++ipcModuleCount;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
InitModuleFromLib(const char *modulesDir, const char *fileName)
|
||||
{
|
||||
LOG(("InitModuleFromLib [%s]\n", fileName));
|
||||
|
||||
static const ipcDaemonMethods gDaemonMethods =
|
||||
{
|
||||
IPC_DAEMON_METHODS_VERSION,
|
||||
IPC_DispatchMsg,
|
||||
IPC_SendMsg,
|
||||
IPC_GetClientByID,
|
||||
IPC_GetClientByName,
|
||||
IPC_EnumClients,
|
||||
IPC_GetClientID,
|
||||
IPC_ClientHasName,
|
||||
IPC_ClientHasTarget,
|
||||
IPC_EnumClientNames,
|
||||
IPC_EnumClientTargets
|
||||
};
|
||||
|
||||
int dLen = strlen(modulesDir);
|
||||
int fLen = strlen(fileName);
|
||||
|
||||
char *buf = (char *) malloc(dLen + 1 + fLen + 1);
|
||||
memcpy(buf, modulesDir, dLen);
|
||||
buf[dLen] = IPC_PATH_SEP_CHAR;
|
||||
memcpy(buf + dLen + 1, fileName, fLen);
|
||||
buf[dLen + 1 + fLen] = '\0';
|
||||
|
||||
PRLibrary *lib = PR_LoadLibrary(buf);
|
||||
if (lib) {
|
||||
ipcGetModulesFunc func =
|
||||
(ipcGetModulesFunc) PR_FindFunctionSymbol(lib, "IPC_GetModules");
|
||||
|
||||
LOG((" func=%p\n", (void*) func));
|
||||
|
||||
if (func) {
|
||||
const ipcModuleEntry *entries = NULL;
|
||||
int count = func(&gDaemonMethods, &entries);
|
||||
for (int i=0; i<count; ++i) {
|
||||
if (AddModule(entries[i].target, entries[i].methods, buf) == PR_SUCCESS) {
|
||||
if (entries[i].methods->init)
|
||||
entries[i].methods->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
PR_UnloadLibrary(lib);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcModuleReg API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
IPC_InitModuleReg(const char *exePath)
|
||||
{
|
||||
if (!(exePath && *exePath))
|
||||
return;
|
||||
|
||||
//
|
||||
// register plug-in modules
|
||||
//
|
||||
char *p = PL_strrchr(exePath, IPC_PATH_SEP_CHAR);
|
||||
if (p == NULL) {
|
||||
LOG(("unexpected exe path\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
int baseLen = p - exePath;
|
||||
int finalLen = baseLen + 1 + sizeof(IPC_MODULES_DIR);
|
||||
|
||||
// build full path to ipc modules
|
||||
char *modulesDir = (char*) malloc(finalLen);
|
||||
memcpy(modulesDir, exePath, baseLen);
|
||||
modulesDir[baseLen] = IPC_PATH_SEP_CHAR;
|
||||
memcpy(modulesDir + baseLen + 1, IPC_MODULES_DIR, sizeof(IPC_MODULES_DIR));
|
||||
|
||||
LOG(("loading libraries in %s\n", modulesDir));
|
||||
//
|
||||
// scan directory for IPC modules
|
||||
//
|
||||
PRDir *dir = PR_OpenDir(modulesDir);
|
||||
if (dir) {
|
||||
PRDirEntry *ent;
|
||||
while ((ent = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
|
||||
//
|
||||
// locate extension, and check if dynamic library
|
||||
//
|
||||
char *p = strrchr(ent->name, '.');
|
||||
if (p && PL_strcasecmp(p, MOZ_DLL_SUFFIX) == 0)
|
||||
InitModuleFromLib(modulesDir, ent->name);
|
||||
}
|
||||
PR_CloseDir(dir);
|
||||
}
|
||||
|
||||
free(modulesDir);
|
||||
}
|
||||
|
||||
void
|
||||
IPC_ShutdownModuleReg()
|
||||
{
|
||||
//
|
||||
// shutdown modules in reverse order
|
||||
//
|
||||
while (ipcModuleCount) {
|
||||
ipcModuleRegEntry &entry = ipcModules[--ipcModuleCount];
|
||||
if (entry.methods->shutdown)
|
||||
entry.methods->shutdown();
|
||||
if (entry.lib)
|
||||
PR_UnloadLibrary(entry.lib);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPC_NotifyClientUp(ipcClient *client)
|
||||
{
|
||||
for (int i = 0; i < ipcModuleCount; ++i) {
|
||||
ipcModuleRegEntry &entry = ipcModules[i];
|
||||
if (entry.methods->clientUp)
|
||||
entry.methods->clientUp(client);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPC_NotifyClientDown(ipcClient *client)
|
||||
{
|
||||
for (int i = 0; i < ipcModuleCount; ++i) {
|
||||
ipcModuleRegEntry &entry = ipcModules[i];
|
||||
if (entry.methods->clientDown)
|
||||
entry.methods->clientDown(client);
|
||||
}
|
||||
}
|
||||
|
||||
PRStatus
|
||||
IPC_DispatchMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
// dispatch message to every module registered under the given target.
|
||||
for (int i=0; i<ipcModuleCount; ++i) {
|
||||
ipcModuleRegEntry &entry = ipcModules[i];
|
||||
if (entry.target.Equals(target)) {
|
||||
if (entry.methods->handleMsg)
|
||||
entry.methods->handleMsg(client, target, data, dataLen);
|
||||
}
|
||||
}
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcModuleReg_h__
|
||||
#define ipcModuleReg_h__
|
||||
|
||||
#include "ipcModule.h"
|
||||
|
||||
//
|
||||
// called to init the module registry. this may only be called once at
|
||||
// startup or once after calling IPC_ShutdownModuleReg.
|
||||
//
|
||||
// params:
|
||||
// exePath - path to the daemon executable. modules are loaded from a
|
||||
// directory relative to the daemon executable.
|
||||
//
|
||||
void IPC_InitModuleReg(const char *exePath);
|
||||
|
||||
//
|
||||
// called to shutdown the module registry. this may be called more than
|
||||
// once and need not follow a call to IPC_InitModuleReg.
|
||||
//
|
||||
void IPC_ShutdownModuleReg();
|
||||
|
||||
//
|
||||
// returns the ipcModuleMethods for the given target.
|
||||
//
|
||||
ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target);
|
||||
|
||||
//
|
||||
// notifies all modules of client connect/disconnect
|
||||
//
|
||||
void IPC_NotifyClientUp(ipcClient *);
|
||||
void IPC_NotifyClientDown(ipcClient *);
|
||||
|
||||
#endif // !ipcModuleReg_h__
|
||||
@@ -1,151 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcModuleUtil_h__
|
||||
#define ipcModuleUtil_h__
|
||||
|
||||
#include "prlog.h"
|
||||
#include "ipcModule.h"
|
||||
|
||||
extern const ipcDaemonMethods *gIPCDaemonMethods;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inline wrapper functions
|
||||
//
|
||||
// these functions may only be called by a module that uses the
|
||||
// IPC_IMPL_GETMODULES macro.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline PRStatus
|
||||
IPC_DispatchMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->dispatchMsg(client, target, data, dataLen);
|
||||
}
|
||||
|
||||
inline PRStatus
|
||||
IPC_SendMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->sendMsg(client, target, data, dataLen);
|
||||
}
|
||||
|
||||
inline ipcClientHandle
|
||||
IPC_GetClientByID(PRUint32 id)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->getClientByID(id);
|
||||
}
|
||||
|
||||
inline ipcClientHandle
|
||||
IPC_GetClientByName(const char *name)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->getClientByName(name);
|
||||
}
|
||||
|
||||
inline void
|
||||
IPC_EnumClients(ipcClientEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
gIPCDaemonMethods->enumClients(func, closure);
|
||||
}
|
||||
|
||||
inline PRUint32
|
||||
IPC_GetClientID(ipcClientHandle client)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->getClientID(client);
|
||||
}
|
||||
|
||||
inline PRBool
|
||||
IPC_ClientHasName(ipcClientHandle client, const char *name)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->clientHasName(client, name);
|
||||
}
|
||||
|
||||
inline PRBool
|
||||
IPC_ClientHasTarget(ipcClientHandle client, const nsID &target)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
return gIPCDaemonMethods->clientHasTarget(client, target);
|
||||
}
|
||||
|
||||
inline void
|
||||
IPC_EnumClientNames(ipcClientHandle client, ipcClientNameEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
gIPCDaemonMethods->enumClientNames(client, func, closure);
|
||||
}
|
||||
|
||||
inline void
|
||||
IPC_EnumClientTargets(ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(gIPCDaemonMethods);
|
||||
gIPCDaemonMethods->enumClientTargets(client, func, closure);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inline composite functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline PRStatus
|
||||
IPC_SendMsg(PRUint32 clientID, const nsID &target, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
ipcClient *client = IPC_GetClientByID(clientID);
|
||||
if (!client)
|
||||
return PR_FAILURE;
|
||||
return IPC_SendMsg(client, target, data, dataLen);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// module factory macros
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define IPC_IMPL_GETMODULES(_modName, _modEntries) \
|
||||
const ipcDaemonMethods *gIPCDaemonMethods; \
|
||||
IPC_EXPORT int \
|
||||
IPC_GetModules(const ipcDaemonMethods *dmeths, \
|
||||
const ipcModuleEntry **ents) { \
|
||||
/* XXX do version checking */ \
|
||||
gIPCDaemonMethods = dmeths; \
|
||||
*ents = _modEntries; \
|
||||
return sizeof(_modEntries) / sizeof(ipcModuleEntry); \
|
||||
}
|
||||
|
||||
#endif // !ipcModuleUtil_h__
|
||||
@@ -1,187 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "prlog.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcClient.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcModule.h"
|
||||
#include "ipcCommandModule.h"
|
||||
#include "ipcdPrivate.h"
|
||||
#include "ipcd.h"
|
||||
|
||||
PRStatus
|
||||
IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
PR_ASSERT(msg);
|
||||
|
||||
// remember if client is expecting SYNC_REPLY. we'll add that flag to the
|
||||
// next message sent to the client.
|
||||
if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) {
|
||||
PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE);
|
||||
client->SetExpectsSyncReply(PR_TRUE);
|
||||
}
|
||||
|
||||
if (msg->Target().Equals(IPCM_TARGET)) {
|
||||
IPCM_HandleMsg(client, msg);
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
return IPC_DispatchMsg(client, msg->Target(), msg->Data(), msg->DataLen());
|
||||
}
|
||||
|
||||
PRStatus
|
||||
IPC_SendMsg(ipcClient *client, ipcMessage *msg)
|
||||
{
|
||||
PR_ASSERT(msg);
|
||||
|
||||
if (client == NULL) {
|
||||
//
|
||||
// broadcast
|
||||
//
|
||||
for (int i=0; i<ipcClientCount; ++i)
|
||||
IPC_SendMsg(&ipcClients[i], msg->Clone());
|
||||
delete msg;
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
// add SYNC_REPLY flag to message if client is expecting...
|
||||
if (client->GetExpectsSyncReply()) {
|
||||
msg->SetFlag(IPC_MSG_FLAG_SYNC_REPLY);
|
||||
client->SetExpectsSyncReply(PR_FALSE);
|
||||
}
|
||||
|
||||
if (client->HasTarget(msg->Target()))
|
||||
return IPC_PlatformSendMsg(client, msg);
|
||||
|
||||
LOG((" no registered message handler\n"));
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IPC daemon methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRStatus
|
||||
IPC_SendMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen)
|
||||
{
|
||||
return IPC_SendMsg(client, new ipcMessage(target, (const char *) data, dataLen));
|
||||
}
|
||||
|
||||
ipcClient *
|
||||
IPC_GetClientByID(PRUint32 clientID)
|
||||
{
|
||||
// linear search OK since number of clients should be small
|
||||
for (int i = 0; i < ipcClientCount; ++i) {
|
||||
if (ipcClients[i].ID() == clientID)
|
||||
return &ipcClients[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipcClient *
|
||||
IPC_GetClientByName(const char *name)
|
||||
{
|
||||
// linear search OK since number of clients should be small
|
||||
for (int i = 0; i < ipcClientCount; ++i) {
|
||||
if (ipcClients[i].HasName(name))
|
||||
return &ipcClients[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
IPC_EnumClients(ipcClientEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(func);
|
||||
for (int i = 0; i < ipcClientCount; ++i) {
|
||||
if (func(closure, &ipcClients[i], ipcClients[i].ID()) == PR_FALSE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
IPC_GetClientID(ipcClient *client)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
return client->ID();
|
||||
}
|
||||
|
||||
PRBool
|
||||
IPC_ClientHasName(ipcClient *client, const char *name)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
PR_ASSERT(name);
|
||||
return client->HasName(name);
|
||||
}
|
||||
|
||||
PRBool
|
||||
IPC_ClientHasTarget(ipcClient *client, const nsID &target)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
return client->HasTarget(target);
|
||||
}
|
||||
|
||||
void
|
||||
IPC_EnumClientNames(ipcClient *client, ipcClientNameEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
PR_ASSERT(func);
|
||||
const ipcStringNode *node = client->Names();
|
||||
while (node) {
|
||||
if (func(closure, client, node->Value()) == PR_FALSE)
|
||||
break;
|
||||
node = node->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPC_EnumClientTargets(ipcClient *client, ipcClientTargetEnumFunc func, void *closure)
|
||||
{
|
||||
PR_ASSERT(client);
|
||||
PR_ASSERT(func);
|
||||
const ipcIDNode *node = client->Targets();
|
||||
while (node) {
|
||||
if (func(closure, client, node->Value()) == PR_FALSE)
|
||||
break;
|
||||
node = node->mNext;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 IPCD_H__
|
||||
#define IPCD_H__
|
||||
|
||||
#include "ipcModule.h"
|
||||
#include "ipcMessage.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IPC daemon methods (see struct ipcDaemonMethods)
|
||||
//
|
||||
// these functions may only be called directly from within the daemon. plug-in
|
||||
// modules must access these through the ipcDaemonMethods structure.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRStatus IPC_DispatchMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen);
|
||||
PRStatus IPC_SendMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen);
|
||||
ipcClientHandle IPC_GetClientByID (PRUint32 id);
|
||||
ipcClientHandle IPC_GetClientByName (const char *name);
|
||||
void IPC_EnumClients (ipcClientEnumFunc func, void *closure);
|
||||
PRUint32 IPC_GetClientID (ipcClientHandle client);
|
||||
PRBool IPC_ClientHasName (ipcClientHandle client, const char *name);
|
||||
PRBool IPC_ClientHasTarget (ipcClientHandle client, const nsID &target);
|
||||
void IPC_EnumClientNames (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure);
|
||||
void IPC_EnumClientTargets (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// other internal IPCD methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// dispatch message
|
||||
//
|
||||
PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg);
|
||||
|
||||
//
|
||||
// send message, takes ownership of |msg|.
|
||||
//
|
||||
PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg);
|
||||
|
||||
#endif // !IPCD_H__
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef ipcdPrivate_h__
|
||||
#define ipcdPrivate_h__
|
||||
|
||||
class ipcClient;
|
||||
|
||||
//
|
||||
// upper limit on the number of active connections
|
||||
// XXX may want to make this more dynamic
|
||||
//
|
||||
#define IPC_MAX_CLIENTS 100
|
||||
|
||||
//
|
||||
// array of connected clients
|
||||
//
|
||||
extern ipcClient *ipcClients;
|
||||
extern int ipcClientCount;
|
||||
|
||||
//
|
||||
// platform specific send message function, takes ownership of |msg|.
|
||||
//
|
||||
PRStatus IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg);
|
||||
|
||||
#endif // !ipcdPrivate_h__
|
||||
@@ -1,439 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "prio.h"
|
||||
#include "prerror.h"
|
||||
#include "prthread.h"
|
||||
#include "prinrval.h"
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcClient.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcdPrivate.h"
|
||||
#include "ipcd.h"
|
||||
|
||||
void
|
||||
IPC_Sleep(int seconds)
|
||||
{
|
||||
while (seconds > 0) {
|
||||
LOG(("\rsleeping for %d seconds...", seconds));
|
||||
PR_Sleep(PR_SecondsToInterval(1));
|
||||
--seconds;
|
||||
}
|
||||
LOG(("\ndone sleeping\n"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipc directory and locking...
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static int ipcLockFD = 0;
|
||||
|
||||
static PRBool AcquireDaemonLock(const char *baseDir)
|
||||
{
|
||||
const char lockName[] = "lock";
|
||||
|
||||
int dirLen = strlen(baseDir);
|
||||
int len = dirLen // baseDir
|
||||
+ 1 // "/"
|
||||
+ sizeof(lockName); // "lock"
|
||||
|
||||
char *lockFile = (char *) malloc(len);
|
||||
memcpy(lockFile, baseDir, dirLen);
|
||||
lockFile[dirLen] = '/';
|
||||
memcpy(lockFile + dirLen + 1, lockName, sizeof(lockName));
|
||||
|
||||
//
|
||||
// open lock file. it remains open until we shutdown.
|
||||
//
|
||||
ipcLockFD = open(lockFile, O_WRONLY|O_CREAT, S_IWUSR|S_IRUSR);
|
||||
|
||||
free(lockFile);
|
||||
|
||||
if (ipcLockFD == -1)
|
||||
return PR_FALSE;
|
||||
|
||||
//
|
||||
// we use fcntl for locking. assumption: filesystem should be local.
|
||||
// this API is nice because the lock will be automatically released
|
||||
// when the process dies. it will also be released when the file
|
||||
// descriptor is closed.
|
||||
//
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
if (fcntl(ipcLockFD, F_SETLK, &lock) == -1)
|
||||
return PR_FALSE;
|
||||
|
||||
//
|
||||
// truncate lock file once we have exclusive access to it.
|
||||
//
|
||||
ftruncate(ipcLockFD, 0);
|
||||
|
||||
//
|
||||
// write our PID into the lock file (this just seems like a good idea...
|
||||
// no real purpose otherwise).
|
||||
//
|
||||
char buf[32];
|
||||
int nb = PR_snprintf(buf, sizeof(buf), "%u\n", (unsigned long) getpid());
|
||||
write(ipcLockFD, buf, nb);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static PRBool InitDaemonDir(const char *socketPath)
|
||||
{
|
||||
LOG(("InitDaemonDir [sock=%s]\n", socketPath));
|
||||
|
||||
char *baseDir = PL_strdup(socketPath);
|
||||
|
||||
//
|
||||
// make sure IPC directory exists (XXX this should be recursive)
|
||||
//
|
||||
char *p = strrchr(baseDir, '/');
|
||||
if (p)
|
||||
p[0] = '\0';
|
||||
mkdir(baseDir, 0700);
|
||||
|
||||
//
|
||||
// if we can't acquire the daemon lock, then another daemon
|
||||
// must be active, so bail.
|
||||
//
|
||||
PRBool haveLock = AcquireDaemonLock(baseDir);
|
||||
|
||||
PL_strfree(baseDir);
|
||||
|
||||
if (haveLock) {
|
||||
// delete an existing socket to prevent bind from failing.
|
||||
unlink(socketPath);
|
||||
}
|
||||
return haveLock;
|
||||
}
|
||||
|
||||
static void ShutdownDaemonDir()
|
||||
{
|
||||
LOG(("ShutdownDaemonDir\n"));
|
||||
|
||||
// deleting directory and files underneath it allows another process
|
||||
// to think it has exclusive access. better to just leave the hidden
|
||||
// directory in /tmp and let the OS clean it up via the usual tmpdir
|
||||
// cleanup cron job.
|
||||
|
||||
// this removes the advisory lock, allowing other processes to acquire it.
|
||||
if (ipcLockFD) {
|
||||
close(ipcLockFD);
|
||||
ipcLockFD = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// poll list
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// declared in ipcdPrivate.h
|
||||
//
|
||||
ipcClient *ipcClients = NULL;
|
||||
int ipcClientCount = 0;
|
||||
|
||||
//
|
||||
// the first element of this array is always zero; this is done so that the
|
||||
// k'th element of ipcClientArray corresponds to the k'th element of
|
||||
// ipcPollList.
|
||||
//
|
||||
static ipcClient ipcClientArray[IPC_MAX_CLIENTS + 1];
|
||||
|
||||
//
|
||||
// element 0 contains the "server socket"
|
||||
//
|
||||
static PRPollDesc ipcPollList[IPC_MAX_CLIENTS + 1];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static int AddClient(PRFileDesc *fd)
|
||||
{
|
||||
if (ipcClientCount == IPC_MAX_CLIENTS) {
|
||||
LOG(("reached maximum client limit\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pollCount = ipcClientCount + 1;
|
||||
|
||||
ipcClientArray[pollCount].Init();
|
||||
|
||||
ipcPollList[pollCount].fd = fd;
|
||||
ipcPollList[pollCount].in_flags = PR_POLL_READ;
|
||||
ipcPollList[pollCount].out_flags = 0;
|
||||
|
||||
++ipcClientCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RemoveClient(int clientIndex)
|
||||
{
|
||||
PRPollDesc *pd = &ipcPollList[clientIndex];
|
||||
|
||||
PR_Close(pd->fd);
|
||||
|
||||
ipcClientArray[clientIndex].Finalize();
|
||||
|
||||
//
|
||||
// keep the clients and poll_fds contiguous; move the last one into
|
||||
// the spot held by the one that is going away.
|
||||
//
|
||||
int toIndex = clientIndex;
|
||||
int fromIndex = ipcClientCount;
|
||||
if (fromIndex != toIndex) {
|
||||
memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient));
|
||||
memcpy(&ipcPollList[toIndex], &ipcPollList[fromIndex], sizeof(PRPollDesc));
|
||||
}
|
||||
|
||||
//
|
||||
// zero out the old entries.
|
||||
//
|
||||
memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient));
|
||||
memset(&ipcPollList[fromIndex], 0, sizeof(PRPollDesc));
|
||||
|
||||
--ipcClientCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void PollLoop(PRFileDesc *listenFD)
|
||||
{
|
||||
// the first element of ipcClientArray is unused.
|
||||
memset(ipcClientArray, 0, sizeof(ipcClientArray));
|
||||
ipcClients = ipcClientArray + 1;
|
||||
ipcClientCount = 0;
|
||||
|
||||
ipcPollList[0].fd = listenFD;
|
||||
ipcPollList[0].in_flags = PR_POLL_EXCEPT | PR_POLL_READ;
|
||||
|
||||
while (1) {
|
||||
PRInt32 rv;
|
||||
PRIntn i;
|
||||
|
||||
int pollCount = ipcClientCount + 1;
|
||||
|
||||
ipcPollList[0].out_flags = 0;
|
||||
|
||||
//
|
||||
// poll
|
||||
//
|
||||
// timeout after 5 minutes. if no connections after timeout, then
|
||||
// exit. this timeout ensures that we don't stay resident when no
|
||||
// clients are interested in connecting after spawning the daemon.
|
||||
//
|
||||
// XXX add #define for timeout value
|
||||
//
|
||||
rv = PR_Poll(ipcPollList, pollCount, PR_SecondsToInterval(60 * 5));
|
||||
if (rv == -1) {
|
||||
LOG(("PR_Poll failed [%d]\n", PR_GetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rv > 0) {
|
||||
//
|
||||
// process clients that are ready
|
||||
//
|
||||
for (i = 1; i < pollCount; ++i) {
|
||||
if (ipcPollList[i].out_flags != 0) {
|
||||
ipcPollList[i].in_flags =
|
||||
ipcClientArray[i].Process(ipcPollList[i].fd,
|
||||
ipcPollList[i].out_flags);
|
||||
ipcPollList[i].out_flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// cleanup any dead clients (indicated by a zero in_flags)
|
||||
//
|
||||
for (i = pollCount - 1; i >= 1; --i) {
|
||||
if (ipcPollList[i].in_flags == 0)
|
||||
RemoveClient(i);
|
||||
}
|
||||
|
||||
//
|
||||
// check for new connection
|
||||
//
|
||||
if (ipcPollList[0].out_flags & PR_POLL_READ) {
|
||||
LOG(("got new connection\n"));
|
||||
|
||||
PRNetAddr clientAddr;
|
||||
memset(&clientAddr, 0, sizeof(clientAddr));
|
||||
PRFileDesc *clientFD;
|
||||
|
||||
clientFD = PR_Accept(listenFD, &clientAddr, PR_INTERVAL_NO_WAIT);
|
||||
if (clientFD == NULL) {
|
||||
// ignore this error... perhaps the client disconnected.
|
||||
LOG(("PR_Accept failed [%d]\n", PR_GetError()));
|
||||
}
|
||||
else {
|
||||
// make socket non-blocking
|
||||
PRSocketOptionData opt;
|
||||
opt.option = PR_SockOpt_Nonblocking;
|
||||
opt.value.non_blocking = PR_TRUE;
|
||||
PR_SetSocketOption(clientFD, &opt);
|
||||
|
||||
if (AddClient(clientFD) != 0)
|
||||
PR_Close(clientFD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// shutdown if no clients
|
||||
//
|
||||
if (ipcClientCount == 0) {
|
||||
LOG(("shutting down\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRStatus
|
||||
IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
|
||||
{
|
||||
LOG(("IPC_PlatformSendMsg\n"));
|
||||
|
||||
//
|
||||
// must copy message onto send queue.
|
||||
//
|
||||
client->EnqueueOutboundMsg(msg);
|
||||
|
||||
//
|
||||
// since our Process method may have already been called, we must ensure
|
||||
// that the PR_POLL_WRITE flag is set.
|
||||
//
|
||||
int clientIndex = client - ipcClientArray;
|
||||
ipcPollList[clientIndex].in_flags |= PR_POLL_WRITE;
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
PRFileDesc *listenFD = NULL;
|
||||
PRNetAddr addr;
|
||||
|
||||
//
|
||||
// ignore SIGINT so <ctrl-c> from terminal only kills the client
|
||||
// which spawned this daemon.
|
||||
//
|
||||
signal(SIGINT, SIG_IGN);
|
||||
// XXX block others? check cartman
|
||||
|
||||
// ensure strict file permissions
|
||||
umask(0077);
|
||||
|
||||
IPC_InitLog("###");
|
||||
|
||||
LOG(("daemon started...\n"));
|
||||
|
||||
//XXX uncomment these lines to test slow starting daemon
|
||||
//LOG(("sleeping for 2 seconds...\n"));
|
||||
//PR_Sleep(PR_SecondsToInterval(2));
|
||||
|
||||
// set socket address
|
||||
addr.local.family = PR_AF_LOCAL;
|
||||
if (argc < 2)
|
||||
IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path));
|
||||
else
|
||||
PL_strncpyz(addr.local.path, argv[1], sizeof(addr.local.path));
|
||||
|
||||
if (!InitDaemonDir(addr.local.path)) {
|
||||
LOG(("InitDaemonDir failed\n"));
|
||||
goto end;
|
||||
}
|
||||
|
||||
listenFD = PR_OpenTCPSocket(PR_AF_LOCAL);
|
||||
if (!listenFD) {
|
||||
LOG(("PR_OpenUDPSocket failed [%d]\n", PR_GetError()));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (PR_Bind(listenFD, &addr) != PR_SUCCESS) {
|
||||
LOG(("PR_Bind failed [%d]\n", PR_GetError()));
|
||||
goto end;
|
||||
}
|
||||
|
||||
IPC_InitModuleReg(argv[0]);
|
||||
|
||||
if (PR_Listen(listenFD, 5) != PR_SUCCESS) {
|
||||
LOG(("PR_Listen failed [%d]\n", PR_GetError()));
|
||||
goto end;
|
||||
}
|
||||
|
||||
PollLoop(listenFD);
|
||||
|
||||
end:
|
||||
IPC_ShutdownModuleReg();
|
||||
|
||||
//IPC_Sleep(5);
|
||||
|
||||
// it is critical that we release the lock before closing the socket,
|
||||
// otherwise, a client might launch another daemon that would be unable
|
||||
// to acquire the lock and would then leave the client without a daemon.
|
||||
|
||||
ShutdownDaemonDir();
|
||||
|
||||
if (listenFD) {
|
||||
LOG(("closing socket\n"));
|
||||
PR_Close(listenFD);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "prthread.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcClient.h"
|
||||
#include "ipcModuleReg.h"
|
||||
#include "ipcdPrivate.h"
|
||||
#include "ipcd.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
//
|
||||
// declared in ipcdPrivate.h
|
||||
//
|
||||
ipcClient *ipcClients = NULL;
|
||||
int ipcClientCount = 0;
|
||||
|
||||
static ipcClient ipcClientArray[IPC_MAX_CLIENTS];
|
||||
|
||||
static HWND ipcHwnd = NULL;
|
||||
static PRBool ipcShutdown = PR_FALSE;
|
||||
|
||||
#define IPC_PURGE_TIMER_ID 1
|
||||
#define IPC_WM_SENDMSG (WM_USER + 1)
|
||||
#define IPC_WM_SHUTDOWN (WM_USER + 2)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// client array manipulation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
RemoveClient(ipcClient *client)
|
||||
{
|
||||
LOG(("RemoveClient\n"));
|
||||
|
||||
int clientIndex = client - ipcClientArray;
|
||||
|
||||
client->Finalize();
|
||||
|
||||
//
|
||||
// move last ipcClient object down into the spot occupied by this client.
|
||||
//
|
||||
int fromIndex = ipcClientCount - 1;
|
||||
int toIndex = clientIndex;
|
||||
if (toIndex != fromIndex)
|
||||
memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient));
|
||||
|
||||
memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient));
|
||||
|
||||
--ipcClientCount;
|
||||
LOG((" num clients = %u\n", ipcClientCount));
|
||||
|
||||
if (ipcClientCount == 0) {
|
||||
LOG((" shutting down...\n"));
|
||||
KillTimer(ipcHwnd, IPC_PURGE_TIMER_ID);
|
||||
PostQuitMessage(0);
|
||||
ipcShutdown = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PurgeStaleClients()
|
||||
{
|
||||
if (ipcClientCount == 0)
|
||||
return;
|
||||
|
||||
LOG(("PurgeStaleClients [num-clients=%u]\n", ipcClientCount));
|
||||
//
|
||||
// walk the list of supposedly active clients, and verify the existance of
|
||||
// their respective message windows.
|
||||
//
|
||||
char wName[IPC_CLIENT_WINDOW_NAME_MAXLEN];
|
||||
for (int i=ipcClientCount-1; i>=0; --i) {
|
||||
ipcClient *client = &ipcClientArray[i];
|
||||
|
||||
LOG((" checking client at index %u [client-id=%u pid=%u]\n",
|
||||
i, client->ID(), client->PID()));
|
||||
|
||||
IPC_GetClientWindowName(client->PID(), wName);
|
||||
|
||||
// XXX dougt has ideas about how to make this better
|
||||
|
||||
HWND hwnd = FindWindow(IPC_CLIENT_WINDOW_CLASS, wName);
|
||||
if (!hwnd) {
|
||||
LOG((" client window not found; removing client!\n"));
|
||||
RemoveClient(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ipcClient *
|
||||
AddClient(HWND hwnd, PRUint32 pid)
|
||||
{
|
||||
LOG(("AddClient\n"));
|
||||
|
||||
//
|
||||
// before adding a new client, verify that all existing clients are
|
||||
// still up and running. remove any stale clients.
|
||||
//
|
||||
PurgeStaleClients();
|
||||
|
||||
if (ipcClientCount == IPC_MAX_CLIENTS) {
|
||||
LOG((" reached maximum client count!\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipcClient *client = &ipcClientArray[ipcClientCount];
|
||||
client->Init();
|
||||
client->SetHwnd(hwnd);
|
||||
client->SetPID(pid); // XXX one function instead of 3
|
||||
|
||||
++ipcClientCount;
|
||||
LOG((" num clients = %u\n", ipcClientCount));
|
||||
|
||||
if (ipcClientCount == 1)
|
||||
SetTimer(ipcHwnd, IPC_PURGE_TIMER_ID, 1000, NULL);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
static ipcClient *
|
||||
GetClientByPID(PRUint32 pid)
|
||||
{
|
||||
for (int i=0; i<ipcClientCount; ++i) {
|
||||
if (ipcClientArray[i].PID() == pid)
|
||||
return &ipcClientArray[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// message processing
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ProcessMsg(HWND hwnd, PRUint32 pid, const ipcMessage *msg)
|
||||
{
|
||||
LOG(("ProcessMsg [pid=%u len=%u]\n", pid, msg->MsgLen()));
|
||||
|
||||
ipcClient *client = GetClientByPID(pid);
|
||||
|
||||
if (client) {
|
||||
//
|
||||
// if this is an IPCM "client hello" message, then reset the client
|
||||
// instance object.
|
||||
//
|
||||
if (msg->Target().Equals(IPCM_TARGET) &&
|
||||
IPCM_GetMsgType(msg) == IPCM_MSG_TYPE_CLIENT_HELLO) {
|
||||
RemoveClient(client);
|
||||
client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (client == NULL) {
|
||||
client = AddClient(hwnd, pid);
|
||||
if (!client)
|
||||
return;
|
||||
}
|
||||
|
||||
IPC_DispatchMsg(client, msg);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRStatus
|
||||
IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
|
||||
{
|
||||
LOG(("IPC_PlatformSendMsg [clientID=%u clientPID=%u]\n",
|
||||
client->ID(), client->PID()));
|
||||
|
||||
// use PostMessage to make this asynchronous; otherwise we might get
|
||||
// some wierd SendMessage recursion between processes.
|
||||
|
||||
WPARAM wParam = (WPARAM) client->Hwnd();
|
||||
LPARAM lParam = (LPARAM) msg;
|
||||
if (!PostMessage(ipcHwnd, IPC_WM_SENDMSG, wParam, lParam)) {
|
||||
LOG(("PostMessage failed\n"));
|
||||
delete msg;
|
||||
return PR_FAILURE;
|
||||
}
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// windows message loop
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static LRESULT CALLBACK
|
||||
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam));
|
||||
|
||||
if (uMsg == WM_COPYDATA) {
|
||||
if (ipcShutdown) {
|
||||
LOG(("ignoring message b/c daemon is shutting down\n"));
|
||||
return TRUE;
|
||||
}
|
||||
COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
|
||||
if (cd && cd->lpData) {
|
||||
ipcMessage msg;
|
||||
PRUint32 bytesRead;
|
||||
PRBool complete;
|
||||
// XXX avoid extra malloc
|
||||
PRStatus rv = msg.ReadFrom((const char *) cd->lpData, cd->cbData,
|
||||
&bytesRead, &complete);
|
||||
if (rv == PR_SUCCESS && complete) {
|
||||
//
|
||||
// grab client PID and hwnd.
|
||||
//
|
||||
ProcessMsg((HWND) wParam, (PRUint32) cd->dwData, &msg);
|
||||
}
|
||||
else
|
||||
LOG(("ignoring malformed message\n"));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (uMsg == IPC_WM_SENDMSG) {
|
||||
HWND hWndDest = (HWND) wParam;
|
||||
ipcMessage *msg = (ipcMessage *) lParam;
|
||||
|
||||
COPYDATASTRUCT cd;
|
||||
cd.dwData = GetCurrentProcessId();
|
||||
cd.cbData = (DWORD) msg->MsgLen();
|
||||
cd.lpData = (PVOID) msg->MsgBuf();
|
||||
|
||||
LOG(("calling SendMessage...\n"));
|
||||
SendMessage(hWndDest, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd);
|
||||
LOG((" done.\n"));
|
||||
|
||||
delete msg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uMsg == WM_TIMER) {
|
||||
PurgeStaleClients();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (uMsg == IPC_WM_SHUTDOWN) {
|
||||
//
|
||||
// since this message is handled asynchronously, it is possible
|
||||
// that other clients may have come online since this was issued.
|
||||
// in which case, we need to ignore this message.
|
||||
//
|
||||
if (ipcClientCount == 0) {
|
||||
ipcShutdown = PR_TRUE;
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// daemon startup synchronization
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static HANDLE ipcSyncEvent;
|
||||
|
||||
static PRBool
|
||||
AcquireLock()
|
||||
{
|
||||
ipcSyncEvent = CreateEvent(NULL, FALSE, FALSE,
|
||||
IPC_SYNC_EVENT_NAME);
|
||||
if (!ipcSyncEvent) {
|
||||
LOG(("CreateEvent failed [%u]\n", GetLastError()));
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// check to see if event already existed prior to this call.
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
LOG((" lock already set; exiting...\n"));
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
LOG((" acquired lock\n"));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseLock()
|
||||
{
|
||||
if (ipcSyncEvent) {
|
||||
LOG(("releasing lock...\n"));
|
||||
CloseHandle(ipcSyncEvent);
|
||||
ipcSyncEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// main
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
IPC_InitLog("###");
|
||||
|
||||
LOG(("daemon started...\n"));
|
||||
|
||||
if (!AcquireLock())
|
||||
return 0;
|
||||
|
||||
// initialize global data
|
||||
memset(ipcClientArray, 0, sizeof(ipcClientArray));
|
||||
ipcClients = ipcClientArray;
|
||||
ipcClientCount = 0;
|
||||
|
||||
// create message window up front...
|
||||
WNDCLASS wc;
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.lpszClassName = IPC_WINDOW_CLASS;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
ipcHwnd = CreateWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME,
|
||||
0, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
|
||||
if (!ipcHwnd)
|
||||
return -1;
|
||||
|
||||
// load modules
|
||||
IPC_InitModuleReg(argv[0]);
|
||||
|
||||
LOG(("entering message loop...\n"));
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, ipcHwnd, 0, 0))
|
||||
DispatchMessage(&msg);
|
||||
|
||||
// unload modules
|
||||
IPC_ShutdownModuleReg();
|
||||
|
||||
//
|
||||
// we release the daemon lock before destroying the window because the
|
||||
// absence of our window is what will cause clients to try to spawn the
|
||||
// daemon.
|
||||
//
|
||||
ReleaseLock();
|
||||
|
||||
//LOG(("sleeping 5 seconds...\n"));
|
||||
//PR_Sleep(PR_SecondsToInterval(5));
|
||||
|
||||
LOG(("destroying message window...\n"));
|
||||
DestroyWindow(ipcHwnd);
|
||||
ipcHwnd = NULL;
|
||||
|
||||
LOG(("exiting\n"));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = lock
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,47 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,52 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
|
||||
XPIDLSRCS = \
|
||||
ipcILockService.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcILockNotify;
|
||||
|
||||
/**
|
||||
* This service provides named interprocess locking with either synchronous
|
||||
* or asynchronous waiting.
|
||||
*/
|
||||
[scriptable, uuid(9f6dbe15-d851-4b00-912a-5ac0be88a409)]
|
||||
interface ipcILockService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Call this method to acquire a named lock. Pass a notification handler
|
||||
* to be notified asynchronously when the lock is acquired. Otherwise,
|
||||
* this function will block until the lock is acquired.
|
||||
*
|
||||
* @param aLockName
|
||||
* specifies the name of the lock
|
||||
* @param aNotify
|
||||
* notification callback (NULL to synchronously acquire lock)
|
||||
* @param aWaitIfBusy
|
||||
* wait for the lock to become available; otherwise, fail if lock
|
||||
* is already held by some other process.
|
||||
*/
|
||||
void acquireLock(in string aLockName,
|
||||
in ipcILockNotify aNotify,
|
||||
in boolean aWaitIfBusy);
|
||||
|
||||
/**
|
||||
* Call this method to release a named lock. This method can be called
|
||||
* before OnAcquireLockComplete has been called, which will effectively
|
||||
* cancel the request to acquire the named lock. OnAcquireLockComplete
|
||||
* will not be called after a call to ReleaseLock.
|
||||
*
|
||||
* @param aLockName
|
||||
* specifies the name of the lock
|
||||
*/
|
||||
void releaseLock(in string aLockName);
|
||||
};
|
||||
|
||||
[scriptable, uuid(b4ac1160-98a4-4030-aecc-01137a05c94b)]
|
||||
interface ipcILockNotify : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called to complete a call to AcquireLock.
|
||||
*
|
||||
* @status aLockName
|
||||
* specifies the name of the lock
|
||||
* @status aStatus
|
||||
* NS_OK if lock has been acquired; reason for failure otherwise.
|
||||
*/
|
||||
void onAcquireLockComplete(in string aLockName,
|
||||
in nsresult aStatus);
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = module
|
||||
|
||||
MODULE = ipc
|
||||
LIBRARY_NAME = ipclock_s
|
||||
EXPORT_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
MODULE_NAME = ipc
|
||||
|
||||
REQUIRES = \
|
||||
xpcom \
|
||||
string \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
ipcLockProtocol.cpp \
|
||||
ipcLockService.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../../../common \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,50 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prlog.h"
|
||||
#include "ipcLockProtocol.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline PRUint8 get_opcode(const PRUint8 *buf)
|
||||
{
|
||||
return (buf[0] & 0x0f);
|
||||
}
|
||||
|
||||
static inline PRUint8 get_flags(const PRUint8 *buf)
|
||||
{
|
||||
return (buf[0] & 0xf0) >> 4;
|
||||
}
|
||||
|
||||
static inline const char *get_key(const PRUint8 *buf)
|
||||
{
|
||||
return ((const char *) buf) + 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PRUint8 *
|
||||
IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen)
|
||||
{
|
||||
PRUint32 len = 1 // header byte
|
||||
+ strlen(msg->key) // key
|
||||
+ 1; // null terminator
|
||||
|
||||
PRUint8 *buf = (PRUint8 *) malloc(len);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
buf[0] = (msg->opcode | (msg->flags << 4));
|
||||
|
||||
memcpy(&buf[1], msg->key, len - 1);
|
||||
*bufLen = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg)
|
||||
{
|
||||
PR_ASSERT(bufLen > 2); // malformed buffer otherwise
|
||||
msg->opcode = get_opcode(buf);
|
||||
msg->flags = get_flags(buf);
|
||||
msg->key = get_key(buf);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
#ifndef ipcLockProtocol_h__
|
||||
#define ipcLockProtocol_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
//
|
||||
// ipc lock message format:
|
||||
//
|
||||
// +----------------------------------+
|
||||
// | opcode : 4 bits |
|
||||
// +----------------------------------+
|
||||
// | flags : 4 bits |
|
||||
// +----------------------------------+
|
||||
// | key : null terminated string |
|
||||
// +----------------------------------+
|
||||
//
|
||||
|
||||
// lock opcodes
|
||||
#define IPC_LOCK_OP_ACQUIRE 1
|
||||
#define IPC_LOCK_OP_RELEASE 2
|
||||
#define IPC_LOCK_OP_STATUS_ACQUIRED 3
|
||||
#define IPC_LOCK_OP_STATUS_FAILED 4
|
||||
#define IPC_LOCK_OP_STATUS_BUSY 5
|
||||
|
||||
// lock flags
|
||||
#define IPC_LOCK_FL_NONBLOCKING 1
|
||||
|
||||
// data structure for representing lock request message
|
||||
struct ipcLockMsg
|
||||
{
|
||||
PRUint8 opcode;
|
||||
PRUint8 flags;
|
||||
const char * key;
|
||||
};
|
||||
|
||||
//
|
||||
// flatten a lock message
|
||||
//
|
||||
// returns a malloc'd buffer containing the flattened message. on return,
|
||||
// bufLen contains the length of the flattened message.
|
||||
//
|
||||
PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen);
|
||||
|
||||
//
|
||||
// unflatten a lock message
|
||||
//
|
||||
void IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg);
|
||||
|
||||
//
|
||||
// TargetID for message passing
|
||||
//
|
||||
#define IPC_LOCK_TARGETID \
|
||||
{ /* 703ada8a-2d38-4d5d-9d39-03d1ccceb567 */ \
|
||||
0x703ada8a, \
|
||||
0x2d38, \
|
||||
0x4d5d, \
|
||||
{0x9d, 0x39, 0x03, 0xd1, 0xcc, 0xce, 0xb5, 0x67} \
|
||||
}
|
||||
|
||||
#endif // !ipcLockProtocol_h__
|
||||
@@ -1,117 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include "nsIServiceManager.h"
|
||||
#include "ipcLockService.h"
|
||||
#include "ipcLockProtocol.h"
|
||||
#include "ipcCID.h"
|
||||
#include "ipcLog.h"
|
||||
|
||||
static NS_DEFINE_IID(kIPCServiceCID, IPC_SERVICE_CID);
|
||||
static const nsID kLockTargetID = IPC_LOCK_TARGETID;
|
||||
|
||||
ipcLockService::ipcLockService()
|
||||
{
|
||||
}
|
||||
|
||||
ipcLockService::~ipcLockService()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcLockService::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mIPCService = do_GetService(kIPCServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return mIPCService->SetMessageObserver(kLockTargetID, this);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ipcLockService, ipcILockService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool waitIfBusy)
|
||||
{
|
||||
LOG(("ipcLockService::AcquireLock [lock=%s sync=%u wait=%u]\n",
|
||||
lockName, notify == nsnull, waitIfBusy));
|
||||
|
||||
ipcLockMsg msg;
|
||||
msg.opcode = IPC_LOCK_OP_ACQUIRE;
|
||||
msg.flags = (waitIfBusy ? 0 : IPC_LOCK_FL_NONBLOCKING);
|
||||
msg.key = lockName;
|
||||
|
||||
PRUint32 bufLen;
|
||||
PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen);
|
||||
if (!buf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, (notify == nsnull));
|
||||
free(buf);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" SendMessage failed [rv=%x]\n", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
nsCStringKey hashKey(lockName);
|
||||
mPendingTable.Put(&hashKey, notify);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcLockService::ReleaseLock(const char *lockName)
|
||||
{
|
||||
LOG(("ipcLockService::ReleaseLock [lock=%s]\n", lockName));
|
||||
|
||||
ipcLockMsg msg;
|
||||
msg.opcode = IPC_LOCK_OP_RELEASE;
|
||||
msg.flags = 0;
|
||||
msg.key = lockName;
|
||||
|
||||
PRUint32 bufLen;
|
||||
PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen);
|
||||
if (!buf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, PR_FALSE);
|
||||
free(buf);
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCStringKey hashKey(lockName);
|
||||
mPendingTable.Remove(&hashKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen)
|
||||
{
|
||||
ipcLockMsg msg;
|
||||
IPC_UnflattenLockMsg(data, dataLen, &msg);
|
||||
|
||||
LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u]\n", msg.key, msg.opcode));
|
||||
|
||||
nsresult status;
|
||||
if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED)
|
||||
status = NS_OK;
|
||||
else
|
||||
status = NS_ERROR_FAILURE;
|
||||
|
||||
NotifyComplete(msg.key, status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ipcLockService::NotifyComplete(const char *lockName, nsresult status)
|
||||
{
|
||||
nsCStringKey hashKey(lockName);
|
||||
nsISupports *obj = mPendingTable.Get(&hashKey); // ADDREFS
|
||||
if (obj) {
|
||||
nsCOMPtr<ipcILockNotify> notify = do_QueryInterface(obj);
|
||||
NS_RELEASE(obj);
|
||||
if (notify)
|
||||
notify->OnAcquireLockComplete(lockName, status);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef ipcLockService_h__
|
||||
#define ipcLockService_h__
|
||||
|
||||
#include "ipcILockService.h"
|
||||
#include "ipcIService.h"
|
||||
#include "ipcList.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
class ipcLockService : public ipcILockService
|
||||
, public ipcIMessageObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IPCILOCKSERVICE
|
||||
NS_DECL_IPCIMESSAGEOBSERVER
|
||||
|
||||
ipcLockService();
|
||||
virtual ~ipcLockService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
private:
|
||||
void NotifyComplete(const char *lockName, nsresult status);
|
||||
|
||||
nsCOMPtr<ipcIService> mIPCService;
|
||||
|
||||
// map from lockname to locknotify for pending notifications
|
||||
nsSupportsHashtable mPendingTable;
|
||||
};
|
||||
|
||||
#endif // !ipcLockService_h__
|
||||
@@ -1,77 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
LIBRARY_NAME = lockmodule
|
||||
EXPORT_LIBRARY = 1
|
||||
MODULE_NAME = ipc
|
||||
REQUIRES = xpcom \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = ipcLockModule.cpp
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/.. \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_OBJS = ../ipcLockProtocol.$(OBJ_SUFFIX)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(LIBS_DIR) \
|
||||
$(NSPR_LIBS) \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(EXTRA_OBJS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_IPC_FILES = \
|
||||
$(LIB_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_IPC_FILES)
|
||||
$(INSTALL) $^ $(DIST)/bin/ipc/modules
|
||||
|
||||
install:: $(_IPC_FILES)
|
||||
$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules
|
||||
@@ -1,238 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "ipcModuleUtil.h"
|
||||
#include "ipcLockProtocol.h"
|
||||
#include "plhash.h"
|
||||
|
||||
static const nsID kLockTargetID = IPC_LOCK_TARGETID;
|
||||
|
||||
static void
|
||||
ipcLockModule_Send(PRUint32 cid, const char *key, PRUint8 opcode)
|
||||
{
|
||||
ipcLockMsg msg = { opcode, 0, key };
|
||||
PRUint32 bufLen;
|
||||
PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen);
|
||||
if (!buf)
|
||||
return;
|
||||
IPC_SendMsg(cid, kLockTargetID, buf, bufLen);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// gLockTable stores mapping from lock name to ipcLockContext
|
||||
//
|
||||
static PLHashTable *gLockTable = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ipcLockContext
|
||||
{
|
||||
PRUint32 mOwnerID; // client ID of this lock's owner
|
||||
struct ipcLockContext *mNextPending; // pointer to client next in line to
|
||||
// acquire this lock.
|
||||
|
||||
ipcLockContext(PRUint32 ownerID)
|
||||
: mOwnerID(ownerID)
|
||||
, mNextPending(NULL) {}
|
||||
};
|
||||
|
||||
static void
|
||||
ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key)
|
||||
{
|
||||
printf("$$$ acquiring lock [key=%s]\n", key);
|
||||
|
||||
if (!gLockTable)
|
||||
return;
|
||||
|
||||
ipcLockContext *ctx;
|
||||
|
||||
ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
|
||||
if (ctx) {
|
||||
//
|
||||
// lock is already acquired, add this client to the queue. make
|
||||
// sure this client doesn't already own the lock or live on the queue.
|
||||
//
|
||||
while (ctx->mOwnerID != cid && ctx->mNextPending)
|
||||
ctx = ctx->mNextPending;
|
||||
if (ctx->mOwnerID != cid) {
|
||||
//
|
||||
// if nonblocking, then send busy status message. otherwise,
|
||||
// proceed to add this client to the pending queue.
|
||||
//
|
||||
if (flags & IPC_LOCK_FL_NONBLOCKING)
|
||||
ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_BUSY);
|
||||
else
|
||||
ctx->mNextPending = new ipcLockContext(cid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// ok, add this lock to the table, and notify client that it now owns
|
||||
// the lock!
|
||||
//
|
||||
ctx = new ipcLockContext(cid);
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
PL_HashTableAdd(gLockTable, key, ctx);
|
||||
|
||||
ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_ACQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipcLockModule_ReleaseLock(PRUint32 cid, const char *key)
|
||||
{
|
||||
printf("$$$ releasing lock [key=%s]\n", key);
|
||||
|
||||
if (!gLockTable)
|
||||
return;
|
||||
|
||||
ipcLockContext *ctx;
|
||||
|
||||
ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
|
||||
if (ctx) {
|
||||
//
|
||||
// lock is already acquired _or_ maybe client is on the pending list.
|
||||
//
|
||||
if (ctx->mOwnerID == cid) {
|
||||
if (ctx->mNextPending) {
|
||||
//
|
||||
// remove this element from the list. since this is the
|
||||
// first element in the list, instead of removing it we
|
||||
// shift the data from the next context into this one and
|
||||
// delete the next context.
|
||||
//
|
||||
ipcLockContext *next = ctx->mNextPending;
|
||||
ctx->mOwnerID = next->mOwnerID;
|
||||
ctx->mNextPending = next->mNextPending;
|
||||
delete next;
|
||||
//
|
||||
// notify client that it now owns the lock
|
||||
//
|
||||
ipcLockModule_Send(ctx->mOwnerID, key, IPC_LOCK_OP_STATUS_ACQUIRED);
|
||||
}
|
||||
else {
|
||||
delete ctx;
|
||||
PL_HashTableRemove(gLockTable, key);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ipcLockContext *prev;
|
||||
for (;;) {
|
||||
prev = ctx;
|
||||
ctx = ctx->mNextPending;
|
||||
if (!ctx)
|
||||
break;
|
||||
if (ctx->mOwnerID == cid) {
|
||||
// remove ctx from list
|
||||
prev->mNextPending = ctx->mNextPending;
|
||||
delete ctx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(PRIntn)
|
||||
ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
PRUint32 cid = *(PRUint32 *) arg;
|
||||
ipcLockModule_ReleaseLock(cid, (const char *) he->key);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ipcLockModule_Init()
|
||||
{
|
||||
printf("$$$ ipcLockModule_Init\n");
|
||||
|
||||
gLockTable = PL_NewHashTable(32,
|
||||
PL_HashString,
|
||||
PL_CompareStrings,
|
||||
PL_CompareValues,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ipcLockModule_Shutdown()
|
||||
{
|
||||
printf("$$$ ipcLockModule_Shutdown\n");
|
||||
|
||||
if (gLockTable) {
|
||||
// XXX walk table destroying all ipcLockContext objects
|
||||
|
||||
PL_HashTableDestroy(gLockTable);
|
||||
gLockTable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipcLockModule_HandleMsg(ipcClientHandle client,
|
||||
const nsID &target,
|
||||
const void *data,
|
||||
PRUint32 dataLen)
|
||||
{
|
||||
PRUint32 cid = IPC_GetClientID(client);
|
||||
|
||||
printf("$$$ ipcLockModule_HandleMsg [cid=%u]\n", cid);
|
||||
|
||||
ipcLockMsg msg;
|
||||
IPC_UnflattenLockMsg((const PRUint8 *) data, dataLen, &msg);
|
||||
|
||||
switch (msg.opcode) {
|
||||
case IPC_LOCK_OP_ACQUIRE:
|
||||
ipcLockModule_AcquireLock(cid, msg.flags, msg.key);
|
||||
break;
|
||||
case IPC_LOCK_OP_RELEASE:
|
||||
ipcLockModule_ReleaseLock(cid, msg.key);
|
||||
break;
|
||||
default:
|
||||
PR_NOT_REACHED("invalid opcode");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipcLockModule_ClientUp(ipcClientHandle client)
|
||||
{
|
||||
printf("$$$ ipcLockModule_ClientUp [%u]\n", IPC_GetClientID(client));
|
||||
}
|
||||
|
||||
static void
|
||||
ipcLockModule_ClientDown(ipcClientHandle client)
|
||||
{
|
||||
PRUint32 cid = IPC_GetClientID(client);
|
||||
|
||||
printf("$$$ ipcLockModule_ClientDown [%u]\n", cid);
|
||||
|
||||
//
|
||||
// enumerate lock table, release any locks held by this client.
|
||||
//
|
||||
|
||||
PL_HashTableEnumerateEntries(gLockTable, ipcLockModule_ReleaseByCID, &cid);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static ipcModuleMethods gLockMethods =
|
||||
{
|
||||
IPC_MODULE_METHODS_VERSION,
|
||||
ipcLockModule_Init,
|
||||
ipcLockModule_Shutdown,
|
||||
ipcLockModule_HandleMsg,
|
||||
ipcLockModule_ClientUp,
|
||||
ipcLockModule_ClientDown
|
||||
};
|
||||
|
||||
static ipcModuleEntry gLockModuleEntry[] =
|
||||
{
|
||||
{ IPC_LOCK_TARGETID, &gLockMethods }
|
||||
};
|
||||
|
||||
IPC_IMPL_GETMODULES(ipcLockModule, gLockModuleEntry)
|
||||
@@ -1,52 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
|
||||
XPIDLSRCS = \
|
||||
ipcIService.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcIMessageObserver;
|
||||
interface ipcIClientObserver;
|
||||
interface ipcIClientQueryHandler;
|
||||
|
||||
/**
|
||||
* ipcIService
|
||||
*
|
||||
* the IPC service provides the means to communicate with an external IPC
|
||||
* daemon and/or other mozilla-based applications on the same physical system.
|
||||
* the IPC daemon hosts modules (some builtin and others dynamically loaded)
|
||||
* with which applications may interact.
|
||||
*
|
||||
* at application startup, the IPC service will attempt to establish a
|
||||
* connection with the IPC daemon. the IPC daemon will be automatically
|
||||
* started if necessary. when a connection has been established, the IPC
|
||||
* service will enumerate the "ipc-startup-category" and broadcast an
|
||||
* "ipc-startup" notification using the observer service.
|
||||
*
|
||||
* when the connection to the IPC daemon is closed, an "ipc-shutdown"
|
||||
* notification will be broadcast.
|
||||
*
|
||||
* each client has a name. the client name need not be unique across all
|
||||
* clients, but it is usually good if it is. the IPC service does not require
|
||||
* unique names. instead, the IPC daemon assigns each client a unique ID that
|
||||
* is good for the current "session." clients can query other clients by name
|
||||
* or by ID. the IPC service supports forwarding messages from one client to
|
||||
* another via the IPC daemon.
|
||||
*
|
||||
* for performance reasons, this system should not be used to transfer large
|
||||
* amounts of data. instead, applications may choose to utilize shared memory,
|
||||
* and rely on the IPC service for synchronization and small message transfer
|
||||
* only.
|
||||
*/
|
||||
[scriptable, uuid(53d3e3a7-528f-4b09-9eab-9416272568c0)]
|
||||
interface ipcIService : nsISupports
|
||||
{
|
||||
/**************************************************************************
|
||||
* properties of this process
|
||||
*/
|
||||
|
||||
/**
|
||||
* returns the "client ID" assigned to this process by the IPC daemon.
|
||||
*
|
||||
* @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon.
|
||||
*/
|
||||
readonly attribute unsigned long clientID;
|
||||
|
||||
/**
|
||||
* this process can appear under several client names. use the following
|
||||
* methods to add or remove names for this process.
|
||||
*
|
||||
* for example, the mozilla browser might have the primary name "mozilla",
|
||||
* but it could also register itself under the names "browser", "mail",
|
||||
* "news", "addrbook", etc. other IPC clients can then query the IPC
|
||||
* daemon for the client named "mail" in order to talk with a mail program.
|
||||
*
|
||||
* XXX An IPC client name resembles a XPCOM contract ID.
|
||||
*/
|
||||
void addClientName(in string aName);
|
||||
void removeClientName(in string aName);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* client query methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* query info about a particular client given its client name. the
|
||||
* observer's onClientInfo method is called with the result of the lookup,
|
||||
* or if there is no client matching the given name, the observer's
|
||||
* onClientDown method will be called instead.
|
||||
*
|
||||
* @param aName
|
||||
* the name of the client being queried.
|
||||
* @param aHandler
|
||||
* the handler to be notified with result.
|
||||
* @param aSync
|
||||
* block the calling thread until the query completes.
|
||||
*
|
||||
* @return integer value identifying this query.
|
||||
*/
|
||||
unsigned long queryClientByName(in string aName,
|
||||
in ipcIClientQueryHandler aHandler,
|
||||
in boolean aSync);
|
||||
|
||||
/**
|
||||
* query info about a particular client given its client ID. the observer's
|
||||
* onClientInfo method is called with the result of the lookup, or if there
|
||||
* is no client matching the given name, the observer's onClientDown method
|
||||
* will be called instead.
|
||||
*
|
||||
* @param aClientID
|
||||
* the ID of the client being queried.
|
||||
* @param aHandler
|
||||
* the handler to be notified with result.
|
||||
* @param aSync
|
||||
* block the calling thread until the query completes.
|
||||
*
|
||||
* @return integer value identifying this query.
|
||||
*/
|
||||
unsigned long queryClientByID(in unsigned long aClientID,
|
||||
in ipcIClientQueryHandler aHandler,
|
||||
in boolean aSync);
|
||||
|
||||
/**
|
||||
* called to cancel a pending query.
|
||||
*
|
||||
* @param aQueryID
|
||||
* the return value from one of the "query" methods.
|
||||
*/
|
||||
void cancelQuery(in unsigned long aQueryID);
|
||||
|
||||
/**
|
||||
* set client observer. observer's onClientUp method is called whenever
|
||||
* a new client comes online, and the observer's onClientDown method is
|
||||
* called whenever a client goes offline.
|
||||
*
|
||||
* @param aObserver
|
||||
* the client observer.
|
||||
*/
|
||||
void setClientObserver(in ipcIClientObserver aObserver);
|
||||
|
||||
// XXX need other functions to enumerate clients, clients implementing targets, etc.
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* message methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* set a message observer for a particular message target.
|
||||
*
|
||||
* @param aTarget
|
||||
* the message target being observed. any existing observer will
|
||||
* be replaced.
|
||||
* @param aObserver
|
||||
* the message observer to receive incoming messages for the
|
||||
* specified target. pass null to remove the existing observer.
|
||||
*/
|
||||
void setMessageObserver(in nsIDRef aTarget, in ipcIMessageObserver aObserver);
|
||||
|
||||
/**
|
||||
* send message asynchronously to a client or a module in the IPC daemon.
|
||||
* there is no guarantee that the message will be delivered.
|
||||
*
|
||||
* @param aClientID
|
||||
* the client ID of the foreign application that should receive this
|
||||
* message. pass 0 to send a message to a module in the IPC daemon.
|
||||
* @param aTarget
|
||||
* the target of the message. if aClientID is 0, then this is the
|
||||
* ID of the daemon module that should receive this message.
|
||||
* @param aData
|
||||
* the message data.
|
||||
* @param aDataLen
|
||||
* the message length.
|
||||
* @param aSync
|
||||
* block the calling thread until a response to this message is
|
||||
* received.
|
||||
*/
|
||||
void sendMessage(in unsigned long aClientID,
|
||||
in nsIDRef aTarget,
|
||||
[array, const, size_is(aDataLen)]
|
||||
in octet aData,
|
||||
in unsigned long aDataLen,
|
||||
in boolean aSync);
|
||||
};
|
||||
|
||||
/**
|
||||
* ipcIMessageObserver
|
||||
*/
|
||||
[scriptable, uuid(e40a4a3c-2dc1-470e-ab7f-5675fe1f1384)]
|
||||
interface ipcIMessageObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* @param aTarget
|
||||
* the target of the message, corresponding to the target this
|
||||
* observer was registered under. this parameter is passed to allow
|
||||
* an observer instance to receive messages for more than one target.
|
||||
* @param aData
|
||||
* the data of the message.
|
||||
* @param aDataLen
|
||||
* the data length of the message.
|
||||
*/
|
||||
void onMessageAvailable(in nsIDRef aTarget,
|
||||
[array, const, size_is(aDataLen)]
|
||||
in octet aData,
|
||||
in unsigned long aDataLen);
|
||||
};
|
||||
|
||||
/**
|
||||
* ipcIClientObserver
|
||||
*/
|
||||
[scriptable, uuid(42283079-030c-4b13-b069-a08b7ad5eab2)]
|
||||
interface ipcIClientObserver : nsISupports
|
||||
{
|
||||
const unsigned long CLIENT_UP = 1;
|
||||
const unsigned long CLIENT_DOWN = 2;
|
||||
|
||||
void onClientStatus(in unsigned long aClientID,
|
||||
in unsigned long aClientStatus);
|
||||
};
|
||||
|
||||
/**
|
||||
* ipcIClientQueryHandler
|
||||
*
|
||||
* the methods on this interface are called when the result of a client query
|
||||
* becomes available.
|
||||
*/
|
||||
[scriptable, uuid(6fefea5c-f747-4bb0-972f-2a7b363a01db)]
|
||||
interface ipcIClientQueryHandler : nsISupports
|
||||
{
|
||||
/**
|
||||
* called on completion of a client query.
|
||||
*
|
||||
* @param aQueryID
|
||||
* the return value from one of the "query" methods.
|
||||
* @param aStatus
|
||||
* the status of the query. if this is a failure code, then the
|
||||
* query failed, otherwise the query succeeded. the value of this
|
||||
* parameter explains the reason for any failure.
|
||||
* @param aClientID
|
||||
* ...
|
||||
*/
|
||||
void onQueryComplete(in unsigned long aQueryID,
|
||||
in nsresult aStatus,
|
||||
in unsigned long aClientID,
|
||||
[array, size_is(aNameCount)]
|
||||
in string aClientNames,
|
||||
in unsigned long aNameCount,
|
||||
[array, const, size_is(aTargetCount)]
|
||||
in nsIDPtr aClientTargets,
|
||||
in unsigned long aTargetCount);
|
||||
};
|
||||
|
||||
%{C++
|
||||
#define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category"
|
||||
#define IPC_SERVICE_STARTUP_TOPIC "ipc-startup"
|
||||
#define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown"
|
||||
|
||||
#define IPC_SERVICE_PREF_PRIMARY_CLIENT_NAME "ipc.primary-client-name"
|
||||
%}
|
||||
@@ -1,73 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = ipc
|
||||
LIBRARY_NAME = ipc_s
|
||||
EXPORT_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
MODULE_NAME = ipc
|
||||
|
||||
REQUIRES = \
|
||||
xpcom \
|
||||
string \
|
||||
necko \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
ipcService.cpp \
|
||||
ipcTransport.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
CPPSRCS += ipcTransportWin.cpp
|
||||
else
|
||||
CPPSRCS += ipcTransportUnix.cpp
|
||||
CPPSRCS += ipcSocketProviderUnix.cpp
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../common \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,556 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <stdlib.h>
|
||||
|
||||
#include "plstr.h"
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
#include "nsNetError.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcService.h"
|
||||
#include "ipcMessageUtils.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
ipcReleaseMessageObserver(nsHashKey *aKey, void *aData, void* aClosure)
|
||||
{
|
||||
ipcIMessageObserver *obs = (ipcIMessageObserver *) aData;
|
||||
NS_RELEASE(obs);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcClientQuery
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class ipcClientQuery
|
||||
{
|
||||
public:
|
||||
ipcClientQuery(PRUint32 cID, ipcIClientQueryHandler *handler)
|
||||
: mNext(nsnull)
|
||||
, mQueryID(++gLastQueryID)
|
||||
, mClientID(cID)
|
||||
, mHandler(handler)
|
||||
{ }
|
||||
|
||||
static PRUint32 gLastQueryID;
|
||||
|
||||
void SetClientID(PRUint32 cID) { mClientID = cID; }
|
||||
void OnQueryComplete(nsresult status, const ipcmMessageClientInfo *msg);
|
||||
|
||||
PRUint32 QueryID() { return mQueryID; }
|
||||
PRBool IsCanceled() { return mHandler.get() == NULL; }
|
||||
|
||||
ipcClientQuery *mNext;
|
||||
private:
|
||||
PRUint32 mQueryID;
|
||||
PRUint32 mClientID;
|
||||
nsCOMPtr<ipcIClientQueryHandler> mHandler;
|
||||
};
|
||||
|
||||
PRUint32 ipcClientQuery::gLastQueryID = 0;
|
||||
|
||||
void
|
||||
ipcClientQuery::OnQueryComplete(nsresult status, const ipcmMessageClientInfo *msg)
|
||||
{
|
||||
NS_ASSERTION(mHandler, "no handler");
|
||||
|
||||
PRUint32 nameCount = 0;
|
||||
PRUint32 targetCount = 0;
|
||||
const char **names = NULL;
|
||||
const nsID **targets = NULL;
|
||||
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
nameCount = msg->NameCount();
|
||||
targetCount = msg->TargetCount();
|
||||
PRUint32 i;
|
||||
|
||||
names = (const char **) malloc(nameCount * sizeof(char *));
|
||||
const char *lastName = NULL;
|
||||
for (i = 0; i < nameCount; ++i) {
|
||||
lastName = msg->NextName(lastName);
|
||||
names[i] = lastName;
|
||||
}
|
||||
|
||||
targets = (const nsID **) malloc(targetCount * sizeof(nsID *));
|
||||
const nsID *lastTarget = NULL;
|
||||
for (i = 0; i < targetCount; ++i) {
|
||||
lastTarget = msg->NextTarget(lastTarget);
|
||||
targets[i] = lastTarget;
|
||||
}
|
||||
}
|
||||
|
||||
mHandler->OnQueryComplete(mQueryID,
|
||||
status,
|
||||
mClientID,
|
||||
names, nameCount,
|
||||
targets, targetCount);
|
||||
mHandler = NULL;
|
||||
|
||||
if (names)
|
||||
free(names);
|
||||
if (targets)
|
||||
free(targets);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcService
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ipcService::ipcService()
|
||||
: mTransport(nsnull)
|
||||
, mClientID(0)
|
||||
#if 0
|
||||
, mDelayedMsgQ(nsnull)
|
||||
, mWaiting(PR_FALSE)
|
||||
, mInWaitMessage(PR_FALSE)
|
||||
#endif
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
|
||||
IPC_InitLog(">>>");
|
||||
}
|
||||
|
||||
ipcService::~ipcService()
|
||||
{
|
||||
NS_ASSERTION(mTransport == nsnull, "no xpcom-shutdown event??");
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcService::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observ(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (observ) {
|
||||
observ->AddObserver(this, "xpcom-shutdown", PR_FALSE);
|
||||
observ->AddObserver(this, "profile-change-net-teardown", PR_FALSE);
|
||||
observ->AddObserver(this, "profile-change-net-restore", PR_FALSE);
|
||||
}
|
||||
|
||||
mTransport = new ipcTransport();
|
||||
if (!mTransport)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(mTransport);
|
||||
|
||||
rv = mTransport->Init(this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnIPCMClientID(const ipcmMessageClientID *msg)
|
||||
{
|
||||
LOG(("ipcService::OnIPCMClientID\n"));
|
||||
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
if (!query) {
|
||||
NS_WARNING("no pending query; ignoring message.");
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 cID = msg->ClientID();
|
||||
PRBool sync = msg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY);
|
||||
|
||||
//
|
||||
// (1) store client ID in query
|
||||
// (2) move query to end of queue
|
||||
// (3) issue CLIENT_INFO request
|
||||
//
|
||||
query->SetClientID(cID);
|
||||
|
||||
mQueryQ.RemoveFirst();
|
||||
mQueryQ.Append(query);
|
||||
|
||||
mTransport->SendMsg(new ipcmMessageQueryClientInfo(cID), sync);
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnIPCMClientInfo(const ipcmMessageClientInfo *msg)
|
||||
{
|
||||
LOG(("ipcService::OnIPCMClientInfo\n"));
|
||||
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
if (!query) {
|
||||
NS_WARNING("no pending query; ignoring message.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!query->IsCanceled())
|
||||
query->OnQueryComplete(NS_OK, msg);
|
||||
|
||||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnIPCMError(const ipcmMessageError *msg)
|
||||
{
|
||||
LOG(("ipcService::OnIPCMError [reason=0x%08x]\n", msg->Reason()));
|
||||
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
if (!query) {
|
||||
NS_WARNING("no pending query; ignoring message.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!query->IsCanceled())
|
||||
query->OnQueryComplete(NS_ERROR_FAILURE, NULL);
|
||||
|
||||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ipcService::
|
||||
ProcessDelayedMsgQ_Event::ProcessDelayedMsgQ_Event(ipcService *serv,
|
||||
ipcMessageQ *msgQ)
|
||||
{
|
||||
NS_ADDREF(mServ = serv);
|
||||
mMsgQ = msgQ;
|
||||
}
|
||||
|
||||
ipcService::
|
||||
ProcessDelayedMsgQ_Event::~ProcessDelayedMsgQ_Event()
|
||||
{
|
||||
NS_RELEASE(mServ);
|
||||
}
|
||||
|
||||
void * PR_CALLBACK
|
||||
ipcService::ProcessDelayedMsgQ_EventHandler(PLEvent *plevent)
|
||||
{
|
||||
LOG(("ipcService::ProcessDelayedMsgQ_EventHandler\n"));
|
||||
|
||||
ProcessDelayedMsgQ_Event *ev = (ProcessDelayedMsgQ_Event *) plevent;
|
||||
|
||||
while (!ev->mMsgQ->IsEmpty()) {
|
||||
ipcMessage *msg = ev->mMsgQ->First();
|
||||
ev->mMsgQ->RemoveFirst();
|
||||
ev->mServ->OnMessageAvailable(msg);
|
||||
delete msg;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void PR_CALLBACK
|
||||
ipcService::ProcessDelayedMsgQ_EventCleanup(PLEvent *plevent)
|
||||
{
|
||||
delete (ProcessDelayedMsgQ_Event *) plevent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// interface impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS2(ipcService, ipcIService, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::GetClientID(PRUint32 *clientID)
|
||||
{
|
||||
if (mClientID == 0)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
*clientID = mClientID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::AddClientName(const char *name)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
ipcMessage *msg = new ipcmMessageClientAddName(name);
|
||||
if (!msg)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return mTransport->SendMsg(msg);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::RemoveClientName(const char *name)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
ipcMessage *msg = new ipcmMessageClientDelName(name);
|
||||
if (!msg)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return mTransport->SendMsg(msg);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::QueryClientByName(const char *name,
|
||||
ipcIClientQueryHandler *handler,
|
||||
PRBool sync,
|
||||
PRUint32 *queryID)
|
||||
{
|
||||
if (!mTransport)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
ipcMessage *msg;
|
||||
|
||||
msg = new ipcmMessageQueryClientByName(name);
|
||||
if (!msg)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
rv = mTransport->SendMsg(msg, sync);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
ipcClientQuery *query = new ipcClientQuery(0, handler);
|
||||
if (queryID)
|
||||
*queryID = query->QueryID();
|
||||
mQueryQ.Append(query);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::QueryClientByID(PRUint32 clientID,
|
||||
ipcIClientQueryHandler *handler,
|
||||
PRBool sync,
|
||||
PRUint32 *queryID)
|
||||
{
|
||||
if (!mTransport)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
ipcMessage *msg;
|
||||
|
||||
msg = new ipcmMessageQueryClientInfo(clientID);
|
||||
if (!msg)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
rv = mTransport->SendMsg(msg, sync);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
ipcClientQuery *query = new ipcClientQuery(clientID, handler);
|
||||
if (queryID)
|
||||
*queryID = query->QueryID();
|
||||
mQueryQ.Append(query);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::CancelQuery(PRUint32 queryID)
|
||||
{
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
while (query) {
|
||||
if (query->QueryID() == queryID) {
|
||||
query->OnQueryComplete(NS_BINDING_ABORTED, NULL);
|
||||
break;
|
||||
}
|
||||
query = query->mNext;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::SetClientObserver(ipcIClientObserver *observer)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::SetMessageObserver(const nsID &target, ipcIMessageObserver *observer)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsIDKey key(target);
|
||||
PRBool sendAdd = PR_TRUE;
|
||||
|
||||
ipcIMessageObserver *cobs = (ipcIMessageObserver *) mObserverDB.Get(&key);
|
||||
if (cobs) {
|
||||
NS_RELEASE(cobs);
|
||||
if (!observer) {
|
||||
mObserverDB.Remove(&key);
|
||||
//
|
||||
// send CLIENT_DEL_TARGET
|
||||
//
|
||||
mTransport->SendMsg(new ipcmMessageClientDelTarget(target));
|
||||
return NS_OK;
|
||||
}
|
||||
sendAdd = PR_FALSE;
|
||||
}
|
||||
if (observer) {
|
||||
NS_ADDREF(observer);
|
||||
mObserverDB.Put(&key, observer);
|
||||
if (sendAdd) {
|
||||
//
|
||||
// send CLIENT_ADD_TARGET
|
||||
//
|
||||
mTransport->SendMsg(new ipcmMessageClientAddTarget(target));
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::SendMessage(PRUint32 clientID,
|
||||
const nsID &target,
|
||||
const PRUint8 *data,
|
||||
PRUint32 dataLen,
|
||||
PRBool sync)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (target.Equals(IPCM_TARGET)) {
|
||||
NS_ERROR("do not try to talk to the IPCM target directly");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ipcMessage *msg;
|
||||
if (clientID)
|
||||
msg = new ipcmMessageForward(clientID, target, (const char *) data, dataLen);
|
||||
else
|
||||
msg = new ipcMessage(target, (const char *) data, dataLen);
|
||||
|
||||
if (!msg)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return mTransport->SendMsg(msg, sync);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIObserver impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
|
||||
{
|
||||
if (strcmp(topic, "xpcom-shutdown") == 0 ||
|
||||
strcmp(topic, "profile-change-net-teardown") == 0) {
|
||||
// disconnect any message observers
|
||||
mObserverDB.Reset(ipcReleaseMessageObserver, nsnull);
|
||||
|
||||
// drop daemon connection
|
||||
if (mTransport)
|
||||
mTransport->Shutdown();
|
||||
}
|
||||
else if (strcmp(topic, "profile-change-net-restore") == 0) {
|
||||
if (mTransport)
|
||||
mTransport->Init(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransportObserver impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
ipcService::OnConnectionEstablished(PRUint32 clientID)
|
||||
{
|
||||
mClientID = clientID;
|
||||
|
||||
//
|
||||
// enumerate ipc startup category...
|
||||
//
|
||||
NS_CreateServicesFromCategory(IPC_SERVICE_STARTUP_CATEGORY,
|
||||
NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_STARTUP_TOPIC);
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnConnectionLost()
|
||||
{
|
||||
mClientID = 0;
|
||||
|
||||
//
|
||||
// error out any pending queries
|
||||
//
|
||||
while (mQueryQ.First()) {
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
query->OnQueryComplete(NS_BINDING_ABORTED, NULL);
|
||||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
//
|
||||
// broadcast ipc shutdown...
|
||||
//
|
||||
nsCOMPtr<nsIObserverService> observ(
|
||||
do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (observ)
|
||||
observ->NotifyObservers(NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_SHUTDOWN_TOPIC, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnMessageAvailable(const ipcMessage *msg)
|
||||
{
|
||||
LOG(("ipcService::OnMessageAvailable [msg=%p]\n", msg));
|
||||
|
||||
if (msg->Target().Equals(IPCM_TARGET)) {
|
||||
//
|
||||
// all IPCM messages stop here.
|
||||
//
|
||||
PRUint32 type = IPCM_GetMsgType(msg);
|
||||
switch (type) {
|
||||
case IPCM_MSG_TYPE_CLIENT_ID:
|
||||
OnIPCMClientID((const ipcmMessageClientID *) msg);
|
||||
break;
|
||||
case IPCM_MSG_TYPE_CLIENT_INFO:
|
||||
OnIPCMClientInfo((const ipcmMessageClientInfo *) msg);
|
||||
break;
|
||||
case IPCM_MSG_TYPE_ERROR:
|
||||
OnIPCMError((const ipcmMessageError *) msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsIDKey key(msg->Target());
|
||||
ipcIMessageObserver *observer = (ipcIMessageObserver *) mObserverDB.Get(&key);
|
||||
if (observer)
|
||||
observer->OnMessageAvailable(msg->Target(),
|
||||
(const PRUint8 *) msg->Data(),
|
||||
msg->DataLen());
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcService_h__
|
||||
#define ipcService_h__
|
||||
|
||||
#include "nsIRequest.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "plevent.h"
|
||||
|
||||
#include "ipcIService.h"
|
||||
#include "ipcTransport.h"
|
||||
#include "ipcList.h"
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcMessageQ.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
typedef ipcList<class ipcClientQuery> ipcClientQueryQ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcService
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class ipcService : public ipcIService
|
||||
, public ipcTransportObserver
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IPCISERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
ipcService();
|
||||
virtual ~ipcService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
// ipcTransportObserver:
|
||||
void OnConnectionEstablished(PRUint32 clientID);
|
||||
void OnConnectionLost();
|
||||
void OnMessageAvailable(const ipcMessage *);
|
||||
|
||||
//PRBool InWaitMessage() { return mInWaitMessage; }
|
||||
|
||||
private:
|
||||
nsresult ErrorAccordingToIPCM(PRUint32 err);
|
||||
void OnIPCMClientID(const ipcmMessageClientID *);
|
||||
void OnIPCMClientInfo(const ipcmMessageClientInfo *);
|
||||
void OnIPCMError(const ipcmMessageError *);
|
||||
|
||||
struct ProcessDelayedMsgQ_Event : PLEvent {
|
||||
ProcessDelayedMsgQ_Event(ipcService *, ipcMessageQ *);
|
||||
~ProcessDelayedMsgQ_Event();
|
||||
ipcService *mServ;
|
||||
ipcMessageQ *mMsgQ;
|
||||
};
|
||||
PR_STATIC_CALLBACK(void*) ProcessDelayedMsgQ_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void) ProcessDelayedMsgQ_EventCleanup(PLEvent *);
|
||||
|
||||
nsHashtable mObserverDB;
|
||||
ipcTransport *mTransport;
|
||||
PRUint32 mClientID;
|
||||
|
||||
ipcClientQueryQ mQueryQ;
|
||||
|
||||
#if 0
|
||||
// WaitMessage support
|
||||
ipcMessageQ *mDelayedMsgQ;
|
||||
nsID mWaitingTarget;
|
||||
PRPackedBool mWaiting;
|
||||
PRPackedBool mInWaitMessage;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // !ipcService_h__
|
||||
@@ -1,187 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private/pprio.h"
|
||||
#include "plstr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
#include "ipcSocketProviderUnix.h"
|
||||
#include "ipcLog.h"
|
||||
|
||||
static PRDescIdentity ipcIOLayerIdentity;
|
||||
static PRIOMethods ipcIOLayerMethods;
|
||||
static char *ipcIOSocketPath;
|
||||
|
||||
static PRStatus PR_CALLBACK
|
||||
ipcIOLayerConnect(PRFileDesc* fd, const PRNetAddr* a, PRIntervalTime timeout)
|
||||
{
|
||||
if (!fd || !fd->lower)
|
||||
return PR_FAILURE;
|
||||
|
||||
PRStatus status;
|
||||
|
||||
if (!ipcIOSocketPath || !ipcIOSocketPath[0]) {
|
||||
NS_ERROR("not initialized");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
//
|
||||
// ignore passed in address.
|
||||
//
|
||||
PRNetAddr addr;
|
||||
addr.local.family = PR_AF_LOCAL;
|
||||
PL_strncpyz(addr.local.path, ipcIOSocketPath, sizeof(addr.local.path));
|
||||
|
||||
status = fd->lower->methods->connect(fd->lower, &addr, timeout);
|
||||
if (status != PR_SUCCESS)
|
||||
return status;
|
||||
|
||||
//
|
||||
// now that we have a connected socket; do some security checks on the
|
||||
// file descriptor.
|
||||
//
|
||||
// (1) make sure owner matches
|
||||
// (2) make sure permissions match expected permissions
|
||||
//
|
||||
// if these conditions aren't met then bail.
|
||||
//
|
||||
int unix_fd = PR_FileDesc2NativeHandle(fd->lower);
|
||||
|
||||
struct stat st;
|
||||
if (fstat(unix_fd, &st) == -1) {
|
||||
NS_ERROR("stat failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
if (st.st_uid != getuid() && st.st_uid != geteuid()) {
|
||||
//
|
||||
// on OSX 10.1.5, |fstat| has a bug when passed a file descriptor to
|
||||
// a socket. it incorrectly returns a UID of 0. however, |stat|
|
||||
// succeeds, but using |stat| introduces a race condition.
|
||||
//
|
||||
// XXX come up with a better security check.
|
||||
//
|
||||
if (st.st_uid != 0) {
|
||||
NS_ERROR("userid check failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
if (stat(ipcIOSocketPath, &st) == -1) {
|
||||
NS_ERROR("stat failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
if (st.st_uid != getuid() && st.st_uid != geteuid()) {
|
||||
NS_ERROR("userid check failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
static void InitIPCMethods()
|
||||
{
|
||||
ipcIOLayerIdentity = PR_GetUniqueIdentity("moz:ipc-layer");
|
||||
|
||||
ipcIOLayerMethods = *PR_GetDefaultIOMethods();
|
||||
ipcIOLayerMethods.connect = ipcIOLayerConnect;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcSocketProviderUnix::NewSocket(const char *host,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRFileDesc **fd,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
static PRBool firstTime = PR_TRUE;
|
||||
if (firstTime) {
|
||||
InitIPCMethods();
|
||||
firstTime = PR_FALSE;
|
||||
}
|
||||
|
||||
PRFileDesc *sock = PR_OpenTCPSocket(PR_AF_LOCAL);
|
||||
if (!sock) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PRFileDesc *layer = PR_CreateIOLayerStub(ipcIOLayerIdentity, &ipcIOLayerMethods);
|
||||
if (!layer)
|
||||
goto loser;
|
||||
layer->secret = nsnull;
|
||||
|
||||
if (PR_PushIOLayer(sock, PR_GetLayersIdentity(sock), layer) != PR_SUCCESS)
|
||||
goto loser;
|
||||
|
||||
*fd = sock;
|
||||
return NS_OK;
|
||||
|
||||
loser:
|
||||
if (layer)
|
||||
layer->dtor(layer);
|
||||
if (sock)
|
||||
PR_Close(sock);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcSocketProviderUnix::AddToSocket(const char *host,
|
||||
PRInt32 port,
|
||||
const char *proxyHost,
|
||||
PRInt32 proxyPort,
|
||||
PRFileDesc *fd,
|
||||
nsISupports **securityInfo)
|
||||
{
|
||||
NS_NOTREACHED("unexpected");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(ipcSocketProviderUnix, nsISocketProvider)
|
||||
|
||||
|
||||
void
|
||||
ipcSocketProviderUnix::SetSocketPath(const char *socketPath)
|
||||
{
|
||||
if (ipcIOSocketPath)
|
||||
free(ipcIOSocketPath);
|
||||
ipcIOSocketPath = socketPath ? strdup(socketPath) : nsnull;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcSocketProviderUnix_h__
|
||||
#define ipcSocketProviderUnix_h__
|
||||
|
||||
#include "nsISocketProvider.h"
|
||||
|
||||
class ipcSocketProviderUnix : public nsISocketProvider
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISOCKETPROVIDER
|
||||
|
||||
ipcSocketProviderUnix() { NS_INIT_ISUPPORTS(); }
|
||||
virtual ~ipcSocketProviderUnix() { }
|
||||
|
||||
//
|
||||
// called to initialize the socket path
|
||||
//
|
||||
static void SetSocketPath(const char *socketPath);
|
||||
};
|
||||
|
||||
#endif // !ipcSocketProviderUnix_h__
|
||||
@@ -1,341 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "nsIObserverService.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIProcess.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "netCore.h"
|
||||
#include "prerror.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcMessageUtils.h"
|
||||
#include "ipcTransport.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransport
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
ipcTransport::Init(ipcTransportObserver *obs)
|
||||
{
|
||||
LOG(("ipcTransport::Init\n"));
|
||||
|
||||
mObserver = obs;
|
||||
|
||||
nsresult rv = PlatformInit();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return Connect();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::Shutdown()
|
||||
{
|
||||
LOG(("ipcTransport::Shutdown\n"));
|
||||
|
||||
mObserver = 0;
|
||||
return Disconnect();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::SendMsg(ipcMessage *msg, PRBool sync)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(msg);
|
||||
NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
LOG(("ipcTransport::SendMsg [msg=%p dataLen=%u]\n", msg, msg->DataLen()));
|
||||
|
||||
ipcMessage *syncReply = nsnull;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
nsresult rv;
|
||||
|
||||
if (sync) {
|
||||
msg->SetFlag(IPC_MSG_FLAG_SYNC_QUERY);
|
||||
// flag before sending to avoid race with background thread.
|
||||
mSyncWaiting = PR_TRUE;
|
||||
}
|
||||
|
||||
if (mHaveConnection) {
|
||||
rv = SendMsg_Internal(msg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else {
|
||||
LOG((" delaying message until connected\n"));
|
||||
mDelayedQ.Append(msg);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
if (!mSyncReplyMsg) {
|
||||
LOG((" waiting for response...\n"));
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
if (!mSyncReplyMsg) {
|
||||
LOG((" sync request timed out or was canceled\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
syncReply = mSyncReplyMsg;
|
||||
mSyncReplyMsg = nsnull;
|
||||
}
|
||||
}
|
||||
if (syncReply) {
|
||||
// NOTE: may re-enter SendMsg
|
||||
mObserver->OnMessageAvailable(syncReply);
|
||||
delete syncReply;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ipcTransport::ProcessIncomingMsgQ()
|
||||
{
|
||||
LOG(("ipcTransport::ProcessIncomingMsgQ\n"));
|
||||
|
||||
// we can't hold mMonitor while calling into the observer, so we grab
|
||||
// mIncomingMsgQ and NULL it out inside the monitor to prevent others
|
||||
// from modifying it while we iterate over it.
|
||||
ipcMessageQ *inQ;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
inQ = mIncomingMsgQ;
|
||||
mIncomingMsgQ = nsnull;
|
||||
}
|
||||
if (inQ) {
|
||||
while (!inQ->IsEmpty()) {
|
||||
ipcMessage *msg = inQ->First();
|
||||
if (mObserver)
|
||||
mObserver->OnMessageAvailable(msg);
|
||||
inQ->DeleteFirst();
|
||||
}
|
||||
delete inQ;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
ipcTransport::ProcessIncomingMsgQ_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
self->ProcessIncomingMsgQ();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void *
|
||||
ipcTransport::ConnectionEstablished_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
if (self->mObserver)
|
||||
self->mObserver->OnConnectionEstablished(self->mClientID);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void *
|
||||
ipcTransport::ConnectionLost_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
if (self->mObserver)
|
||||
self->mObserver->OnConnectionLost();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
ipcTransport::Generic_EventCleanup(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
NS_RELEASE(self);
|
||||
delete ev;
|
||||
}
|
||||
|
||||
// called on a background thread
|
||||
void
|
||||
ipcTransport::OnMessageAvailable(ipcMessage *rawMsg)
|
||||
{
|
||||
LOG(("ipcTransport::OnMessageAvailable [msg=%p dataLen=%u]\n",
|
||||
rawMsg, rawMsg->DataLen()));
|
||||
|
||||
//
|
||||
// XXX FIX COMMENTS XXX
|
||||
//
|
||||
// 1- append to incoming message queue
|
||||
//
|
||||
// 2- post event to main thread to handle incoming message queue
|
||||
// or if sync waiting, unblock waiter so it can scan incoming
|
||||
// message queue.
|
||||
//
|
||||
|
||||
PRBool dispatchEvent = PR_FALSE;
|
||||
PRBool connectEvent = PR_FALSE;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (!mHaveConnection) {
|
||||
if (rawMsg->Target().Equals(IPCM_TARGET)) {
|
||||
if (IPCM_GetMsgType(rawMsg) == IPCM_MSG_TYPE_CLIENT_ID) {
|
||||
LOG((" connection established!\n"));
|
||||
mHaveConnection = PR_TRUE;
|
||||
|
||||
// remember our client ID
|
||||
ipcMessageCast<ipcmMessageClientID> msg(rawMsg);
|
||||
mClientID = msg->ClientID();
|
||||
connectEvent = PR_TRUE;
|
||||
|
||||
// move messages off the delayed message queue
|
||||
while (!mDelayedQ.IsEmpty()) {
|
||||
ipcMessage *msg = mDelayedQ.First();
|
||||
mDelayedQ.RemoveFirst();
|
||||
SendMsg_Internal(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG((" received unexpected first message!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG((" mSyncWaiting=%u MSG_FLAG_SYNC_REPLY=%u\n",
|
||||
mSyncWaiting, rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY) != 0));
|
||||
|
||||
if (mSyncWaiting && rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY)) {
|
||||
mSyncReplyMsg = rawMsg;
|
||||
mSyncWaiting = PR_FALSE;
|
||||
mon.Notify();
|
||||
}
|
||||
else {
|
||||
if (!mIncomingMsgQ) {
|
||||
mIncomingMsgQ = new ipcMessageQ();
|
||||
if (!mIncomingMsgQ)
|
||||
return;
|
||||
dispatchEvent = PR_TRUE;
|
||||
}
|
||||
mIncomingMsgQ->Append(rawMsg);
|
||||
}
|
||||
|
||||
LOG((" connectEvent=%u dispatchEvent=%u mSyncReplyMsg=%p mIncomingMsgQ=%p\n",
|
||||
connectEvent, dispatchEvent, mSyncReplyMsg, mIncomingMsgQ));
|
||||
}
|
||||
|
||||
if (connectEvent)
|
||||
ProxyToMainThread(ConnectionEstablished_EventHandler);
|
||||
if (dispatchEvent)
|
||||
ProxyToMainThread(ProcessIncomingMsgQ_EventHandler);
|
||||
}
|
||||
|
||||
void
|
||||
ipcTransport::ProxyToMainThread(PLHandleEventProc proc)
|
||||
{
|
||||
LOG(("ipcTransport::ProxyToMainThread\n"));
|
||||
|
||||
nsCOMPtr<nsIEventQueue> eq;
|
||||
NS_GetMainEventQ(getter_AddRefs(eq));
|
||||
if (eq) {
|
||||
PLEvent *ev = new PLEvent();
|
||||
PL_InitEvent(ev, this, proc, Generic_EventCleanup);
|
||||
NS_ADDREF_THIS();
|
||||
if (eq->PostEvent(ev) == PR_FAILURE) {
|
||||
LOG((" PostEvent failed"));
|
||||
NS_RELEASE_THIS();
|
||||
delete ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::SpawnDaemon()
|
||||
{
|
||||
LOG(("ipcTransport::SpawnDaemon\n"));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> file;
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIProcess> proc(do_CreateInstance(NS_PROCESS_CONTRACTID,&rv));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = proc->Init(file);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 pid;
|
||||
return proc->Run(PR_FALSE, nsnull, 0, &pid);
|
||||
}
|
||||
|
||||
// called on a background thread
|
||||
nsresult
|
||||
ipcTransport::OnConnectFailure()
|
||||
{
|
||||
LOG(("ipcTransport::OnConnectFailure\n"));
|
||||
|
||||
nsresult rv;
|
||||
if (!mSpawnedDaemon) {
|
||||
//
|
||||
// spawn daemon on connection failure
|
||||
//
|
||||
rv = SpawnDaemon();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" failed to spawn daemon [rv=%x]\n", rv));
|
||||
return rv;
|
||||
}
|
||||
mSpawnedDaemon = PR_TRUE;
|
||||
}
|
||||
|
||||
Disconnect();
|
||||
|
||||
PRUint32 ms = 50 * mConnectionAttemptCount;
|
||||
LOG((" sleeping for %u ms...\n", ms));
|
||||
PR_Sleep(PR_MillisecondsToInterval(ms));
|
||||
|
||||
Connect();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS0(ipcTransport)
|
||||
@@ -1,169 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcTransport_h__
|
||||
#define ipcTransport_h__
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prmon.h"
|
||||
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcMessageQ.h"
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include "ipcTransportUnix.h"
|
||||
typedef nsISocketEventHandler ipcTransportSuper;
|
||||
#else
|
||||
typedef nsISupports ipcTransportSuper;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcTransportObserver interface
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class ipcTransportObserver
|
||||
{
|
||||
public:
|
||||
virtual void OnConnectionEstablished(PRUint32 clientID) = 0;
|
||||
virtual void OnConnectionLost() = 0;
|
||||
virtual void OnMessageAvailable(const ipcMessage *) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransport
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcTransport : public ipcTransportSuper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ipcTransport()
|
||||
: mMonitor(PR_NewMonitor())
|
||||
, mObserver(nsnull)
|
||||
, mIncomingMsgQ(nsnull)
|
||||
, mSyncReplyMsg(nsnull)
|
||||
, mSyncWaiting(nsnull)
|
||||
, mSentHello(PR_FALSE)
|
||||
, mHaveConnection(PR_FALSE)
|
||||
, mSpawnedDaemon(PR_FALSE)
|
||||
, mConnectionAttemptCount(0)
|
||||
, mClientID(0)
|
||||
{}
|
||||
|
||||
virtual ~ipcTransport()
|
||||
{
|
||||
PR_DestroyMonitor(mMonitor);
|
||||
#ifdef XP_UNIX
|
||||
if (mReceiver)
|
||||
((ipcReceiver *) mReceiver.get())->ClearTransport();
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult Init(ipcTransportObserver *observer);
|
||||
nsresult Shutdown();
|
||||
|
||||
// takes ownership of |msg|
|
||||
nsresult SendMsg(ipcMessage *msg, PRBool sync = PR_FALSE);
|
||||
|
||||
PRBool HaveConnection() const { return mHaveConnection; }
|
||||
|
||||
public:
|
||||
//
|
||||
// internal to implementation
|
||||
//
|
||||
void OnMessageAvailable(ipcMessage *); // takes ownership
|
||||
|
||||
private:
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
nsresult PlatformInit();
|
||||
nsresult Connect();
|
||||
nsresult Disconnect();
|
||||
nsresult OnConnectFailure();
|
||||
nsresult SendMsg_Internal(ipcMessage *msg);
|
||||
nsresult SpawnDaemon();
|
||||
void ProxyToMainThread(PLHandleEventProc);
|
||||
void ProcessIncomingMsgQ();
|
||||
|
||||
PR_STATIC_CALLBACK(void *) ProcessIncomingMsgQ_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void *) ConnectionEstablished_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void *) ConnectionLost_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void) Generic_EventCleanup(PLEvent *);
|
||||
|
||||
//
|
||||
// data
|
||||
//
|
||||
PRMonitor *mMonitor;
|
||||
ipcTransportObserver *mObserver; // weak reference
|
||||
ipcMessageQ mDelayedQ;
|
||||
ipcMessageQ *mIncomingMsgQ;
|
||||
ipcMessage *mSyncReplyMsg;
|
||||
PRPackedBool mSyncWaiting;
|
||||
PRPackedBool mSentHello;
|
||||
PRPackedBool mHaveConnection;
|
||||
PRPackedBool mSpawnedDaemon;
|
||||
PRUint32 mConnectionAttemptCount;
|
||||
PRUint32 mClientID;
|
||||
|
||||
#ifdef XP_UNIX
|
||||
nsCOMPtr<nsIInputStreamNotify> mReceiver;
|
||||
nsCOMPtr<nsISocketTransport> mTransport;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
|
||||
//
|
||||
// unix specific helpers
|
||||
//
|
||||
nsresult CreateTransport();
|
||||
nsresult GetSocketPath(nsACString &);
|
||||
|
||||
public:
|
||||
NS_DECL_NSISOCKETEVENTHANDLER
|
||||
|
||||
//
|
||||
// internal helper methods
|
||||
//
|
||||
void OnConnectionLost(nsresult reason);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // !ipcTransport_h__
|
||||
@@ -1,355 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "prenv.h"
|
||||
|
||||
#include "nsIThread.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "ipcSocketProviderUnix.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetError.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcTransportUnix.h"
|
||||
#include "ipcTransport.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||
|
||||
#define IPC_BUFFER_SEGMENT_SIZE 4096
|
||||
|
||||
// for use with nsISocketTransportService::PostEvent
|
||||
enum {
|
||||
IPC_TRANSPORT_EVENT_CONNECT,
|
||||
IPC_TRANSPORT_EVENT_DISCONNECT,
|
||||
IPC_TRANSPORT_EVENT_SENDMSG
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransport (XP_UNIX specific methods)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
ipcTransport::PlatformInit()
|
||||
{
|
||||
PRNetAddr addr; // this way we know our buffer is large enough ;-)
|
||||
IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path));
|
||||
|
||||
ipcSocketProviderUnix::SetSocketPath(addr.local.path);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_METHOD ipcWriteMessage(nsIOutputStream *stream,
|
||||
void *closure,
|
||||
char *segment,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 *countWritten)
|
||||
{
|
||||
ipcMessage *msg = (ipcMessage *) closure;
|
||||
|
||||
PRBool complete;
|
||||
PRStatus rv = msg->WriteTo(segment, count, countWritten, &complete);
|
||||
NS_ASSERTION(rv == PR_SUCCESS, "failed to write message");
|
||||
|
||||
// stop writing once the message has been completely written.
|
||||
if (*countWritten == 0 && complete)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// runs on main thread or socket thread
|
||||
nsresult
|
||||
ipcTransport::SendMsg_Internal(ipcMessage *msg)
|
||||
{
|
||||
LOG(("ipcTransport::SendMsg_Internal [msg=%p dataLen=%u]\n", msg, msg->DataLen()));
|
||||
|
||||
if (nsIThread::IsMainThread()) {
|
||||
LOG((" proxy to socket thread\n"));
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISocketTransportService> sts(
|
||||
do_GetService(kSocketTransportServiceCID, &rv)); // XXX cache service
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return sts->PostEvent(this, IPC_TRANSPORT_EVENT_SENDMSG, 0, msg);
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mOutputStream, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv;
|
||||
PRUint32 n;
|
||||
|
||||
rv = mOutputStream->WriteSegments(ipcWriteMessage, msg, msg->MsgLen(), &n);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ASSERTION(n == msg->MsgLen(), "not all bytes written");
|
||||
|
||||
delete msg; // done with message
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// runs on main thread or socket thread
|
||||
nsresult
|
||||
ipcTransport::Connect()
|
||||
{
|
||||
LOG(("ipcTransport::Connect\n"));
|
||||
|
||||
if (++mConnectionAttemptCount > 20) {
|
||||
LOG((" giving up after 20 unsuccessful connection attempts\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (nsIThread::IsMainThread()) {
|
||||
LOG((" proxy to socket thread\n"));
|
||||
nsCOMPtr<nsISocketTransportService> sts(
|
||||
do_GetService(kSocketTransportServiceCID, &rv)); // XXX cache service
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return sts->PostEvent(this, IPC_TRANSPORT_EVENT_CONNECT, 0, nsnull);
|
||||
}
|
||||
|
||||
rv = CreateTransport();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
//
|
||||
// send CLIENT_HELLO; expect CLIENT_ID in response.
|
||||
//
|
||||
rv = SendMsg_Internal(new ipcmMessageClientHello());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
//
|
||||
// put the receiver to work...
|
||||
//
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncIn = do_QueryInterface(mInputStream, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!mReceiver) {
|
||||
mReceiver = new ipcReceiver(this);
|
||||
if (!mReceiver)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return asyncIn->AsyncWait(mReceiver, 0, nsnull);
|
||||
}
|
||||
|
||||
// runs on main thread or socket thread
|
||||
nsresult
|
||||
ipcTransport::Disconnect()
|
||||
{
|
||||
if (nsIThread::IsMainThread()) {
|
||||
LOG((" proxy to socket thread\n"));
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISocketTransportService> sts(
|
||||
do_GetService(kSocketTransportServiceCID, &rv)); // XXX cache service
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return sts->PostEvent(this, IPC_TRANSPORT_EVENT_DISCONNECT, 0, nsnull);
|
||||
}
|
||||
|
||||
mHaveConnection = PR_FALSE;
|
||||
if (mTransport) {
|
||||
mTransport->Close(NS_BINDING_ABORTED);
|
||||
mTransport = nsnull;
|
||||
mInputStream = nsnull;
|
||||
mOutputStream = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// runs on socket transport thread
|
||||
void
|
||||
ipcTransport::OnConnectionLost(nsresult reason)
|
||||
{
|
||||
LOG(("ipcTransport::OnConnectionLost [reason=%x]\n", reason));
|
||||
|
||||
PRBool hadConnection = mHaveConnection;
|
||||
Disconnect();
|
||||
|
||||
if (hadConnection)
|
||||
ProxyToMainThread(ConnectionLost_EventHandler);
|
||||
|
||||
if (reason == NS_BINDING_ABORTED)
|
||||
return;
|
||||
|
||||
if (NS_FAILED(reason))
|
||||
OnConnectFailure();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::CreateTransport()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISocketTransportService> sts(
|
||||
do_GetService(kSocketTransportServiceCID, &rv));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
const char *types[] = { IPC_SOCKET_TYPE };
|
||||
rv = sts->CreateTransport(types, 1,
|
||||
NS_LITERAL_CSTRING("127.0.0.1"), IPC_PORT, nsnull,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// open a blocking, buffered output stream (buffer size is unlimited)
|
||||
rv = mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
|
||||
IPC_BUFFER_SEGMENT_SIZE, PRUint32(-1),
|
||||
getter_AddRefs(mOutputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// open a non-blocking, buffered input stream (buffer size limited)
|
||||
rv = mTransport->OpenInputStream(0, IPC_BUFFER_SEGMENT_SIZE, 4,
|
||||
getter_AddRefs(mInputStream));
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::GetSocketPath(nsACString &socketPath)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
|
||||
if (!file)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
const char *logName = PR_GetEnv("LOGNAME");
|
||||
if (!(logName && *logName)) {
|
||||
logName = PR_GetEnv("USER");
|
||||
if (!(logName && *logName)) {
|
||||
LOG(("could not determine username from environment\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
nsCAutoString leaf;
|
||||
leaf = NS_LITERAL_CSTRING(".mozilla-ipc-")
|
||||
+ nsDependentCString(logName);
|
||||
file->AppendNative(leaf);
|
||||
file->AppendNative(NS_LITERAL_CSTRING("ipcd"));
|
||||
file->GetNativePath(socketPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcTransport::nsISocketEventHandler
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcTransport::OnSocketEvent(PRUint32 type, PRUint32 uparam, void *vparam)
|
||||
{
|
||||
switch (type) {
|
||||
case IPC_TRANSPORT_EVENT_CONNECT:
|
||||
Connect();
|
||||
break;
|
||||
case IPC_TRANSPORT_EVENT_DISCONNECT:
|
||||
Disconnect();
|
||||
break;
|
||||
case IPC_TRANSPORT_EVENT_SENDMSG:
|
||||
SendMsg_Internal((ipcMessage *) vparam);
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcReceiver
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(ipcReceiver, nsIInputStreamNotify)
|
||||
|
||||
NS_METHOD
|
||||
ipcReceiver::ReadSegment(nsIInputStream *stream,
|
||||
void *closure,
|
||||
const char *ptr,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 *countRead)
|
||||
{
|
||||
ipcReceiver *self = (ipcReceiver *) closure;
|
||||
|
||||
*countRead = 0;
|
||||
while (count) {
|
||||
PRUint32 nread;
|
||||
PRBool complete;
|
||||
|
||||
if (!self->mMsg) {
|
||||
self->mMsg = new ipcMessage();
|
||||
if (!self->mMsg)
|
||||
return (self->mStatus = NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
self->mMsg->ReadFrom(ptr, count, &nread, &complete);
|
||||
|
||||
if (complete) {
|
||||
self->mTransport->OnMessageAvailable(self->mMsg); // hand over ownership
|
||||
self->mMsg = nsnull;
|
||||
}
|
||||
|
||||
count -= nread;
|
||||
ptr += nread;
|
||||
*countRead += nread;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ipcReceiver::OnInputStreamReady(nsIAsyncInputStream *stream)
|
||||
{
|
||||
LOG(("ipcReceiver::OnInputStreamReady\n"));
|
||||
|
||||
nsresult rv;
|
||||
PRUint32 n;
|
||||
|
||||
rv = stream->ReadSegments(ReadSegment, this, IPC_BUFFER_SEGMENT_SIZE, &n);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = mStatus;
|
||||
if (NS_SUCCEEDED(rv) && n == 0)
|
||||
rv = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
mTransport->OnConnectionLost(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// continue reading...
|
||||
return stream->AsyncWait(this, 0, nsnull);
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 ipcTransportUnix_h__
|
||||
#define ipcTransportUnix_h__
|
||||
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "prio.h"
|
||||
|
||||
#include "ipcMessageQ.h"
|
||||
|
||||
class ipcTransport;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcReceiver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcReceiver : public nsIInputStreamNotify
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAMNOTIFY
|
||||
|
||||
ipcReceiver(ipcTransport *transport)
|
||||
: mTransport(transport)
|
||||
, mMsg(nsnull)
|
||||
, mStatus(NS_OK)
|
||||
{ }
|
||||
virtual ~ipcReceiver() { }
|
||||
|
||||
// called by the transport when it is going away.
|
||||
void ClearTransport() { mTransport = nsnull; }
|
||||
|
||||
private:
|
||||
static NS_METHOD ReadSegment(nsIInputStream *, void *, const char *,
|
||||
PRUint32, PRUint32, PRUint32 *);
|
||||
|
||||
// the transport owns the receiver, so this back pointer does not need
|
||||
// to be an owning reference.
|
||||
ipcTransport *mTransport;
|
||||
ipcMessage *mMsg; // message in progress
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
#endif // !ipcTransportUnix_h__
|
||||
@@ -1,315 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "prprf.h"
|
||||
#include "prmon.h"
|
||||
#include "prthread.h"
|
||||
#include "plevent.h"
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#include "ipcConfig.h"
|
||||
#include "ipcLog.h"
|
||||
#include "ipcTransport.h"
|
||||
#include "ipcm.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// windows message thread
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define IPC_WM_SENDMSG (WM_USER + 0x1)
|
||||
#define IPC_WM_SHUTDOWN (WM_USER + 0x2)
|
||||
|
||||
static nsresult ipcThreadStatus = NS_OK;
|
||||
static PRThread *ipcThread = NULL;
|
||||
static PRMonitor *ipcMonitor = NULL;
|
||||
static HWND ipcDaemonHwnd = NULL;
|
||||
static HWND ipcLocalHwnd = NULL;
|
||||
static PRBool ipcShutdown = PR_FALSE; // not accessed on message thread!!
|
||||
static ipcTransport *ipcTrans = NULL; // not accessed on message thread!!
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// window proc
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static LRESULT CALLBACK
|
||||
ipcThreadWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam));
|
||||
|
||||
if (uMsg == WM_COPYDATA) {
|
||||
COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
|
||||
if (cd && cd->lpData) {
|
||||
ipcMessage *msg = new ipcMessage();
|
||||
PRUint32 bytesRead;
|
||||
PRBool complete;
|
||||
PRStatus rv = msg->ReadFrom((const char *) cd->lpData, cd->cbData,
|
||||
&bytesRead, &complete);
|
||||
if (rv == PR_SUCCESS && complete && ipcTrans)
|
||||
ipcTrans->OnMessageAvailable(msg); // takes ownership of msg
|
||||
else {
|
||||
LOG((" unable to deliver message [complete=%u]\n", complete));
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (uMsg == IPC_WM_SENDMSG) {
|
||||
ipcMessage *msg = (ipcMessage *) lParam;
|
||||
if (msg) {
|
||||
LOG((" sending message...\n"));
|
||||
COPYDATASTRUCT cd;
|
||||
cd.dwData = GetCurrentProcessId();
|
||||
cd.cbData = (DWORD) msg->MsgLen();
|
||||
cd.lpData = (PVOID) msg->MsgBuf();
|
||||
SendMessageA(ipcDaemonHwnd, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd);
|
||||
LOG((" done.\n"));
|
||||
delete msg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uMsg == IPC_WM_SHUTDOWN) {
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipc thread functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
ipcThreadFunc(void *arg)
|
||||
{
|
||||
LOG(("entering message thread\n"));
|
||||
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
|
||||
WNDCLASS wc;
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.lpfnWndProc = ipcThreadWindowProc;
|
||||
wc.lpszClassName = IPC_CLIENT_WINDOW_CLASS;
|
||||
RegisterClass(&wc);
|
||||
|
||||
char wName[sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20];
|
||||
PR_snprintf(wName, sizeof(wName), "%s%u", IPC_CLIENT_WINDOW_NAME_PREFIX, pid);
|
||||
|
||||
ipcLocalHwnd = CreateWindow(IPC_CLIENT_WINDOW_CLASS, wName,
|
||||
0, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
|
||||
|
||||
{
|
||||
nsAutoMonitor mon(ipcMonitor);
|
||||
if (!ipcLocalHwnd)
|
||||
ipcThreadStatus = NS_ERROR_FAILURE;
|
||||
mon.Notify();
|
||||
}
|
||||
|
||||
if (ipcLocalHwnd) {
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, ipcLocalHwnd, 0, 0))
|
||||
DispatchMessage(&msg);
|
||||
|
||||
ipcShutdown = PR_TRUE; // assuming atomic memory write
|
||||
|
||||
DestroyWindow(ipcLocalHwnd);
|
||||
ipcLocalHwnd = NULL;
|
||||
}
|
||||
|
||||
LOG(("exiting message thread\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
static PRStatus
|
||||
ipcThreadInit(ipcTransport *transport)
|
||||
{
|
||||
if (ipcThread)
|
||||
return PR_FAILURE;
|
||||
|
||||
NS_ADDREF(ipcTrans = transport);
|
||||
ipcShutdown = PR_FALSE;
|
||||
|
||||
ipcMonitor = PR_NewMonitor();
|
||||
if (!ipcMonitor)
|
||||
return PR_FAILURE;
|
||||
|
||||
// spawn message thread
|
||||
ipcThread = PR_CreateThread(PR_USER_THREAD, ipcThreadFunc, NULL,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0);
|
||||
if (!ipcThread) {
|
||||
NS_WARNING("thread creation failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
// wait for hidden window to be created
|
||||
{
|
||||
nsAutoMonitor mon(ipcMonitor);
|
||||
while (!ipcLocalHwnd && NS_SUCCEEDED(ipcThreadStatus))
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
if (NS_FAILED(ipcThreadStatus)) {
|
||||
NS_WARNING("message thread failed");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
static PRStatus
|
||||
ipcThreadShutdown()
|
||||
{
|
||||
if (PR_AtomicSet(&ipcShutdown, PR_TRUE) == PR_FALSE) {
|
||||
LOG(("posting IPC_WM_SHUTDOWN message\n"));
|
||||
PostMessage(ipcLocalHwnd, IPC_WM_SHUTDOWN, 0, 0);
|
||||
}
|
||||
|
||||
LOG(("joining w/ message thread...\n"));
|
||||
PR_JoinThread(ipcThread);
|
||||
ipcThread = NULL;
|
||||
|
||||
//
|
||||
// ok, now the message thread is dead
|
||||
//
|
||||
|
||||
PR_DestroyMonitor(ipcMonitor);
|
||||
ipcMonitor = NULL;
|
||||
|
||||
NS_RELEASE(ipcTrans);
|
||||
// NS_RELEASE(ipcEventQ);
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// windows specific ipcTransport impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
ipcTransport::PlatformInit()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::Disconnect()
|
||||
{
|
||||
mHaveConnection = PR_FALSE;
|
||||
|
||||
if (ipcThread)
|
||||
ipcThreadShutdown();
|
||||
|
||||
// clear our reference to the daemon's HWND.
|
||||
ipcDaemonHwnd = NULL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::Connect()
|
||||
{
|
||||
LOG(("ipcTransport::Connect\n"));
|
||||
|
||||
if (++mConnectionAttemptCount > 20) {
|
||||
LOG((" giving up after 20 unsuccessful connection attempts\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(ipcDaemonHwnd == NULL, NS_ERROR_ALREADY_INITIALIZED);
|
||||
|
||||
ipcDaemonHwnd = FindWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME);
|
||||
if (!ipcDaemonHwnd) {
|
||||
LOG((" daemon does not appear to be running\n"));
|
||||
//
|
||||
// daemon does not exist
|
||||
//
|
||||
return OnConnectFailure();
|
||||
}
|
||||
|
||||
//
|
||||
// delay creation of the message thread until we know the daemon exists.
|
||||
//
|
||||
if (!ipcThread)
|
||||
ipcThreadInit(this);
|
||||
|
||||
//
|
||||
// send CLIENT_HELLO; expect CLIENT_ID in response.
|
||||
//
|
||||
SendMsg_Internal(new ipcmMessageClientHello());
|
||||
mSentHello = PR_TRUE;
|
||||
|
||||
#if 0
|
||||
// XXX need something else here
|
||||
//
|
||||
// begin a timer. if the timer fires before we get a CLIENT_ID, then
|
||||
// assume the connection attempt failed.
|
||||
//
|
||||
nsresult rv;
|
||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mTimer->Init(this, 1000, nsITimer::TYPE_ONE_SHOT);
|
||||
return rv;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::SendMsg_Internal(ipcMessage *msg)
|
||||
{
|
||||
LOG(("ipcTransport::SendMsg_Internal\n"));
|
||||
|
||||
if (ipcShutdown) {
|
||||
NS_WARNING("unable to send message b/c message thread is shutdown\n");
|
||||
goto loser;
|
||||
}
|
||||
if (!PostMessage(ipcLocalHwnd, IPC_WM_SENDMSG, 0, (LPARAM) msg)) {
|
||||
LOG((" PostMessage failed w/ error = %u\n", GetLastError()));
|
||||
goto loser;
|
||||
}
|
||||
return NS_OK;
|
||||
loser:
|
||||
delete msg;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#
|
||||
# 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):
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_ipc
|
||||
REQUIRES = xpcom \
|
||||
string \
|
||||
ipc \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
TestIPC.cpp \
|
||||
$(NULL)
|
||||
|
||||
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
LIBS = \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(XPCOM_LIBS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,316 +0,0 @@
|
||||
/* ***** 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 IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@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 "ipcIService.h"
|
||||
#include "ipcILockService.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsString.h"
|
||||
#include "prmem.h"
|
||||
|
||||
static const nsID kIPCMTargetID =
|
||||
{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */
|
||||
0x753ca8ff,
|
||||
0xc8c2,
|
||||
0x4601,
|
||||
{0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50}
|
||||
};
|
||||
|
||||
static const nsID kTestTargetID =
|
||||
{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */
|
||||
0xe628fc6e,
|
||||
0xa6a7,
|
||||
0x48c7,
|
||||
{0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8}
|
||||
};
|
||||
|
||||
#define RETURN_IF_FAILED(rv, step) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (NS_FAILED(rv)) { \
|
||||
printf("*** %s failed: rv=%x\n", step, rv); \
|
||||
return rv;\
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static nsIEventQueue* gEventQ = nsnull;
|
||||
static PRBool gKeepRunning = PR_TRUE;
|
||||
//static PRInt32 gMsgCount = 0;
|
||||
static ipcIService *gIpcServ = nsnull;
|
||||
static ipcILockService *gIpcLockServ = nsnull;
|
||||
|
||||
static void
|
||||
SendMsg(ipcIService *ipc, PRUint32 cID, const nsID &target, const char *data, PRUint32 dataLen, PRBool sync = PR_FALSE)
|
||||
{
|
||||
printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen);
|
||||
|
||||
ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen, sync);
|
||||
// gMsgCount++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class myIpcMessageObserver : public ipcIMessageObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IPCIMESSAGEOBSERVER
|
||||
|
||||
myIpcMessageObserver() { NS_INIT_ISUPPORTS(); }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
myIpcMessageObserver::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen)
|
||||
{
|
||||
printf("*** got message: [%s]\n", (const char *) data);
|
||||
|
||||
// if (--gMsgCount == 0)
|
||||
// gKeepRunning = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class myIpcClientQueryHandler : public ipcIClientQueryHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IPCICLIENTQUERYHANDLER
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(myIpcClientQueryHandler, ipcIClientQueryHandler)
|
||||
|
||||
NS_IMETHODIMP
|
||||
myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID,
|
||||
nsresult aStatus,
|
||||
PRUint32 aClientID,
|
||||
const char **aNames,
|
||||
PRUint32 aNameCount,
|
||||
const nsID **aTargets,
|
||||
PRUint32 aTargetCount)
|
||||
{
|
||||
printf("*** query complete [queryID=%u status=0x%x clientID=%u]\n",
|
||||
aQueryID, aStatus, aClientID);
|
||||
|
||||
PRUint32 i;
|
||||
printf("*** names:\n");
|
||||
for (i = 0; i < aNameCount; ++i)
|
||||
printf("*** %d={%s}\n", i, aNames[i]);
|
||||
printf("*** targets:\n");
|
||||
for (i = 0; i < aTargetCount; ++i) {
|
||||
const char *trailer;
|
||||
if (aTargets[i]->Equals(kTestTargetID))
|
||||
trailer = " (TEST_TARGET_ID)";
|
||||
else if (aTargets[i]->Equals(kIPCMTargetID))
|
||||
trailer = " (IPCM_TARGET_ID)";
|
||||
else
|
||||
trailer = " (unknown)";
|
||||
char *str = aTargets[i]->ToString();
|
||||
printf("*** %d=%s%s\n", i, str, trailer);
|
||||
PR_Free(str);
|
||||
}
|
||||
|
||||
if (aClientID != 0) {
|
||||
const char hello[] = "hello friend!";
|
||||
SendMsg(gIpcServ, aClientID, kTestTargetID, hello, sizeof(hello));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class myIpcLockNotify : public ipcILockNotify
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IPCILOCKNOTIFY
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(myIpcLockNotify, ipcILockNotify)
|
||||
|
||||
NS_IMETHODIMP
|
||||
myIpcLockNotify::OnAcquireLockComplete(const char *lockName, nsresult status)
|
||||
{
|
||||
printf("*** OnAcquireLockComplete [lock=%s status=%x]\n", lockName, status);
|
||||
gIpcLockServ->ReleaseLock(lockName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIServiceManager> servMan;
|
||||
NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
|
||||
nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
|
||||
NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
|
||||
if (registrar)
|
||||
registrar->AutoRegister(nsnull);
|
||||
|
||||
// Create the Event Queue for this thread...
|
||||
nsCOMPtr<nsIEventQueueService> eqs =
|
||||
do_GetService(kEventQueueServiceCID, &rv);
|
||||
RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)");
|
||||
|
||||
rv = eqs->CreateMonitoredThreadEventQueue();
|
||||
RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue");
|
||||
|
||||
rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ);
|
||||
RETURN_IF_FAILED(rv, "GetThreadEventQueue");
|
||||
|
||||
nsCOMPtr<ipcIService> ipcServ(do_GetService("@mozilla.org/ipc/service;1", &rv));
|
||||
RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
|
||||
NS_ADDREF(gIpcServ = ipcServ);
|
||||
|
||||
if (argc > 1) {
|
||||
printf("*** using client name [%s]\n", argv[1]);
|
||||
gIpcServ->AddClientName(argv[1]);
|
||||
}
|
||||
|
||||
ipcServ->SetMessageObserver(kTestTargetID, new myIpcMessageObserver());
|
||||
|
||||
const char *data =
|
||||
"01 this is a really long message.\n"
|
||||
"02 this is a really long message.\n"
|
||||
"03 this is a really long message.\n"
|
||||
"04 this is a really long message.\n"
|
||||
"05 this is a really long message.\n"
|
||||
"06 this is a really long message.\n"
|
||||
"07 this is a really long message.\n"
|
||||
"08 this is a really long message.\n"
|
||||
"09 this is a really long message.\n"
|
||||
"10 this is a really long message.\n"
|
||||
"11 this is a really long message.\n"
|
||||
"12 this is a really long message.\n"
|
||||
"13 this is a really long message.\n"
|
||||
"14 this is a really long message.\n"
|
||||
"15 this is a really long message.\n"
|
||||
"16 this is a really long message.\n"
|
||||
"17 this is a really long message.\n"
|
||||
"18 this is a really long message.\n"
|
||||
"19 this is a really long message.\n"
|
||||
"20 this is a really long message.\n"
|
||||
"21 this is a really long message.\n"
|
||||
"22 this is a really long message.\n"
|
||||
"23 this is a really long message.\n"
|
||||
"24 this is a really long message.\n"
|
||||
"25 this is a really long message.\n"
|
||||
"26 this is a really long message.\n"
|
||||
"27 this is a really long message.\n"
|
||||
"28 this is a really long message.\n"
|
||||
"29 this is a really long message.\n"
|
||||
"30 this is a really long message.\n"
|
||||
"31 this is a really long message.\n"
|
||||
"32 this is a really long message.\n"
|
||||
"33 this is a really long message.\n"
|
||||
"34 this is a really long message.\n"
|
||||
"35 this is a really long message.\n"
|
||||
"36 this is a really long message.\n"
|
||||
"37 this is a really long message.\n"
|
||||
"38 this is a really long message.\n"
|
||||
"39 this is a really long message.\n"
|
||||
"40 this is a really long message.\n"
|
||||
"41 this is a really long message.\n"
|
||||
"42 this is a really long message.\n"
|
||||
"43 this is a really long message.\n"
|
||||
"44 this is a really long message.\n"
|
||||
"45 this is a really long message.\n"
|
||||
"46 this is a really long message.\n"
|
||||
"47 this is a really long message.\n"
|
||||
"48 this is a really long message.\n"
|
||||
"49 this is a really long message.\n"
|
||||
"50 this is a really long message.\n"
|
||||
"51 this is a really long message.\n"
|
||||
"52 this is a really long message.\n"
|
||||
"53 this is a really long message.\n"
|
||||
"54 this is a really long message.\n"
|
||||
"55 this is a really long message.\n"
|
||||
"56 this is a really long message.\n"
|
||||
"57 this is a really long message.\n"
|
||||
"58 this is a really long message.\n"
|
||||
"59 this is a really long message.\n"
|
||||
"60 this is a really long message.\n";
|
||||
SendMsg(ipcServ, 0, kTestTargetID, data, strlen(data)+1, PR_TRUE);
|
||||
|
||||
PRUint32 queryID;
|
||||
nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler());
|
||||
ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID);
|
||||
|
||||
//
|
||||
// test lock service
|
||||
//
|
||||
nsCOMPtr<ipcILockService> lockService = do_GetService("@mozilla.org/ipc/lock-service;1", &rv);
|
||||
RETURN_IF_FAILED(rv, "do_GetService(ipcLockServ)");
|
||||
NS_ADDREF(gIpcLockServ = lockService);
|
||||
|
||||
nsCOMPtr<ipcILockNotify> notify(new myIpcLockNotify());
|
||||
gIpcLockServ->AcquireLock("blah", notify, PR_TRUE);
|
||||
|
||||
rv = gIpcLockServ->AcquireLock("foo", nsnull, PR_TRUE);
|
||||
printf("*** sync AcquireLock returned [rv=%x]\n", rv);
|
||||
|
||||
PLEvent *ev;
|
||||
while (gKeepRunning) {
|
||||
gEventQ->WaitForEvent(&ev);
|
||||
gEventQ->HandleEvent(ev);
|
||||
}
|
||||
|
||||
NS_RELEASE(gIpcServ);
|
||||
|
||||
printf("*** processing remaining events\n");
|
||||
|
||||
// process any remaining events
|
||||
while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev)
|
||||
gEventQ->HandleEvent(ev);
|
||||
|
||||
printf("*** done\n");
|
||||
} // this scopes the nsCOMPtrs
|
||||
|
||||
// no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
|
||||
rv = NS_ShutdownXPCOM(nsnull);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
# ***** 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 IPC.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Darin Fisher <darin@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 = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = testmodule
|
||||
LIBRARY_NAME = testmodule
|
||||
EXPORT_LIBRARY = 1
|
||||
MODULE_NAME = testmodule
|
||||
REQUIRES = xpcom \
|
||||
ipc \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = TestModule.cpp
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../common \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(LIBS_DIR) \
|
||||
$(NSPR_LIBS) \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_IPC_FILES = \
|
||||
$(LIB_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_IPC_FILES)
|
||||
$(INSTALL) $^ $(DIST)/bin/ipc/modules
|
||||
|
||||
install:: $(_IPC_FILES)
|
||||
$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules
|
||||
@@ -1,62 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "ipcModuleUtil.h"
|
||||
|
||||
#define TEST_MODULE_ID \
|
||||
{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ \
|
||||
0xe628fc6e, \
|
||||
0xa6a7, \
|
||||
0x48c7, \
|
||||
{0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} \
|
||||
}
|
||||
static const nsID kTestModuleID = TEST_MODULE_ID;
|
||||
|
||||
struct TestModule
|
||||
{
|
||||
static void Init()
|
||||
{
|
||||
printf("*** TestModule::Init\n");
|
||||
}
|
||||
|
||||
static void Shutdown()
|
||||
{
|
||||
printf("*** TestModule::Shutdown\n");
|
||||
}
|
||||
|
||||
static void HandleMsg(ipcClientHandle client,
|
||||
const nsID &target,
|
||||
const void *data,
|
||||
PRUint32 dataLen)
|
||||
{
|
||||
printf("*** TestModule::HandleMsg [%s]\n", (const char *) data);
|
||||
|
||||
static const char buf[] = "pong";
|
||||
IPC_SendMsg(client, kTestModuleID, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void ClientUp(ipcClientHandle client)
|
||||
{
|
||||
printf("*** TestModule::ClientUp [%u]\n", IPC_GetClientID(client));
|
||||
}
|
||||
|
||||
static void ClientDown(ipcClientHandle client)
|
||||
{
|
||||
printf("*** TestModule::ClientDown [%u]\n", IPC_GetClientID(client));
|
||||
}
|
||||
};
|
||||
|
||||
static ipcModuleMethods gTestMethods =
|
||||
{
|
||||
IPC_MODULE_METHODS_VERSION,
|
||||
TestModule::Init,
|
||||
TestModule::Shutdown,
|
||||
TestModule::HandleMsg,
|
||||
TestModule::ClientUp,
|
||||
TestModule::ClientDown
|
||||
};
|
||||
|
||||
static ipcModuleEntry gTestModuleEntry[] =
|
||||
{
|
||||
{ TEST_MODULE_ID, &gTestMethods }
|
||||
};
|
||||
|
||||
IPC_IMPL_GETMODULES(TestModule, gTestModuleEntry)
|
||||
BIN
mozilla/webtools/bugzilla/1x1.gif
Normal file
BIN
mozilla/webtools/bugzilla/1x1.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 B |
97
mozilla/webtools/bugzilla/Attachment.pm
Normal file
97
mozilla/webtools/bugzilla/Attachment.pm
Normal file
@@ -0,0 +1,97 @@
|
||||
# -*- 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 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>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
|
||||
############################################################################
|
||||
# Module Initialization
|
||||
############################################################################
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
package Attachment;
|
||||
|
||||
# This module requires that its caller have said "require CGI.pl" to import
|
||||
# relevant functions from that script and its companion globals.pl.
|
||||
|
||||
############################################################################
|
||||
# Functions
|
||||
############################################################################
|
||||
|
||||
sub query
|
||||
{
|
||||
# Retrieves and returns an array of attachment records for a given bug.
|
||||
# This data should be given to attachment/list.atml in an
|
||||
# "attachments" variable.
|
||||
my ($bugid) = @_;
|
||||
|
||||
my $in_editbugs = &::UserInGroup($::userid, "editbugs");
|
||||
|
||||
# Retrieve a list of attachments for this bug and write them into an array
|
||||
# of hashes in which each hash represents a single attachment.
|
||||
&::SendSQL("
|
||||
SELECT attach_id, creation_ts, mimetype, description, ispatch,
|
||||
isobsolete, submitter_id
|
||||
FROM attachments WHERE bug_id = $bugid ORDER BY attach_id
|
||||
");
|
||||
my @attachments = ();
|
||||
while (&::MoreSQLData()) {
|
||||
my %a;
|
||||
my $submitter_id;
|
||||
($a{'attachid'}, $a{'date'}, $a{'contenttype'}, $a{'description'},
|
||||
$a{'ispatch'}, $a{'isobsolete'}, $submitter_id) = &::FetchSQLData();
|
||||
|
||||
# Format the attachment's creation/modification date into a standard
|
||||
# format (YYYY-MM-DD HH:MM)
|
||||
if ($a{'date'} =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
|
||||
$a{'date'} = "$1-$2-$3 $4:$5";
|
||||
}
|
||||
|
||||
# Retrieve a list of status flags that have been set on the attachment.
|
||||
&::PushGlobalSQLState();
|
||||
&::SendSQL("
|
||||
SELECT name
|
||||
FROM attachstatuses, attachstatusdefs
|
||||
WHERE attach_id = $a{'attachid'}
|
||||
AND attachstatuses.statusid = attachstatusdefs.id
|
||||
ORDER BY sortkey
|
||||
");
|
||||
my @statuses = ();
|
||||
while (&::MoreSQLData()) {
|
||||
my ($status) = &::FetchSQLData();
|
||||
push @statuses , $status;
|
||||
}
|
||||
$a{'statuses'} = \@statuses;
|
||||
&::PopGlobalSQLState();
|
||||
|
||||
# We will display the edit link if the user can edit the attachment;
|
||||
# ie the are the submitter, or they have canedit.
|
||||
# Also show the link if the user is not logged in - in that cae,
|
||||
# They'll be prompted later
|
||||
$a{'canedit'} = ($::userid == 0 || $submitter_id == $::userid ||
|
||||
$in_editbugs);
|
||||
push @attachments, \%a;
|
||||
}
|
||||
|
||||
return \@attachments;
|
||||
}
|
||||
|
||||
1;
|
||||
525
mozilla/webtools/bugzilla/Bug.pm
Executable file
525
mozilla/webtools/bugzilla/Bug.pm
Executable file
@@ -0,0 +1,525 @@
|
||||
# -*- 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 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): Dawn Endico <endico@mozilla.org>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
# Chris Yeh <cyeh@bluemartini.com>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use DBI;
|
||||
use RelationSet;
|
||||
use vars qw($unconfirmedstate $legal_keywords);
|
||||
require "globals.pl";
|
||||
require "CGI.pl";
|
||||
package Bug;
|
||||
use CGI::Carp qw(fatalsToBrowser);
|
||||
my %ok_field;
|
||||
|
||||
for my $key (qw (bug_id product version rep_platform op_sys bug_status
|
||||
resolution priority bug_severity component assigned_to
|
||||
reporter bug_file_loc short_desc target_milestone
|
||||
qa_contact status_whiteboard creation_ts
|
||||
delta_ts votes whoid comment query error) ){
|
||||
$ok_field{$key}++;
|
||||
}
|
||||
|
||||
# create a new empty bug
|
||||
#
|
||||
sub new {
|
||||
my $type = shift();
|
||||
my %bug;
|
||||
|
||||
# create a ref to an empty hash and bless it
|
||||
#
|
||||
my $self = {%bug};
|
||||
bless $self, $type;
|
||||
|
||||
# construct from a hash containing a bug's info
|
||||
#
|
||||
if ($#_ == 1) {
|
||||
$self->initBug(@_);
|
||||
} else {
|
||||
confess("invalid number of arguments \($#_\)($_)");
|
||||
}
|
||||
|
||||
# bless as a Bug
|
||||
#
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# dump info about bug into hash unless user doesn't have permission
|
||||
# user_id 0 is used when person is not logged in.
|
||||
#
|
||||
sub initBug {
|
||||
my $self = shift();
|
||||
my ($bug_id, $user_id) = (@_);
|
||||
|
||||
my $old_bug_id = $bug_id;
|
||||
if ((! defined $bug_id) || (!$bug_id) || (!&::detaint_natural($bug_id))) {
|
||||
# no bug number given
|
||||
$self->{'bug_id'} = $old_bug_id;
|
||||
$self->{'error'} = "InvalidBugId";
|
||||
return $self;
|
||||
}
|
||||
|
||||
# default userid 0, or get DBID if you used an email address
|
||||
unless (defined $user_id) {
|
||||
$user_id = 0;
|
||||
}
|
||||
else {
|
||||
if ($user_id =~ /^\@/) {
|
||||
$user_id = &::DBname_to_id($user_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&::ConnectToDatabase();
|
||||
&::GetVersionTable();
|
||||
|
||||
# this verification should already have been done by caller
|
||||
# my $loginok = quietly_check_login();
|
||||
|
||||
|
||||
$self->{'whoid'} = $user_id;
|
||||
|
||||
# First check that we can see it
|
||||
if (!&::CanSeeBug($bug_id, $user_id)) {
|
||||
# is it not there, or are we just forbidden to see it?
|
||||
&::SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $bug_id");
|
||||
if (&::FetchSQLData()) {
|
||||
$self->{'error'} = "NotPermitted";
|
||||
} else {
|
||||
$self->{'error'} = "NotFound";
|
||||
}
|
||||
$self->{'bug_id'} = $bug_id;
|
||||
return $self;
|
||||
}
|
||||
|
||||
my $query = "";
|
||||
if ($::driver eq 'mysql') {
|
||||
$query = "
|
||||
select
|
||||
bugs.bug_id, product, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact,
|
||||
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
|
||||
delta_ts, sum(votes.count)
|
||||
from bugs left join votes using(bug_id)
|
||||
where bugs.bug_id = $bug_id
|
||||
group by bugs.bug_id";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$query = "
|
||||
select
|
||||
bugs.bug_id, product, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact,
|
||||
status_whiteboard, creation_ts,
|
||||
delta_ts, sum(votes.count)
|
||||
from bugs left join votes using(bug_id)
|
||||
where bugs.bug_id = $bug_id
|
||||
group by bugs.bug_id, product, version, rep_platform, op_sys, bug_status,
|
||||
resolution, priority, bug_severity, component, assigned_to, reporter,
|
||||
bug_file_loc, short_desc, target_milestone, qa_contact, status_whiteboard,
|
||||
creation_ts, delta_ts";
|
||||
}
|
||||
|
||||
&::SendSQL($query);
|
||||
my @row;
|
||||
|
||||
@row = &::FetchSQLData();
|
||||
my $count = 0;
|
||||
my %fields;
|
||||
foreach my $field ("bug_id", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes") {
|
||||
$fields{$field} = shift @row;
|
||||
if ($fields{$field}) {
|
||||
$self->{$field} = $fields{$field};
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
|
||||
$self->{'assigned_to'} = &::DBID_to_name($self->{'assigned_to'});
|
||||
$self->{'reporter'} = &::DBID_to_name($self->{'reporter'});
|
||||
|
||||
my $ccSet = new RelationSet;
|
||||
$ccSet->mergeFromDB("select who from cc where bug_id=$bug_id");
|
||||
my @cc = $ccSet->toArrayOfStrings();
|
||||
if (@cc) {
|
||||
$self->{'cc'} = \@cc;
|
||||
}
|
||||
|
||||
if (&::Param("useqacontact") && (defined $self->{'qa_contact'}) ) {
|
||||
my $name = $self->{'qa_contact'} > 0 ? &::DBID_to_name($self->{'qa_contact'}) :"";
|
||||
if ($name) {
|
||||
$self->{'qa_contact'} = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (@::legal_keywords) {
|
||||
&::SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
WHERE keywords.bug_id = $bug_id
|
||||
AND keyworddefs.id = keywords.keywordid
|
||||
ORDER BY keyworddefs.name");
|
||||
my @list;
|
||||
while (&::MoreSQLData()) {
|
||||
push(@list, &::FetchOneColumn());
|
||||
}
|
||||
if (@list) {
|
||||
$self->{'keywords'} = join(', ', @list);
|
||||
}
|
||||
}
|
||||
|
||||
&::SendSQL("select attach_id, creation_ts, description
|
||||
from attachments
|
||||
where bug_id = $bug_id");
|
||||
my @attachments;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($attachid, $date, $desc) = (&::FetchSQLData());
|
||||
if ($date =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
|
||||
$date = "$3/$4/$2 $5:$6";
|
||||
my %attach;
|
||||
$attach{'attachid'} = $attachid;
|
||||
$attach{'date'} = $date;
|
||||
$attach{'desc'} = $desc;
|
||||
push @attachments, \%attach;
|
||||
}
|
||||
}
|
||||
if (@attachments) {
|
||||
$self->{'attachments'} = \@attachments;
|
||||
}
|
||||
|
||||
&::SendSQL("select bug_id, who, bug_when, thetext
|
||||
from longdescs
|
||||
where bug_id = $bug_id");
|
||||
my @longdescs;
|
||||
while (&::MoreSQLData()) {
|
||||
my ($bug_id, $who, $bug_when, $thetext) = (&::FetchSQLData());
|
||||
my %longdesc;
|
||||
$longdesc{'who'} = $who;
|
||||
$longdesc{'bug_when'} = $bug_when;
|
||||
$longdesc{'thetext'} = $thetext;
|
||||
push @longdescs, \%longdesc;
|
||||
}
|
||||
if (@longdescs) {
|
||||
$self->{'longdescs'} = \@longdescs;
|
||||
}
|
||||
|
||||
if (&::Param("usedependencies")) {
|
||||
my @depends = EmitDependList("blocked", "dependson", $bug_id);
|
||||
if ( @depends ) {
|
||||
$self->{'dependson'} = \@depends;
|
||||
}
|
||||
my @blocks = EmitDependList("dependson", "blocked", $bug_id);
|
||||
if ( @blocks ) {
|
||||
$self->{'blocks'} = \@blocks;
|
||||
}
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# given a bug hash, emit xml for it. with file header provided by caller
|
||||
#
|
||||
sub emitXML {
|
||||
( $#_ == 0 ) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
my $xml;
|
||||
|
||||
|
||||
if (exists $self->{'error'}) {
|
||||
$xml .= "<bug error=\"$self->{'error'}\">\n";
|
||||
$xml .= " <bug_id>$self->{'bug_id'}</bug_id>\n";
|
||||
$xml .= "</bug>\n";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
$xml .= "<bug>\n";
|
||||
|
||||
foreach my $field ("bug_id", "bug_status", "product",
|
||||
"priority", "version", "rep_platform", "assigned_to", "delta_ts",
|
||||
"component", "reporter", "target_milestone", "bug_severity",
|
||||
"creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc",
|
||||
"short_desc", "keywords", "status_whiteboard") {
|
||||
if ($self->{$field}) {
|
||||
$xml .= " <$field>" . QuoteXMLChars($self->{$field}) . "</$field>\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $field ("dependson", "blocks", "cc") {
|
||||
if (defined $self->{$field}) {
|
||||
for (my $i=0 ; $i < @{$self->{$field}} ; $i++) {
|
||||
$xml .= " <$field>" . $self->{$field}[$i] . "</$field>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $self->{'longdescs'}) {
|
||||
for (my $i=0 ; $i < @{$self->{'longdescs'}} ; $i++) {
|
||||
$xml .= " <long_desc>\n";
|
||||
$xml .= " <who>" . &::DBID_to_name($self->{'longdescs'}[$i]->{'who'})
|
||||
. "</who>\n";
|
||||
$xml .= " <bug_when>" . $self->{'longdescs'}[$i]->{'bug_when'}
|
||||
. "</bug_when>\n";
|
||||
$xml .= " <thetext>" . QuoteXMLChars($self->{'longdescs'}[$i]->{'thetext'})
|
||||
. "</thetext>\n";
|
||||
$xml .= " </long_desc>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $self->{'attachments'}) {
|
||||
for (my $i=0 ; $i < @{$self->{'attachments'}} ; $i++) {
|
||||
$xml .= " <attachment>\n";
|
||||
$xml .= " <attachid>" . $self->{'attachments'}[$i]->{'attachid'}
|
||||
. "</attachid>\n";
|
||||
$xml .= " <date>" . $self->{'attachments'}[$i]->{'date'} . "</date>\n";
|
||||
$xml .= " <desc>" . QuoteXMLChars($self->{'attachments'}[$i]->{'desc'}) . "</desc>\n";
|
||||
# $xml .= " <type>" . $self->{'attachments'}[$i]->{'type'} . "</type>\n";
|
||||
# $xml .= " <data>" . $self->{'attachments'}[$i]->{'data'} . "</data>\n";
|
||||
$xml .= " </attachment>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$xml .= "</bug>\n";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
sub EmitDependList {
|
||||
my ($myfield, $targetfield, $bug_id) = (@_);
|
||||
my @list;
|
||||
&::SendSQL("select dependencies.$targetfield, bugs.bug_status
|
||||
from dependencies, bugs
|
||||
where dependencies.$myfield = $bug_id
|
||||
and bugs.bug_id = dependencies.$targetfield
|
||||
order by dependencies.$targetfield");
|
||||
while (&::MoreSQLData()) {
|
||||
my ($i, $stat) = (&::FetchSQLData());
|
||||
push @list, $i;
|
||||
}
|
||||
return @list;
|
||||
}
|
||||
|
||||
sub QuoteXMLChars {
|
||||
$_[0] =~ s/&/&/g;
|
||||
$_[0] =~ s/</</g;
|
||||
$_[0] =~ s/>/>/g;
|
||||
$_[0] =~ s/'/'/g;
|
||||
$_[0] =~ s/"/"/g;
|
||||
# $_[0] =~ s/([\x80-\xFF])/&XmlUtf8Encode(ord($1))/ge;
|
||||
return($_[0]);
|
||||
}
|
||||
|
||||
sub XML_Header {
|
||||
my ($urlbase, $version, $maintainer, $exporter) = (@_);
|
||||
|
||||
my $xml;
|
||||
$xml = "<?xml version=\"1.0\" standalone=\"yes\"?>\n";
|
||||
$xml .= "<!DOCTYPE bugzilla SYSTEM \"$urlbase";
|
||||
if (! ($urlbase =~ /.+\/$/)) {
|
||||
$xml .= "/";
|
||||
}
|
||||
$xml .= "bugzilla.dtd\">\n";
|
||||
$xml .= "<bugzilla";
|
||||
if (defined $exporter) {
|
||||
$xml .= " exporter=\"$exporter\"";
|
||||
}
|
||||
$xml .= " version=\"$version\"";
|
||||
$xml .= " urlbase=\"$urlbase\"";
|
||||
$xml .= " maintainer=\"$maintainer\">\n";
|
||||
return ($xml);
|
||||
}
|
||||
|
||||
|
||||
sub XML_Footer {
|
||||
return ("</bugzilla>\n");
|
||||
}
|
||||
|
||||
sub UserInGroup {
|
||||
my $self = shift();
|
||||
my ($groupname) = (@_);
|
||||
return &::UserInGroup($self->{'whoid'}, $groupname);
|
||||
}
|
||||
|
||||
sub CanChangeField {
|
||||
my $self = shift();
|
||||
my ($f, $oldvalue, $newvalue) = (@_);
|
||||
my $UserInEditGroup = -1;
|
||||
my $UserInCanConfirmGroup = -1;
|
||||
my $ownerid;
|
||||
my $reporterid;
|
||||
my $qacontactid;
|
||||
|
||||
if ($f eq "assigned_to" || $f eq "reporter" || $f eq "qa_contact") {
|
||||
if ($oldvalue =~ /^\d+$/) {
|
||||
if ($oldvalue == 0) {
|
||||
$oldvalue = "";
|
||||
} else {
|
||||
$oldvalue = &::DBID_to_name($oldvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($oldvalue eq $newvalue) {
|
||||
return 1;
|
||||
}
|
||||
if (&::trim($oldvalue) eq &::trim($newvalue)) {
|
||||
return 1;
|
||||
}
|
||||
if ($f =~ /^longdesc/) {
|
||||
return 1;
|
||||
}
|
||||
if ($UserInEditGroup < 0) {
|
||||
$UserInEditGroup = UserInGroup($self, "editbugs");
|
||||
}
|
||||
if ($UserInEditGroup) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT reporter, assigned_to, qa_contact FROM bugs " .
|
||||
"WHERE bug_id = $self->{'bug_id'}");
|
||||
($reporterid, $ownerid, $qacontactid) = (&::FetchSQLData());
|
||||
|
||||
# Let reporter change bug status, even if they can't edit bugs.
|
||||
# If reporter can't re-open their bug they will just file a duplicate.
|
||||
# While we're at it, let them close their own bugs as well.
|
||||
if ( ($f eq "bug_status") && ($self->{'whoid'} eq $reporterid) ) {
|
||||
return 1;
|
||||
}
|
||||
if ($f eq "bug_status" && $newvalue ne $::unconfirmedstate &&
|
||||
&::IsOpenedState($newvalue)) {
|
||||
|
||||
# Hmm. They are trying to set this bug to some opened state
|
||||
# that isn't the UNCONFIRMED state. Are they in the right
|
||||
# group? Or, has it ever been confirmed? If not, then this
|
||||
# isn't legal.
|
||||
|
||||
if ($UserInCanConfirmGroup < 0) {
|
||||
$UserInCanConfirmGroup = &::UserInGroup($self->{'whoid'},"canconfirm");
|
||||
}
|
||||
if ($UserInCanConfirmGroup) {
|
||||
return 1;
|
||||
}
|
||||
&::SendSQL("SELECT everconfirmed FROM bugs WHERE bug_id = $self->{'bug_id'}");
|
||||
my $everconfirmed = FetchOneColumn();
|
||||
if ($everconfirmed) {
|
||||
return 1;
|
||||
}
|
||||
} elsif ($reporterid eq $self->{'whoid'} || $ownerid eq $self->{'whoid'} ||
|
||||
$qacontactid eq $self->{'whoid'}) {
|
||||
return 1;
|
||||
}
|
||||
$self->{'error'} = "
|
||||
Only the owner or submitter of the bug, or a sufficiently
|
||||
empowered user, may make that change to the $f field."
|
||||
}
|
||||
|
||||
sub Collision {
|
||||
my $self = shift();
|
||||
my $write = "WRITE"; # Might want to make a param to control
|
||||
# whether we do LOW_PRIORITY ...
|
||||
if ($::driver eq 'mysql') {
|
||||
&::SendSQL("LOCK TABLES bugs $write, bugs_activity $write, cc $write, " .
|
||||
"cc AS selectVisible_cc $write, " .
|
||||
"profiles $write, dependencies $write, votes $write, " .
|
||||
"keywords $write, longdescs $write, fielddefs $write, " .
|
||||
"keyworddefs READ, groups READ, attachments READ, products READ");
|
||||
}
|
||||
&::SendSQL("SELECT delta_ts FROM bugs where bug_id=$self->{'bug_id'}");
|
||||
my $delta_ts = &::FetchOneColumn();
|
||||
if ($::driver eq 'mysql') {
|
||||
&::SendSQL("unlock tables");
|
||||
}
|
||||
if ($self->{'delta_ts'} ne $delta_ts) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub AppendComment {
|
||||
my $self = shift();
|
||||
my ($comment) = (@_);
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment =~ /^\s*$/) { # Nothin' but whitespace.
|
||||
return;
|
||||
}
|
||||
|
||||
&::SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) " .
|
||||
"VALUES($self->{'bug_id'}, $self->{'whoid'}, now(), " . &::SqlQuote($comment) . ")");
|
||||
|
||||
&::SendSQL("UPDATE bugs SET delta_ts = now() WHERE bug_id = $self->{'bug_id'}");
|
||||
}
|
||||
|
||||
|
||||
#from o'reilley's Programming Perl
|
||||
sub display {
|
||||
my $self = shift;
|
||||
my @keys;
|
||||
if (@_ == 0) { # no further arguments
|
||||
@keys = sort keys(%$self);
|
||||
} else {
|
||||
@keys = @_; # use the ones given
|
||||
}
|
||||
foreach my $key (@keys) {
|
||||
print "\t$key => $self->{$key}\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub CommitChanges {
|
||||
|
||||
#snapshot bug
|
||||
#snapshot dependencies
|
||||
#check can change fields
|
||||
#check collision
|
||||
#lock and change fields
|
||||
#notify through mail
|
||||
|
||||
}
|
||||
|
||||
sub AUTOLOAD {
|
||||
use vars qw($AUTOLOAD);
|
||||
my $self = shift;
|
||||
my $type = ref($self) || $self;
|
||||
my $attr = $AUTOLOAD;
|
||||
|
||||
$attr =~ s/.*:://;
|
||||
return unless $attr=~ /[^A-Z]/;
|
||||
if (@_) {
|
||||
$self->{$attr} = shift;
|
||||
return;
|
||||
}
|
||||
confess ("invalid bug attribute $attr") unless $ok_field{$attr};
|
||||
if (defined $self->{$attr}) {
|
||||
return $self->{$attr};
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
1186
mozilla/webtools/bugzilla/CGI.pl
Normal file
1186
mozilla/webtools/bugzilla/CGI.pl
Normal file
File diff suppressed because it is too large
Load Diff
16
mozilla/webtools/bugzilla/README
Normal file
16
mozilla/webtools/bugzilla/README
Normal file
@@ -0,0 +1,16 @@
|
||||
* This README is no longer used to house installation instructions. Instead,
|
||||
it contains pointers to where you may find the information you need.
|
||||
|
||||
* Installation instructions are now found in docs/, with a variety of document
|
||||
types available. Please refer to these documents when installing, configuring,
|
||||
and maintaining your Bugzilla installation. A helpful starting point is
|
||||
docs/txt/Bugzilla-Guide.txt, or with a web browser at docs/html/index.html.
|
||||
|
||||
* Release notes for people upgrading to a new version of Bugzilla are
|
||||
available at docs/rel_notes.txt.
|
||||
|
||||
* If you wish to contribute to the documentation, please read docs/README.docs.
|
||||
|
||||
* The Bugzilla web site is at "http://www.mozilla.org/projects/bugzilla/".
|
||||
This site will contain the latest Bugzilla information, including how to
|
||||
report bugs and how to get help with Bugzilla.
|
||||
268
mozilla/webtools/bugzilla/RelationSet.pm
Normal file
268
mozilla/webtools/bugzilla/RelationSet.pm
Normal file
@@ -0,0 +1,268 @@
|
||||
#
|
||||
# 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) 2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
# Dave Miller <justdave@syndicomm.com>
|
||||
|
||||
# This object models a set of relations between one item and a group
|
||||
# of other items. An example is the set of relations between one bug
|
||||
# and the users CCed on that bug. Currently, the relation objects are
|
||||
# expected to be bugzilla userids. However, this could and perhaps
|
||||
# should be generalized to work with non userid objects, such as
|
||||
# keywords associated with a bug. That shouldn't be hard to do; it
|
||||
# might involve turning this into a virtual base class, and having
|
||||
# UserSet and KeywordSet types that inherit from it.
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
# Everything that uses RelationSet should already have globals.pl loaded
|
||||
# so we don't want to load it here. Doing so causes a loop in Perl because
|
||||
# globals.pl turns around and does a 'use RelationSet'
|
||||
# See http://bugzilla.mozilla.org/show_bug.cgi?id=72862
|
||||
#require "globals.pl";
|
||||
|
||||
package RelationSet;
|
||||
use CGI::Carp qw(fatalsToBrowser);
|
||||
|
||||
# create a new empty RelationSet
|
||||
#
|
||||
sub new {
|
||||
my $type = shift();
|
||||
|
||||
# create a ref to an empty hash and bless it
|
||||
#
|
||||
my $self = {};
|
||||
bless $self, $type;
|
||||
|
||||
# construct from a comma-delimited string
|
||||
#
|
||||
if ($#_ == 0) {
|
||||
$self->mergeFromString($_[0]);
|
||||
}
|
||||
# unless this was a constructor for an empty list, somebody screwed up.
|
||||
#
|
||||
elsif ( $#_ != -1 ) {
|
||||
confess("invalid number of arguments");
|
||||
}
|
||||
|
||||
# bless as a RelationSet
|
||||
#
|
||||
return $self;
|
||||
}
|
||||
|
||||
# Assumes that the set of relations "FROM $table WHERE $constantSql and
|
||||
# $column = $value" is currently represented by $self, and this set should
|
||||
# be updated to look like $other.
|
||||
#
|
||||
# Returns an array of two strings, one INSERT and one DELETE, which will
|
||||
# make this change. Either or both strings may be the empty string,
|
||||
# meaning that no INSERT or DELETE or both (respectively) need to be done.
|
||||
#
|
||||
# THE CALLER IS RESPONSIBLE FOR ANY DESIRED LOCKING AND/OR CONSISTENCY
|
||||
# CHECKS (not to mention doing the SendSQL() calls).
|
||||
#
|
||||
sub generateSqlDeltas {
|
||||
($#_ == 5) || confess("invalid number of arguments");
|
||||
my ( $self, # instance ptr to set representing the existing state
|
||||
$endState, # instance ptr to set representing the desired state
|
||||
$table, # table where these relations are kept
|
||||
$invariantName, # column held const for a RelationSet (often "bug_id")
|
||||
$invariantValue, # what to hold the above column constant at
|
||||
$columnName # the column which varies (often a userid)
|
||||
) = @_;
|
||||
|
||||
# construct the insert list by finding relations which exist in the
|
||||
# end state but not the current state.
|
||||
#
|
||||
my @endStateRelations = keys(%$endState);
|
||||
my @insertList = ();
|
||||
foreach ( @endStateRelations ) {
|
||||
push ( @insertList, $_ ) if ( ! exists $$self{"$_"} );
|
||||
}
|
||||
|
||||
# we've built the list. If it's non-null, add required sql chrome.
|
||||
#
|
||||
my $sqlInsert="";
|
||||
if ( $#insertList > -1 ) {
|
||||
$sqlInsert = "INSERT INTO $table ($invariantName, $columnName) VALUES " .
|
||||
join (",",
|
||||
map ( "($invariantValue, $_)" , @insertList )
|
||||
);
|
||||
}
|
||||
|
||||
# construct the delete list by seeing which relations exist in the
|
||||
# current state but not the end state
|
||||
#
|
||||
my @selfRelations = keys(%$self);
|
||||
my @deleteList = ();
|
||||
foreach ( @selfRelations ) {
|
||||
push (@deleteList, $_) if ( ! exists $$endState{"$_"} );
|
||||
}
|
||||
|
||||
# we've built the list. if it's non-empty, add required sql chrome.
|
||||
#
|
||||
my $sqlDelete = "";
|
||||
if ( $#deleteList > -1 ) {
|
||||
$sqlDelete = "DELETE FROM $table WHERE $invariantName = $invariantValue " .
|
||||
"AND $columnName IN ( " . join (",", @deleteList) . " )";
|
||||
}
|
||||
|
||||
return ($sqlInsert, $sqlDelete);
|
||||
}
|
||||
|
||||
# compare the current object with another.
|
||||
#
|
||||
sub isEqual {
|
||||
($#_ == 1) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
my $other = shift();
|
||||
|
||||
# get arrays of the keys for faster processing
|
||||
#
|
||||
my @selfRelations = keys(%$self);
|
||||
my @otherRelations = keys(%$other);
|
||||
|
||||
# make sure the arrays are the same size
|
||||
#
|
||||
return 0 if ( $#selfRelations != $#otherRelations );
|
||||
|
||||
# bail out if any of the elements are different
|
||||
#
|
||||
foreach my $relation ( @selfRelations ) {
|
||||
return 0 if ( !exists $$other{$relation})
|
||||
}
|
||||
|
||||
# we made it!
|
||||
#
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
# merge the results of a SQL command into this set
|
||||
#
|
||||
sub mergeFromDB {
|
||||
( $#_ == 1 ) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
&::SendSQL(shift());
|
||||
while (my @row = &::FetchSQLData()) {
|
||||
$$self{$row[0]} = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# merge a set in string form into this set
|
||||
#
|
||||
sub mergeFromString {
|
||||
($#_ == 1) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
# do the merge
|
||||
#
|
||||
foreach my $person (split(/[ ,]/, shift())) {
|
||||
if ($person ne "") {
|
||||
$$self{&::DBNameToIdAndCheck($person)} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# remove a set in string form from this set
|
||||
#
|
||||
sub removeItemsInString {
|
||||
($#_ == 1) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
# do the merge
|
||||
#
|
||||
foreach my $person (split(/[ ,]/, shift())) {
|
||||
if ($person ne "") {
|
||||
my $dbid = &::DBNameToIdAndCheck($person);
|
||||
if (exists $$self{$dbid}) {
|
||||
delete $$self{$dbid};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# remove a set in array form from this set
|
||||
#
|
||||
sub removeItemsInArray {
|
||||
($#_ > 0) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
# do the merge
|
||||
#
|
||||
while (my $person = shift()) {
|
||||
if ($person ne "") {
|
||||
my $dbid = &::DBNameToIdAndCheck($person);
|
||||
if (exists $$self{$dbid}) {
|
||||
delete $$self{$dbid};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# return the number of elements in this set
|
||||
#
|
||||
sub size {
|
||||
my $self = shift();
|
||||
|
||||
my @k = keys(%$self);
|
||||
return $#k++;
|
||||
}
|
||||
|
||||
# return this set in array form
|
||||
#
|
||||
sub toArray {
|
||||
my $self= shift();
|
||||
|
||||
return keys(%$self);
|
||||
}
|
||||
|
||||
# return this set as an array of strings
|
||||
#
|
||||
sub toArrayOfStrings {
|
||||
($#_ == 0) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
my @result = ();
|
||||
foreach my $i ( keys %$self ) {
|
||||
push @result, &::DBID_to_name($i);
|
||||
}
|
||||
|
||||
return sort { lc($a) cmp lc($b) } @result;
|
||||
}
|
||||
|
||||
# return this set in string form (comma-separated and sorted)
|
||||
#
|
||||
sub toString {
|
||||
($#_ == 0) || confess("invalid number of arguments");
|
||||
my $self = shift();
|
||||
|
||||
my @result = ();
|
||||
foreach my $i ( keys %$self ) {
|
||||
push @result, &::DBID_to_name($i);
|
||||
}
|
||||
|
||||
return join(',', sort(@result));
|
||||
}
|
||||
|
||||
1;
|
||||
273
mozilla/webtools/bugzilla/Token.pm
Normal file
273
mozilla/webtools/bugzilla/Token.pm
Normal file
@@ -0,0 +1,273 @@
|
||||
# -*- 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 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): Myk Melez <myk@mozilla.org>
|
||||
|
||||
################################################################################
|
||||
# Module Initialization
|
||||
################################################################################
|
||||
|
||||
# Make it harder for us to do dangerous things in Perl.
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
# Bundle the functions in this file together into the "Token" package.
|
||||
package Token;
|
||||
|
||||
use Date::Format;
|
||||
|
||||
# This module requires that its caller have said "require CGI.pl" to import
|
||||
# relevant functions from that script and its companion globals.pl.
|
||||
|
||||
################################################################################
|
||||
# Constants
|
||||
################################################################################
|
||||
|
||||
# The maximum number of days a token will remain valid.
|
||||
my $maxtokenage = 3;
|
||||
|
||||
################################################################################
|
||||
# Functions
|
||||
################################################################################
|
||||
|
||||
sub IssueEmailChangeToken {
|
||||
my ($userid, $old_email, $new_email) = @_;
|
||||
|
||||
my $token_ts = time();
|
||||
my $issuedate = time2str("%Y-%m-%d %H:%M", $token_ts);
|
||||
|
||||
# Generate a unique token and insert it into the tokens table.
|
||||
# We have to lock the tokens table before generating the token,
|
||||
# since the database must be queried for token uniqueness.
|
||||
&::SendSQL("LOCK TABLES tokens WRITE");
|
||||
my $token = GenerateUniqueToken();
|
||||
my $quotedtoken = &::SqlQuote($token);
|
||||
my $quoted_emails = &::SqlQuote($old_email . ":" . $new_email);
|
||||
&::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
|
||||
tokentype , eventdata )
|
||||
VALUES ( $userid , '$issuedate' , $quotedtoken ,
|
||||
'emailold' , $quoted_emails )");
|
||||
my $newtoken = GenerateUniqueToken();
|
||||
$quotedtoken = &::SqlQuote($newtoken);
|
||||
&::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
|
||||
tokentype , eventdata )
|
||||
VALUES ( $userid , '$issuedate' , $quotedtoken ,
|
||||
'emailnew' , $quoted_emails )");
|
||||
&::SendSQL("UNLOCK TABLES");
|
||||
|
||||
# Mail the user the token along with instructions for using it.
|
||||
|
||||
my $template = $::template;
|
||||
my $vars = $::vars;
|
||||
|
||||
$vars->{'oldemailaddress'} = $old_email . &::Param('emailsuffix');
|
||||
$vars->{'newemailaddress'} = $new_email . &::Param('emailsuffix');
|
||||
|
||||
$vars->{'max_token_age'} = $maxtokenage;
|
||||
$vars->{'token_ts'} = $token_ts;
|
||||
|
||||
$vars->{'token'} = $token;
|
||||
$vars->{'emailaddress'} = $old_email . &::Param('emailsuffix');
|
||||
|
||||
my $message;
|
||||
$template->process("account/email/change-old.txt.tmpl", $vars, \$message)
|
||||
|| &::ThrowTemplateError($template->error());
|
||||
|
||||
open SENDMAIL, "|/usr/lib/sendmail -t -i";
|
||||
print SENDMAIL $message;
|
||||
close SENDMAIL;
|
||||
|
||||
$vars->{'token'} = $newtoken;
|
||||
$vars->{'emailaddress'} = $new_email . &::Param('emailsuffix');
|
||||
|
||||
$message = "";
|
||||
$template->process("account/email/change-new.txt.tmpl", $vars, \$message)
|
||||
|| &::ThrowTemplateError($template->error());
|
||||
|
||||
open SENDMAIL, "|/usr/lib/sendmail -t -i";
|
||||
print SENDMAIL $message;
|
||||
close SENDMAIL;
|
||||
|
||||
}
|
||||
|
||||
sub IssuePasswordToken {
|
||||
# Generates a random token, adds it to the tokens table, and sends it
|
||||
# to the user with instructions for using it to change their password.
|
||||
|
||||
my ($loginname) = @_;
|
||||
|
||||
# Retrieve the user's ID from the database.
|
||||
my $quotedloginname = &::SqlQuote($loginname);
|
||||
&::SendSQL("SELECT userid FROM profiles WHERE login_name = $quotedloginname");
|
||||
my ($userid) = &::FetchSQLData();
|
||||
|
||||
my $token_ts = time();
|
||||
my $issuedate = time2str("%Y-%m-%d %H:%M", $token_ts);
|
||||
|
||||
# Generate a unique token and insert it into the tokens table.
|
||||
# We have to lock the tokens table before generating the token,
|
||||
# since the database must be queried for token uniqueness.
|
||||
&::SendSQL("LOCK TABLE tokens WRITE") if $::driver eq 'mysql';
|
||||
my $token = GenerateUniqueToken();
|
||||
my $quotedtoken = &::SqlQuote($token);
|
||||
my $quotedipaddr = &::SqlQuote($::ENV{'REMOTE_ADDR'});
|
||||
&::SendSQL("INSERT INTO tokens ( userid , issuedate , token , tokentype , eventdata )
|
||||
VALUES ( $userid , '$issuedate' , $quotedtoken , 'password' , $quotedipaddr )");
|
||||
&::SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
|
||||
# Mail the user the token along with instructions for using it.
|
||||
|
||||
my $template = $::template;
|
||||
my $vars = $::vars;
|
||||
|
||||
$vars->{'token'} = $token;
|
||||
$vars->{'emailaddress'} = $loginname . &::Param('emailsuffix');
|
||||
|
||||
$vars->{'max_token_age'} = $maxtokenage;
|
||||
$vars->{'token_ts'} = $token_ts;
|
||||
|
||||
my $message = "";
|
||||
$template->process("account/password/forgotten-password.txt.tmpl",
|
||||
$vars, \$message)
|
||||
|| &::ThrowTemplateError($template->error());
|
||||
|
||||
open SENDMAIL, "|/usr/lib/sendmail -t -i";
|
||||
print SENDMAIL $message;
|
||||
close SENDMAIL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub CleanTokenTable {
|
||||
&::SendSQL("LOCK TABLES tokens WRITE") if $::driver eq 'mysql';
|
||||
if ($::driver eq 'mysql') {
|
||||
&::SendSQL("DELETE FROM tokens WHERE TO_DAYS(NOW()) - TO_DAYS(issuedate) >= " . $maxtokenage);
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
&::SendSQL("DELETE FROM tokens WHERE now() - issuedate >= '$maxtokenage days'");
|
||||
}
|
||||
&::SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
}
|
||||
|
||||
|
||||
sub GenerateUniqueToken {
|
||||
# Generates a unique random token. Uses &GenerateRandomPassword
|
||||
# for the tokens themselves and checks uniqueness by searching for
|
||||
# the token in the "tokens" table. Gives up if it can't come up
|
||||
# with a token after about one hundred tries.
|
||||
|
||||
my $token;
|
||||
my $duplicate = 1;
|
||||
my $tries = 0;
|
||||
while ($duplicate) {
|
||||
|
||||
++$tries;
|
||||
if ($tries > 100) {
|
||||
&::DisplayError("Something is seriously wrong with the token generation system.");
|
||||
exit;
|
||||
}
|
||||
|
||||
$token = &::GenerateRandomPassword();
|
||||
&::SendSQL("SELECT userid FROM tokens WHERE token = " . &::SqlQuote($token));
|
||||
$duplicate = &::FetchSQLData();
|
||||
}
|
||||
|
||||
return $token;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub Cancel {
|
||||
# Cancels a previously issued token and notifies the system administrator.
|
||||
# This should only happen when the user accidentally makes a token request
|
||||
# or when a malicious hacker makes a token request on behalf of a user.
|
||||
|
||||
my ($token, $cancelaction) = @_;
|
||||
|
||||
# Quote the token for inclusion in SQL statements.
|
||||
my $quotedtoken = &::SqlQuote($token);
|
||||
|
||||
# Get information about the token being cancelled.
|
||||
&::SendSQL("SELECT issuedate , tokentype , eventdata , login_name , realname
|
||||
FROM tokens, profiles
|
||||
WHERE tokens.userid = profiles.userid
|
||||
AND token = $quotedtoken");
|
||||
my ($issuedate, $tokentype, $eventdata, $loginname, $realname) = &::FetchSQLData();
|
||||
|
||||
# Get the email address of the Bugzilla maintainer.
|
||||
my $maintainer = &::Param('maintainer');
|
||||
|
||||
# Format the user's real name and email address into a single string.
|
||||
my $username = $realname ? $realname . " <" . $loginname . ">" : $loginname;
|
||||
|
||||
my $template = $::template;
|
||||
my $vars = $::vars;
|
||||
|
||||
$vars->{'emailaddress'} = $username;
|
||||
$vars->{'maintainer'} = $maintainer;
|
||||
$vars->{'remoteaddress'} = $::ENV{'REMOTE_ADDR'};
|
||||
$vars->{'token'} = $token;
|
||||
$vars->{'tokentype'} = $tokentype;
|
||||
$vars->{'issuedate'} = $issuedate;
|
||||
$vars->{'eventdata'} = $eventdata;
|
||||
$vars->{'cancelaction'} = $cancelaction;
|
||||
|
||||
# Notify the user via email about the cancellation.
|
||||
|
||||
my $message;
|
||||
$template->process("account/cancel-token.txt.tmpl", $vars, \$message)
|
||||
|| &::ThrowTemplateError($template->error());
|
||||
|
||||
open SENDMAIL, "|/usr/lib/sendmail -t -i";
|
||||
print SENDMAIL $message;
|
||||
close SENDMAIL;
|
||||
|
||||
# Delete the token from the database.
|
||||
&::SendSQL("LOCK TABLE tokens WRITE") if $::driver eq 'mysql';
|
||||
&::SendSQL("DELETE FROM tokens WHERE token = $quotedtoken");
|
||||
&::SendSQL("UNLOCK TABLES") if $::driver eq 'mysql';
|
||||
}
|
||||
|
||||
sub HasPasswordToken {
|
||||
# Returns a password token if the user has one.
|
||||
|
||||
my ($userid) = @_;
|
||||
|
||||
&::SendSQL("SELECT token FROM tokens
|
||||
WHERE userid = $userid AND tokentype = 'password' LIMIT 1");
|
||||
my ($token) = &::FetchSQLData();
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
sub HasEmailChangeToken {
|
||||
# Returns an email change token if the user has one.
|
||||
|
||||
my ($userid) = @_;
|
||||
|
||||
&::SendSQL("SELECT token FROM tokens
|
||||
WHERE userid = $userid
|
||||
AND tokentype = 'emailnew'
|
||||
OR tokentype = 'emailold' LIMIT 1");
|
||||
my ($token) = &::FetchSQLData();
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
3
mozilla/webtools/bugzilla/UPGRADING
Normal file
3
mozilla/webtools/bugzilla/UPGRADING
Normal file
@@ -0,0 +1,3 @@
|
||||
Please consult The Bugzilla Guide for instructions on how to upgrade
|
||||
Bugzilla from an older version. The Guide can be found with this
|
||||
distribution, in docs/html, docs/txt, and docs/sgml.
|
||||
407
mozilla/webtools/bugzilla/UPGRADING-pre-2.8
Normal file
407
mozilla/webtools/bugzilla/UPGRADING-pre-2.8
Normal file
@@ -0,0 +1,407 @@
|
||||
This file contains only important changes made to Bugzilla before release
|
||||
2.8. If you are upgrading from version older than 2.8, please read this file.
|
||||
If you are upgrading from 2.8 or newer, please read the Installation and
|
||||
Upgrade instructions in The Bugzilla Guide, found with this distribution in
|
||||
docs/html, docs/txt, and docs/sgml.
|
||||
|
||||
For a complete list of what changes, use Bonsai
|
||||
(http://cvs-mirror.mozilla.org/webtools/bonsai/cvsqueryform.cgi) to
|
||||
query the CVS tree. For example,
|
||||
|
||||
http://cvs-mirror.mozilla.org/webtools/bonsai/cvsquery.cgi?module=all&branch=HEAD&branchtype=match&dir=mozilla%2Fwebtools%2Fbugzilla&file=&filetype=match&who=&whotype=match&sortby=Date&hours=2&date=week&mindate=&maxdate=&cvsroot=%2Fcvsroot
|
||||
|
||||
will tell you what has been changed in the last week.
|
||||
|
||||
|
||||
10/12/99 The CHANGES file is now obsolete! There is a new file called
|
||||
checksetup.pl. You should get in the habit of running that file every time
|
||||
you update your installation of Bugzilla. That file will be constantly
|
||||
updated to automatically update your installation to match any code changes.
|
||||
If you're curious as to what is going on, changes are commented in that file,
|
||||
at the end.
|
||||
|
||||
Many thanks to Holger Schurig <holgerschurig@nikocity.de> for writing this
|
||||
script!
|
||||
|
||||
|
||||
|
||||
10/11/99 Restructured voting database to add a cached value in each
|
||||
bug recording how many total votes that bug has. While I'm at it, I
|
||||
removed the unused "area" field from the bugs database. It is
|
||||
distressing to realize that the bugs table has reached the maximum
|
||||
number of indices allowed by MySQL (16), which may make future
|
||||
enhancements awkward.
|
||||
|
||||
You must feed the following to MySQL:
|
||||
|
||||
alter table bugs drop column area;
|
||||
alter table bugs add column votes mediumint not null, add index (votes);
|
||||
|
||||
You then *must* delete the data/versioncache file when you make this
|
||||
change, as it contains references to the "area" field. Deleting it is safe,
|
||||
bugzilla will correctly regenerate it.
|
||||
|
||||
If you have been using the voting feature at all, then you will then
|
||||
need to update the voting cache. You can do this by visiting the
|
||||
sanitycheck.cgi page, and taking it up on its offer to rebuild the
|
||||
votes stuff.
|
||||
|
||||
|
||||
10/7/99 Added voting ability. You must run the new script
|
||||
"makevotestable.sh". You must also feed the following to mysql:
|
||||
|
||||
alter table products add column votesperuser smallint not null;
|
||||
|
||||
|
||||
|
||||
9/15/99 Apparently, newer alphas of MySQL won't allow you to have
|
||||
"when" as a column name. So, I have had to rename a column in the
|
||||
bugs_activity table. You must feed the below to mysql or you won't
|
||||
work at all.
|
||||
|
||||
alter table bugs_activity change column when bug_when datetime not null;
|
||||
|
||||
|
||||
8/16/99 Added "OpenVMS" to the list of OS's. Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "BeOS", "OpenVMS", "other") not null;
|
||||
|
||||
6/22/99 Added an entry to the attachments table to record who the submitter
|
||||
was. Nothing uses this yet, but it still should be recorded.
|
||||
|
||||
alter table attachments add column submitter_id mediumint not null;
|
||||
|
||||
You should also run this script to populate the new field:
|
||||
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
use diagnostics;
|
||||
use strict;
|
||||
require "globals.pl";
|
||||
$|=1;
|
||||
ConnectToDatabase();
|
||||
SendSQL("select bug_id, attach_id from attachments order by bug_id");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
my @row = FetchSQLData();
|
||||
push(@list, \@row);
|
||||
}
|
||||
foreach my $ref (@list) {
|
||||
my ($bug, $attach) = (@$ref);
|
||||
SendSQL("select long_desc from bugs where bug_id = $bug");
|
||||
my $comment = FetchOneColumn() . "Created an attachment (id=$attach)";
|
||||
|
||||
if ($comment =~ m@-* Additional Comments From ([^ ]*)[- 0-9/:]*\nCreated an attachment \(id=$attach\)@) {
|
||||
print "Found $1\n";
|
||||
SendSQL("select userid from profiles where login_name=" .
|
||||
SqlQuote($1));
|
||||
my $userid = FetchOneColumn();
|
||||
if (defined $userid && $userid > 0) {
|
||||
SendSQL("update attachments set submitter_id=$userid where attach_id = $attach");
|
||||
}
|
||||
} else {
|
||||
print "Bug $bug can't find comment for attachment $attach\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6/14/99 Added "BeOS" to the list of OS's. Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "BeOS", "other") not null;
|
||||
|
||||
|
||||
5/27/99 Added support for dependency information. You must run the new
|
||||
"makedependenciestable.sh" script. You can turn off dependencies with the new
|
||||
"usedependencies" param, but it defaults to being on. Also, read very
|
||||
carefully the description for the new "webdotbase" param; you will almost
|
||||
certainly need to tweak it.
|
||||
|
||||
|
||||
5/24/99 Added "Mac System 8.6" and "Neutrino" to the list of OS's.
|
||||
Feed this to mysql:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "Mac System 8.6", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "Neutrino", "OS/2", "other") not null;
|
||||
|
||||
|
||||
5/12/99 Added a pref to control how much email you get. This needs a new
|
||||
column in the profiles table, so feed the following to mysql:
|
||||
|
||||
alter table profiles add column emailnotification enum("ExcludeSelfChanges", "CConly", "All") not null default "ExcludeSelfChanges";
|
||||
|
||||
5/5/99 Added the ability to search by creation date. To make this perform
|
||||
well, you ought to do the following:
|
||||
|
||||
alter table bugs change column creation_ts creation_ts datetime not null, add index (creation_ts);
|
||||
|
||||
|
||||
4/30/99 Added a new severity, "blocker". To get this into your running
|
||||
Bugzilla, do the following:
|
||||
|
||||
alter table bugs change column bug_severity bug_severity enum("blocker", "critical", "major", "normal", "minor", "trivial", "enhancement") not null;
|
||||
|
||||
|
||||
4/22/99 There was a bug where the long descriptions of bugs had a variety of
|
||||
newline characters at the end, depending on the operating system of the browser
|
||||
that submitted the text. This bug has been fixed, so that no further changes
|
||||
like that will happen. But to fix problems that have already crept into your
|
||||
database, you can run the following perl script (which is slow and ugly, but
|
||||
does work:)
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
use diagnostics;
|
||||
use strict;
|
||||
require "globals.pl";
|
||||
$|=1;
|
||||
ConnectToDatabase();
|
||||
SendSQL("select bug_id from bugs order by bug_id");
|
||||
my @list;
|
||||
while (MoreSQLData()) {
|
||||
push(@list, FetchOneColumn());
|
||||
}
|
||||
foreach my $id (@list) {
|
||||
if ($id % 50 == 0) {
|
||||
print "\n$id ";
|
||||
}
|
||||
SendSQL("select long_desc from bugs where bug_id = $id");
|
||||
my $comment = FetchOneColumn();
|
||||
my $orig = $comment;
|
||||
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
|
||||
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
|
||||
if ($comment ne $orig) {
|
||||
SendSQL("update bugs set long_desc = " . SqlQuote($comment) .
|
||||
" where bug_id = $id");
|
||||
print ".";
|
||||
} else {
|
||||
print "-";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
4/8/99 Added ability to store patches with bugs. This requires a new table
|
||||
to store the data, so you will need to run the "makeattachmenttable.sh" script.
|
||||
|
||||
3/25/99 Unfortunately, the HTML::FromText CPAN module had too many bugs, and
|
||||
so I had to roll my own. We no longer use the HTML::FromText CPAN module.
|
||||
|
||||
3/24/99 (This entry has been removed. It used to say that we required the
|
||||
HTML::FromText CPAN module, but that's no longer true.)
|
||||
|
||||
3/22/99 Added the ability to query by fields which have changed within a date
|
||||
range. To make this perform a bit better, we need a new index:
|
||||
|
||||
alter table bugs_activity add index (field);
|
||||
|
||||
3/10/99 Added 'groups' stuff, where we have different group bits that we can
|
||||
put on a person or on a bug. Some of the group bits control access to bugzilla
|
||||
features. And a person can't access a bug unless he has every group bit set
|
||||
that is also set on the bug. See the comments in makegroupstable.sh for a bit
|
||||
more info.
|
||||
|
||||
The 'maintainer' param is now used only as an email address for people to send
|
||||
complaints to. The groups table is what is now used to determine permissions.
|
||||
|
||||
You will need to run the new script "makegroupstable.sh". And then you need to
|
||||
feed the following lines to MySQL (replace XXX with the login name of the
|
||||
maintainer, the person you wish to be all-powerful).
|
||||
|
||||
alter table bugs add column groupset bigint not null;
|
||||
alter table profiles add column groupset bigint not null;
|
||||
update profiles set groupset=0x7fffffffffffffff where login_name = XXX;
|
||||
|
||||
|
||||
|
||||
3/8/99 Added params to control how priorities are set in a new bug. You can
|
||||
now choose whether to let submitters of new bugs choose a priority, or whether
|
||||
they should just accept the default priority (which is now no longer hardcoded
|
||||
to "P2", but is instead a param.) The default value of the params will cause
|
||||
the same behavior as before.
|
||||
|
||||
3/3/99 Added a "disallownew" field to the products table. If non-zero, then
|
||||
don't let people file new bugs against this product. (This is for when a
|
||||
product is retired, but you want to keep the bug reports around for posterity.)
|
||||
Feed this to MySQL:
|
||||
|
||||
alter table products add column disallownew tinyint not null;
|
||||
|
||||
|
||||
2/8/99 Added FreeBSD to the list of OS's. Feed this to MySQL:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "FreeBSD", "OSF/1", "Solaris", "SunOS", "OS/2", "other") not null;
|
||||
|
||||
|
||||
2/4/99 Added a new column "description" to the components table, and added
|
||||
links to a new page which will use this to describe the components of a
|
||||
given product. Feed this to MySQL:
|
||||
|
||||
alter table components add column description mediumtext not null;
|
||||
|
||||
|
||||
2/3/99 Added a new column "initialqacontact" to the components table that gives
|
||||
an initial QA contact field. It may be empty if you wish the initial qa
|
||||
contact to be empty. If you're not using the QA contact field, you don't need
|
||||
to add this column, but you might as well be safe and add it anyway:
|
||||
|
||||
alter table components add column initialqacontact tinytext not null;
|
||||
|
||||
|
||||
2/2/99 Added a new column "milestoneurl" to the products table that gives a URL
|
||||
which is to describe the currently defined milestones for a product. If you
|
||||
don't use target milestone, you might be able to get away without adding this
|
||||
column, but you might as well be safe and add it anyway:
|
||||
|
||||
alter table products add column milestoneurl tinytext not null;
|
||||
|
||||
|
||||
1/29/99 Whoops; had a misspelled op_sys. It was "Mac System 7.1.6"; it should
|
||||
be "Mac System 7.6.1". It turns out I had no bugs with this value set, so I
|
||||
could just do the below simple command. If you have bugs with this value, you
|
||||
may need to do something more complicated.
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.6.1", "Mac System 8.0", "Mac System 8.5", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "OSF/1", "Solaris", "SunOS", "OS/2", "other") not null;
|
||||
|
||||
|
||||
|
||||
1/20/99 Added new fields: Target Milestone, QA Contact, and Status Whiteboard.
|
||||
These fields are all optional in the UI; there are parameters to turn them on.
|
||||
However, whether or not you use them, the fields need to be in the DB. There
|
||||
is some code that needs them, even if you don't.
|
||||
|
||||
To update your DB to have these fields, send the following to MySQL:
|
||||
|
||||
alter table bugs add column target_milestone varchar(20) not null,
|
||||
add column qa_contact mediumint not null,
|
||||
add column status_whiteboard mediumtext not null,
|
||||
add index (target_milestone), add index (qa_contact);
|
||||
|
||||
|
||||
|
||||
1/18/99 You can now query by CC. To make this perform reasonably, the CC table
|
||||
needs some indices. The following MySQL does the necessary stuff:
|
||||
|
||||
alter table cc add index (bug_id), add index (who);
|
||||
|
||||
|
||||
1/15/99 The op_sys field can now be queried by (and more easily tweaked).
|
||||
To make this perform reasonably, it needs an index. The following MySQL
|
||||
command will create the necessary index:
|
||||
|
||||
alter table bugs add index (op_sys);
|
||||
|
||||
|
||||
12/2/98 The op_sys and rep_platform fields have been tweaked. op_sys
|
||||
is now an enum, rather than having the legal values all hard-coded in
|
||||
perl. rep_platform now no longer allows a value of "X-Windows".
|
||||
|
||||
Here's how I ported to the new world. This ought to work for you too.
|
||||
Actually, it's probably overkill. I had a lot of illegal values for op_sys
|
||||
in my tables, from importing bugs from strange places. If you haven't done
|
||||
anything funky, then much of the below will be a no-op.
|
||||
|
||||
First, send the following commands to MySQL to make sure all your values for
|
||||
rep_platform and op_sys are legal in the new world..
|
||||
|
||||
update bugs set rep_platform="Sun" where rep_platform="X-Windows" and op_sys like "Solaris%";
|
||||
update bugs set rep_platform="SGI" where rep_platform="X-Windows" and op_sys = "IRIX";
|
||||
update bugs set rep_platform="SGI" where rep_platform="X-Windows" and op_sys = "HP-UX";
|
||||
update bugs set rep_platform="DEC" where rep_platform="X-Windows" and op_sys = "OSF/1";
|
||||
update bugs set rep_platform="PC" where rep_platform="X-Windows" and op_sys = "Linux";
|
||||
update bugs set rep_platform="other" where rep_platform="X-Windows";
|
||||
update bugs set rep_platform="other" where rep_platform="";
|
||||
update bugs set op_sys="Mac System 7" where op_sys="System 7";
|
||||
update bugs set op_sys="Mac System 7.5" where op_sys="System 7.5";
|
||||
update bugs set op_sys="Mac System 8.0" where op_sys="8.0";
|
||||
update bugs set op_sys="OSF/1" where op_sys="Digital Unix 4.0";
|
||||
update bugs set op_sys="IRIX" where op_sys like "IRIX %";
|
||||
update bugs set op_sys="HP-UX" where op_sys like "HP-UX %";
|
||||
update bugs set op_sys="Windows NT" where op_sys like "NT %";
|
||||
update bugs set op_sys="OSF/1" where op_sys like "OSF/1 %";
|
||||
update bugs set op_sys="Solaris" where op_sys like "Solaris %";
|
||||
update bugs set op_sys="SunOS" where op_sys like "SunOS%";
|
||||
update bugs set op_sys="other" where op_sys = "Motif";
|
||||
update bugs set op_sys="other" where op_sys = "Other";
|
||||
|
||||
Next, send the following commands to make sure you now have only legal
|
||||
entries in your table. If either of the queries do not come up empty, then
|
||||
you have to do more stuff like the above.
|
||||
|
||||
select bug_id,op_sys,rep_platform from bugs where rep_platform not regexp "^(All|DEC|HP|Macintosh|PC|SGI|Sun|X-Windows|Other)$";
|
||||
select bug_id,op_sys,rep_platform from bugs where op_sys not regexp "^(All|Windows 3.1|Windows 95|Windows 98|Windows NT|Mac System 7|Mac System 7.5|Mac System 7.1.6|Mac System 8.0|AIX|BSDI|HP-UX|IRIX|Linux|OSF/1|Solaris|SunOS|other)$";
|
||||
|
||||
Finally, once that's all clear, alter the table to make enforce the new legal
|
||||
entries:
|
||||
|
||||
alter table bugs change column op_sys op_sys enum("All", "Windows 3.1", "Windows 95", "Windows 98", "Windows NT", "Mac System 7", "Mac System 7.5", "Mac System 7.1.6", "Mac System 8.0", "AIX", "BSDI", "HP-UX", "IRIX", "Linux", "OSF/1", "Solaris", "SunOS", "other") not null, change column rep_platform rep_platform enum("All", "DEC", "HP", "Macintosh", "PC", "SGI", "Sun", "Other");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11/20/98 Added searching of CC field. To better support this, added
|
||||
some indexes to the CC table. You probably want to execute the following
|
||||
mysql commands:
|
||||
|
||||
alter table cc add index (bug_id);
|
||||
alter table cc add index (who);
|
||||
|
||||
|
||||
10/27/98 security check for legal products in place. bug charts are not
|
||||
available as an option if collectstats.pl has never been run. all products
|
||||
get daily stats collected now. README updated: Chart::Base is listed as
|
||||
a requirement, instructions for using collectstats.pl included as
|
||||
an optional step. also got silly and added optional quips to bug
|
||||
reports.
|
||||
|
||||
10/17/98 modified README installation instructions slightly.
|
||||
|
||||
10/7/98 Added a new table called "products". Right now, this is used
|
||||
only to have a description for each product, and that description is
|
||||
only used when initially adding a new bug. Anyway, you *must* create
|
||||
the new table (which you can do by running the new makeproducttable.sh
|
||||
script). If you just leave it empty, things will work much as they
|
||||
did before, or you can add descriptions for some or all of your
|
||||
products.
|
||||
|
||||
|
||||
9/15/98 Everything has been ported to Perl. NO MORE TCL. This
|
||||
transition should be relatively painless, except for the "params"
|
||||
file. This is the file that contains parameters you've set up on the
|
||||
editparams.cgi page. Before changing to Perl, this was a tcl-syntax
|
||||
file, stored in the same directory as the code; after the change to
|
||||
Perl, it becomes a perl-syntax file, stored in a subdirectory named
|
||||
"data". See the README file for more details on what version of Perl
|
||||
you need.
|
||||
|
||||
So, if updating from an older version of Bugzilla, you will need to
|
||||
edit data/param, change the email address listed for
|
||||
$::param{'maintainer'}, and then go revisit the editparams.cgi page
|
||||
and reset all the parameters to your taste. Fortunately, your old
|
||||
params file will still be around, and so you ought to be able to
|
||||
cut&paste important bits from there.
|
||||
|
||||
Also, note that the "whineatnews" script has changed name (it now has
|
||||
an extension of .pl instead of .tcl), so you'll need to change your
|
||||
cron job.
|
||||
|
||||
And the "comments" file has been moved to the data directory. Just do
|
||||
"cat comments >> data/comments" to restore any old comments that may
|
||||
have been lost.
|
||||
|
||||
|
||||
|
||||
9/2/98 Changed the way password validation works. We now keep a
|
||||
crypt'd version of the password in the database, and check against
|
||||
that. (This is silly, because we're also keeping the plaintext
|
||||
version there, but I have plans...) Stop passing the plaintext
|
||||
password around as a cookie; instead, we have a cookie that references
|
||||
a record in a new database table, logincookies.
|
||||
|
||||
IMPORTANT: if updating from an older version of Bugzilla, you must run
|
||||
the following commands to keep things working:
|
||||
|
||||
./makelogincookiestable.sh
|
||||
echo "alter table profiles add column cryptpassword varchar(64);" | mysql bugs
|
||||
echo "update profiles set cryptpassword = encrypt(password,substring(rand(),3, 4));" | mysql bugs
|
||||
|
||||
BIN
mozilla/webtools/bugzilla/ant.jpg
Normal file
BIN
mozilla/webtools/bugzilla/ant.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
792
mozilla/webtools/bugzilla/attachment.cgi
Executable file
792
mozilla/webtools/bugzilla/attachment.cgi
Executable file
@@ -0,0 +1,792 @@
|
||||
#!/usr/bonsaitools/bin/perl -wT
|
||||
# -*- 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 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>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
|
||||
################################################################################
|
||||
# Script Initialization
|
||||
################################################################################
|
||||
|
||||
# Make it harder for us to do dangerous things in Perl.
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
use vars qw(
|
||||
$template
|
||||
$vars
|
||||
);
|
||||
|
||||
# Include the Bugzilla CGI and general utility library.
|
||||
require "CGI.pl";
|
||||
|
||||
# Establish a connection to the database backend.
|
||||
ConnectToDatabase();
|
||||
|
||||
# Check whether or not the user is logged in and, if so, set the $userid
|
||||
my $userid = quietly_check_login();
|
||||
|
||||
################################################################################
|
||||
# Main Body Execution
|
||||
################################################################################
|
||||
|
||||
# All calls to this script should contain an "action" variable whose value
|
||||
# determines what the user wants to do. The code below checks the value of
|
||||
# that variable and runs the appropriate code.
|
||||
|
||||
# Determine whether to use the action specified by the user or the default.
|
||||
my $action = $::FORM{'action'} || 'view';
|
||||
|
||||
if ($action eq "view")
|
||||
{
|
||||
validateID();
|
||||
view();
|
||||
}
|
||||
elsif ($action eq "viewall")
|
||||
{
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
viewall();
|
||||
}
|
||||
elsif ($action eq "enter")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
enter();
|
||||
}
|
||||
elsif ($action eq "insert")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
ValidateBugID($::FORM{'bugid'}, $userid);
|
||||
ValidateComment($::FORM{'comment'});
|
||||
validateFilename();
|
||||
validateData();
|
||||
validateDescription();
|
||||
validateIsPatch();
|
||||
validateContentType() unless $::FORM{'ispatch'};
|
||||
validateObsolete() if $::FORM{'obsolete'};
|
||||
insert();
|
||||
}
|
||||
elsif ($action eq "edit")
|
||||
{
|
||||
quietly_check_login();
|
||||
validateID();
|
||||
validateCanEdit($::FORM{'id'});
|
||||
edit();
|
||||
}
|
||||
elsif ($action eq "update")
|
||||
{
|
||||
my $userid = confirm_login();
|
||||
UserInGroup($userid, "editbugs")
|
||||
|| DisplayError("You are not authorized to edit attachments.")
|
||||
&& exit;
|
||||
ValidateComment($::FORM{'comment'});
|
||||
validateID();
|
||||
validateCanEdit($::FORM{'id'});
|
||||
validateDescription();
|
||||
validateIsPatch();
|
||||
validateContentType() unless $::FORM{'ispatch'};
|
||||
validateIsObsolete();
|
||||
validateStatuses();
|
||||
update();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayError("I could not figure out what you wanted to do.")
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
################################################################################
|
||||
# Data Validation / Security Authorization
|
||||
################################################################################
|
||||
|
||||
sub validateID
|
||||
{
|
||||
# Validate the value of the "id" form field, which must contain an
|
||||
# integer that is the ID of an existing attachment.
|
||||
|
||||
detaint_natural($::FORM{'id'})
|
||||
|| DisplayError("You did not enter a valid attachment number.")
|
||||
&& exit;
|
||||
|
||||
# Make sure the attachment exists in the database.
|
||||
SendSQL("SELECT bug_id FROM attachments WHERE attach_id = $::FORM{'id'}");
|
||||
MoreSQLData()
|
||||
|| DisplayError("Attachment #$::FORM{'id'} does not exist.")
|
||||
&& exit;
|
||||
|
||||
# Make sure the user is authorized to access this attachment's bug.
|
||||
my ($bugid) = FetchSQLData();
|
||||
ValidateBugID($bugid, $userid);
|
||||
}
|
||||
|
||||
sub validateCanEdit
|
||||
{
|
||||
my ($attach_id) = (@_);
|
||||
|
||||
# If the user is not logged in, claim that they can edit. This allows
|
||||
# the edit scrren to be displayed to people who aren't logged in.
|
||||
# People not logged in can't actually commit changes, because that code
|
||||
# calls confirm_login, not quietly_check_login, before calling this sub
|
||||
return if $userid == 0;
|
||||
|
||||
# People in editbugs can edit all attachments
|
||||
return if UserInGroup($userid, "editbugs");
|
||||
|
||||
# Bug 97729 - the submitter can edit their attachments
|
||||
SendSQL("SELECT attach_id FROM attachments WHERE " .
|
||||
"attach_id = $attach_id AND submitter_id = $userid");
|
||||
|
||||
FetchSQLData()
|
||||
|| DisplayError("You are not authorised to edit attachment #$attach_id")
|
||||
&& exit;
|
||||
}
|
||||
|
||||
sub validateDescription
|
||||
{
|
||||
$::FORM{'description'}
|
||||
|| DisplayError("You must enter a description for the attachment.")
|
||||
&& exit;
|
||||
}
|
||||
|
||||
sub validateIsPatch
|
||||
{
|
||||
# Set the ispatch flag to zero if it is undefined, since the UI uses
|
||||
# an HTML checkbox to represent this flag, and unchecked HTML checkboxes
|
||||
# do not get sent in HTML requests.
|
||||
$::FORM{'ispatch'} = $::FORM{'ispatch'} ? 1 : 0;
|
||||
|
||||
# Set the content type to text/plain if the attachment is a patch.
|
||||
$::FORM{'contenttype'} = "text/plain" if $::FORM{'ispatch'};
|
||||
}
|
||||
|
||||
sub validateContentType
|
||||
{
|
||||
if (!$::FORM{'contenttypemethod'})
|
||||
{
|
||||
DisplayError("You must choose a method for determining the content type,
|
||||
either <em>auto-detect</em>, <em>select from list</em>, or <em>enter
|
||||
manually</em>.");
|
||||
exit;
|
||||
}
|
||||
elsif ($::FORM{'contenttypemethod'} eq 'autodetect')
|
||||
{
|
||||
# The user asked us to auto-detect the content type, so use the type
|
||||
# specified in the HTTP request headers.
|
||||
if ( !$::FILE{'data'}->{'contenttype'} )
|
||||
{
|
||||
DisplayError("You asked Bugzilla to auto-detect the content type, but
|
||||
your browser did not specify a content type when uploading the file,
|
||||
so you must enter a content type manually.");
|
||||
exit;
|
||||
}
|
||||
$::FORM{'contenttype'} = $::FILE{'data'}->{'contenttype'};
|
||||
}
|
||||
elsif ($::FORM{'contenttypemethod'} eq 'list')
|
||||
{
|
||||
# The user selected a content type from the list, so use their selection.
|
||||
$::FORM{'contenttype'} = $::FORM{'contenttypeselection'};
|
||||
}
|
||||
elsif ($::FORM{'contenttypemethod'} eq 'manual')
|
||||
{
|
||||
# The user entered a content type manually, so use their entry.
|
||||
$::FORM{'contenttype'} = $::FORM{'contenttypeentry'};
|
||||
}
|
||||
else
|
||||
{
|
||||
my $htmlcontenttypemethod = html_quote($::FORM{'contenttypemethod'});
|
||||
DisplayError("Your form submission got corrupted somehow. The <em>content
|
||||
method</em> field, which specifies how the content type gets determined,
|
||||
should have been either <em>autodetect</em>, <em>list</em>,
|
||||
or <em>manual</em>, but was instead <em>$htmlcontenttypemethod</em>.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( $::FORM{'contenttype'} !~ /^(application|audio|image|message|model|multipart|text|video)\/.+$/ )
|
||||
{
|
||||
my $htmlcontenttype = html_quote($::FORM{'contenttype'});
|
||||
DisplayError("The content type <em>$htmlcontenttype</em> is invalid.
|
||||
Valid types must be of the form <em>foo/bar</em> where <em>foo</em>
|
||||
is either <em>application, audio, image, message, model, multipart,
|
||||
text,</em> or <em>video</em>.");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub validateIsObsolete
|
||||
{
|
||||
# Set the isobsolete flag to zero if it is undefined, since the UI uses
|
||||
# an HTML checkbox to represent this flag, and unchecked HTML checkboxes
|
||||
# do not get sent in HTML requests.
|
||||
$::FORM{'isobsolete'} = $::FORM{'isobsolete'} ? 1 : 0;
|
||||
}
|
||||
|
||||
sub validateStatuses
|
||||
{
|
||||
# Get a list of attachment statuses that are valid for this attachment.
|
||||
PushGlobalSQLState();
|
||||
SendSQL("SELECT attachstatusdefs.id
|
||||
FROM attachments, bugs, attachstatusdefs
|
||||
WHERE attachments.attach_id = $::FORM{'id'}
|
||||
AND attachments.bug_id = bugs.bug_id
|
||||
AND attachstatusdefs.product = bugs.product");
|
||||
my @statusdefs;
|
||||
push(@statusdefs, FetchSQLData()) while MoreSQLData();
|
||||
PopGlobalSQLState();
|
||||
|
||||
foreach my $status (@{$::MFORM{'status'}})
|
||||
{
|
||||
grep($_ == $status, @statusdefs)
|
||||
|| DisplayError("One of the statuses you entered is not a valid status
|
||||
for this attachment.")
|
||||
&& exit;
|
||||
# We have tested that the status is valid, so it can be detainted
|
||||
detaint_natural($status);
|
||||
}
|
||||
}
|
||||
|
||||
sub validateData
|
||||
{
|
||||
$::FORM{'data'}
|
||||
|| DisplayError("The file you are trying to attach is empty!")
|
||||
&& exit;
|
||||
|
||||
my $len = length($::FORM{'data'});
|
||||
|
||||
my $maxpatchsize = Param('maxpatchsize');
|
||||
my $maxattachmentsize = Param('maxattachmentsize');
|
||||
|
||||
# Makes sure the attachment does not exceed either the "maxpatchsize" or
|
||||
# the "maxattachmentsize" parameter.
|
||||
if ( $::FORM{'ispatch'} && $maxpatchsize && $len > $maxpatchsize*1024 )
|
||||
{
|
||||
my $lenkb = sprintf("%.0f", $len/1024);
|
||||
DisplayError("The file you are trying to attach is ${lenkb} kilobytes (KB) in size.
|
||||
Patches cannot be more than ${maxpatchsize}KB in size.
|
||||
Try breaking your patch into several pieces.");
|
||||
exit;
|
||||
} elsif ( !$::FORM{'ispatch'} && $maxattachmentsize && $len > $maxattachmentsize*1024 ) {
|
||||
my $lenkb = sprintf("%.0f", $len/1024);
|
||||
DisplayError("The file you are trying to attach is ${lenkb} kilobytes (KB) in size.
|
||||
Non-patch attachments cannot be more than ${maxattachmentsize}KB.
|
||||
If your attachment is an image, try converting it to a compressable
|
||||
format like JPG or PNG, or put it elsewhere on the web and
|
||||
link to it from the bug's URL field or in a comment on the bug.");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub validateFilename
|
||||
{
|
||||
defined $::FILE{'data'}
|
||||
|| DisplayError("You did not specify a file to attach.")
|
||||
&& exit;
|
||||
}
|
||||
|
||||
sub validateObsolete
|
||||
{
|
||||
# Make sure the attachment id is valid and the user has permissions to view
|
||||
# the bug to which it is attached.
|
||||
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
|
||||
detaint_natural($attachid)
|
||||
|| DisplayError("The attachment number of one of the attachments
|
||||
you wanted to obsolete is invalid.")
|
||||
&& exit;
|
||||
|
||||
SendSQL("SELECT bug_id, isobsolete, description
|
||||
FROM attachments WHERE attach_id = $attachid");
|
||||
|
||||
# Make sure the attachment exists in the database.
|
||||
MoreSQLData()
|
||||
|| DisplayError("Attachment #$attachid does not exist.")
|
||||
&& exit;
|
||||
|
||||
my ($bugid, $isobsolete, $description) = FetchSQLData();
|
||||
|
||||
if ($bugid != $::FORM{'bugid'})
|
||||
{
|
||||
$description = html_quote($description);
|
||||
DisplayError("Attachment #$attachid ($description) is attached
|
||||
to bug #$bugid, but you tried to flag it as obsolete while
|
||||
creating a new attachment to bug #$::FORM{'bugid'}.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( $isobsolete )
|
||||
{
|
||||
$description = html_quote($description);
|
||||
DisplayError("Attachment #$attachid ($description) is already obsolete.");
|
||||
exit;
|
||||
}
|
||||
|
||||
# Check that the user can modify this attachment
|
||||
validateCanEdit($attachid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Functions
|
||||
################################################################################
|
||||
|
||||
sub view
|
||||
{
|
||||
# Display an attachment.
|
||||
|
||||
# Retrieve the attachment content and its content type from the database.
|
||||
SendSQL("SELECT mimetype, thedata FROM attachments WHERE attach_id = $::FORM{'id'}");
|
||||
my ($contenttype, $thedata) = FetchSQLData();
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: $contenttype\n\n";
|
||||
|
||||
print $thedata;
|
||||
}
|
||||
|
||||
|
||||
sub viewall
|
||||
{
|
||||
# Display all attachments for a given bug in a series of IFRAMEs within one HTML page.
|
||||
|
||||
# Retrieve the attachments from the database and write them into an array
|
||||
# of hashes where each hash represents one attachment.
|
||||
SendSQL("SELECT attach_id, creation_ts, mimetype, description, ispatch, isobsolete
|
||||
FROM attachments WHERE bug_id = $::FORM{'bugid'} ORDER BY attach_id");
|
||||
my @attachments; # the attachments array
|
||||
while (MoreSQLData())
|
||||
{
|
||||
my %a; # the attachment hash
|
||||
($a{'attachid'}, $a{'date'}, $a{'contenttype'},
|
||||
$a{'description'}, $a{'ispatch'}, $a{'isobsolete'}) = FetchSQLData();
|
||||
|
||||
# Format the attachment's creation/modification date into something readable.
|
||||
if ($a{'date'} =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
|
||||
$a{'date'} = "$3/$4/$2 $5:$6";
|
||||
}
|
||||
|
||||
# Flag attachments as to whether or not they can be viewed (as opposed to
|
||||
# being downloaded). Currently I decide they are viewable if their MIME type
|
||||
# is either text/*, image/*, or application/vnd.mozilla.*.
|
||||
# !!! Yuck, what an ugly hack. Fix it!
|
||||
$a{'isviewable'} = ( $a{'contenttype'} =~ /^(text|image|application\/vnd\.mozilla\.)/ );
|
||||
|
||||
# Retrieve a list of status flags that have been set on the attachment.
|
||||
PushGlobalSQLState();
|
||||
SendSQL("SELECT name
|
||||
FROM attachstatuses, attachstatusdefs
|
||||
WHERE attach_id = $a{'attachid'}
|
||||
AND attachstatuses.statusid = attachstatusdefs.id
|
||||
ORDER BY sortkey");
|
||||
my @statuses;
|
||||
push(@statuses, FetchSQLData()) while MoreSQLData();
|
||||
$a{'statuses'} = \@statuses;
|
||||
PopGlobalSQLState();
|
||||
|
||||
# Add the hash representing the attachment to the array of attachments.
|
||||
push @attachments, \%a;
|
||||
}
|
||||
|
||||
# Retrieve the bug summary for displaying on screen.
|
||||
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
|
||||
my ($bugsummary) = FetchSQLData();
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
$vars->{'bugid'} = $::FORM{'bugid'};
|
||||
$vars->{'bugsummary'} = $bugsummary;
|
||||
$vars->{'attachments'} = \@attachments;
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/show-multiple.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
|
||||
sub enter
|
||||
{
|
||||
# Display a form for entering a new attachment.
|
||||
|
||||
# Retrieve the attachments the user can edit from the database and write
|
||||
# them into an array of hashes where each hash represents one attachment.
|
||||
my $canEdit = "";
|
||||
if (!UserInGroup($userid, "editbugs")) {
|
||||
$canEdit = "AND submitter_id = $userid";
|
||||
}
|
||||
SendSQL("SELECT attach_id, description
|
||||
FROM attachments
|
||||
WHERE bug_id = $::FORM{'bugid'}
|
||||
AND isobsolete = 0 $canEdit
|
||||
ORDER BY attach_id");
|
||||
my @attachments; # the attachments array
|
||||
while ( MoreSQLData() ) {
|
||||
my %a; # the attachment hash
|
||||
($a{'id'}, $a{'description'}) = FetchSQLData();
|
||||
|
||||
# Add the hash representing the attachment to the array of attachments.
|
||||
push @attachments, \%a;
|
||||
}
|
||||
|
||||
# Retrieve the bug summary for displaying on screen.
|
||||
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
|
||||
my ($bugsummary) = FetchSQLData();
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
$vars->{'bugid'} = $::FORM{'bugid'};
|
||||
$vars->{'bugsummary'} = $bugsummary;
|
||||
$vars->{'attachments'} = \@attachments;
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/create.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
|
||||
sub insert
|
||||
{
|
||||
# Insert a new attachment into the database.
|
||||
|
||||
# Escape characters in strings that will be used in SQL statements.
|
||||
my $filename = SqlQuote($::FILE{'data'}->{'filename'});
|
||||
my $description = SqlQuote($::FORM{'description'});
|
||||
my $contenttype = SqlQuote($::FORM{'contenttype'});
|
||||
my $thedata = SqlQuote($::FORM{'data'});
|
||||
|
||||
# Insert the attachment into the database.
|
||||
SendSQL("INSERT INTO attachments (bug_id, filename, description, mimetype, ispatch, submitter_id, thedata)
|
||||
VALUES ($::FORM{'bugid'}, $filename, $description, $contenttype, $::FORM{'ispatch'}, $userid, $thedata)");
|
||||
|
||||
# Retrieve the ID of the newly created attachment record.
|
||||
my $attachid = CurrId('attachments_attach_id_seq');
|
||||
|
||||
# Insert a comment about the new attachment into the database.
|
||||
my $comment = "Created an attachment (id=$attachid)\n$::FORM{'description'}\n";
|
||||
$comment .= ("\n" . $::FORM{'comment'}) if $::FORM{'comment'};
|
||||
|
||||
use Text::Wrap;
|
||||
$Text::Wrap::columns = 80;
|
||||
$Text::Wrap::huge = 'overflow';
|
||||
$comment = Text::Wrap::wrap('', '', $comment);
|
||||
|
||||
AppendComment($::FORM{'bugid'},
|
||||
$::COOKIE{"Bugzilla_login"},
|
||||
$comment);
|
||||
|
||||
# Make existing attachments obsolete.
|
||||
my $fieldid = GetFieldID('attachments.isobsolete');
|
||||
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
|
||||
SendSQL("UPDATE attachments SET isobsolete = 1 WHERE attach_id = $attachid");
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($::FORM{'bugid'}, $attachid, $userid, NOW(), $fieldid, '0', '1')");
|
||||
}
|
||||
|
||||
# Send mail to let people know the attachment has been created. Uses a
|
||||
# special syntax of the "open" and "exec" commands to capture the output of
|
||||
# "processmail", which "system" doesn't allow, without running the command
|
||||
# through a shell, which backticks (``) do.
|
||||
#system ("./processmail", $bugid , $userid);
|
||||
#my $mailresults = `./processmail $bugid $::userid`;
|
||||
my $mailresults = '';
|
||||
open(PMAIL, "-|") or exec('./processmail', $::FORM{'bugid'}, $::COOKIE{'Bugzilla_login'});
|
||||
$mailresults .= $_ while <PMAIL>;
|
||||
close(PMAIL);
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
$vars->{'bugid'} = $::FORM{'bugid'};
|
||||
$vars->{'attachid'} = $attachid;
|
||||
$vars->{'description'} = $description;
|
||||
$vars->{'mailresults'} = $mailresults;
|
||||
$vars->{'contenttypemethod'} = $::FORM{'contenttypemethod'};
|
||||
$vars->{'contenttype'} = $::FORM{'contenttype'};
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/created.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $::FORM{'bugid'}");
|
||||
}
|
||||
|
||||
|
||||
sub edit
|
||||
{
|
||||
# Edit an attachment record. Users with "editbugs" privileges, (or the
|
||||
# original attachment's submitter) can edit the attachment's description,
|
||||
# content type, ispatch and isobsolete flags, and statuses, and they can
|
||||
# also submit a comment that appears in the bug.
|
||||
# Users cannot edit the content of the attachment itself.
|
||||
|
||||
# Retrieve the attachment from the database.
|
||||
SendSQL("SELECT description, mimetype, bug_id, ispatch, isobsolete
|
||||
FROM attachments WHERE attach_id = $::FORM{'id'}");
|
||||
my ($description, $contenttype, $bugid, $ispatch, $isobsolete) = FetchSQLData();
|
||||
|
||||
# Flag attachment as to whether or not it can be viewed (as opposed to
|
||||
# being downloaded). Currently I decide it is viewable if its content
|
||||
# type is either text/.* or application/vnd.mozilla.*.
|
||||
# !!! Yuck, what an ugly hack. Fix it!
|
||||
my $isviewable = ( $contenttype =~ /^(text|image|application\/vnd\.mozilla\.)/ );
|
||||
|
||||
# Retrieve a list of status flags that have been set on the attachment.
|
||||
my %statuses;
|
||||
SendSQL("SELECT id, name
|
||||
FROM attachstatuses, attachstatusdefs
|
||||
WHERE attachstatuses.statusid = attachstatusdefs.id
|
||||
AND attach_id = $::FORM{'id'}");
|
||||
while ( my ($id, $name) = FetchSQLData() )
|
||||
{
|
||||
$statuses{$id} = $name;
|
||||
}
|
||||
|
||||
# Retrieve a list of statuses for this bug's product, and build an array
|
||||
# of hashes in which each hash is a status flag record.
|
||||
# ???: Move this into versioncache or its own routine?
|
||||
my @statusdefs;
|
||||
SendSQL("SELECT id, name
|
||||
FROM attachstatusdefs, bugs
|
||||
WHERE bug_id = $bugid
|
||||
AND attachstatusdefs.product = bugs.product
|
||||
ORDER BY sortkey");
|
||||
while ( MoreSQLData() )
|
||||
{
|
||||
my ($id, $name) = FetchSQLData();
|
||||
push @statusdefs, { 'id' => $id , 'name' => $name };
|
||||
}
|
||||
|
||||
# Retrieve a list of attachments for this bug as well as a summary of the bug
|
||||
# to use in a navigation bar across the top of the screen.
|
||||
SendSQL("SELECT attach_id FROM attachments WHERE bug_id = $bugid ORDER BY attach_id");
|
||||
my @bugattachments;
|
||||
push(@bugattachments, FetchSQLData()) while (MoreSQLData());
|
||||
SendSQL("SELECT short_desc FROM bugs WHERE bug_id = $bugid");
|
||||
my ($bugsummary) = FetchSQLData();
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
$vars->{'attachid'} = $::FORM{'id'};
|
||||
$vars->{'description'} = $description;
|
||||
$vars->{'contenttype'} = $contenttype;
|
||||
$vars->{'bugid'} = $bugid;
|
||||
$vars->{'bugsummary'} = $bugsummary;
|
||||
$vars->{'ispatch'} = $ispatch;
|
||||
$vars->{'isobsolete'} = $isobsolete;
|
||||
$vars->{'isviewable'} = $isviewable;
|
||||
$vars->{'statuses'} = \%statuses;
|
||||
$vars->{'statusdefs'} = \@statusdefs;
|
||||
$vars->{'attachments'} = \@bugattachments;
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/edit.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
|
||||
sub update
|
||||
{
|
||||
# Update an attachment record.
|
||||
|
||||
# Get the bug ID for the bug to which this attachment is attached.
|
||||
SendSQL("SELECT bug_id FROM attachments WHERE attach_id = $::FORM{'id'}");
|
||||
my $bugid = FetchSQLData()
|
||||
|| DisplayError("Cannot figure out bug number.")
|
||||
&& exit;
|
||||
|
||||
# Lock database tables in preparation for updating the attachment.
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("LOCK TABLES attachments WRITE , attachstatuses WRITE ,
|
||||
attachstatusdefs READ , fielddefs READ , bugs_activity WRITE");
|
||||
}
|
||||
|
||||
# Get a copy of the attachment record before we make changes
|
||||
# so we can record those changes in the activity table.
|
||||
SendSQL("SELECT description, mimetype, ispatch, isobsolete
|
||||
FROM attachments WHERE attach_id = $::FORM{'id'}");
|
||||
my ($olddescription, $oldcontenttype, $oldispatch, $oldisobsolete) = FetchSQLData();
|
||||
|
||||
# Get the list of old status flags.
|
||||
SendSQL("SELECT attachstatusdefs.name
|
||||
FROM attachments, attachstatuses, attachstatusdefs
|
||||
WHERE attachments.attach_id = $::FORM{'id'}
|
||||
AND attachments.attach_id = attachstatuses.attach_id
|
||||
AND attachstatuses.statusid = attachstatusdefs.id
|
||||
ORDER BY attachstatusdefs.sortkey
|
||||
");
|
||||
my @oldstatuses;
|
||||
while (MoreSQLData()) {
|
||||
push(@oldstatuses, FetchSQLData());
|
||||
}
|
||||
my $oldstatuslist = join(', ', @oldstatuses);
|
||||
|
||||
# Update the database with the new status flags.
|
||||
SendSQL("DELETE FROM attachstatuses WHERE attach_id = $::FORM{'id'}");
|
||||
foreach my $statusid (@{$::MFORM{'status'}})
|
||||
{
|
||||
SendSQL("INSERT INTO attachstatuses (attach_id, statusid) VALUES ($::FORM{'id'}, $statusid)");
|
||||
}
|
||||
|
||||
# Get the list of new status flags.
|
||||
SendSQL("SELECT attachstatusdefs.name
|
||||
FROM attachments, attachstatuses, attachstatusdefs
|
||||
WHERE attachments.attach_id = $::FORM{'id'}
|
||||
AND attachments.attach_id = attachstatuses.attach_id
|
||||
AND attachstatuses.statusid = attachstatusdefs.id
|
||||
ORDER BY attachstatusdefs.sortkey
|
||||
");
|
||||
my @newstatuses;
|
||||
while (MoreSQLData()) {
|
||||
push(@newstatuses, FetchSQLData());
|
||||
}
|
||||
my $newstatuslist = join(', ', @newstatuses);
|
||||
|
||||
# Quote the description and content type for use in the SQL UPDATE statement.
|
||||
my $quoteddescription = SqlQuote($::FORM{'description'});
|
||||
my $quotedcontenttype = SqlQuote($::FORM{'contenttype'});
|
||||
|
||||
# Update the attachment record in the database.
|
||||
# Sets the creation timestamp to itself to avoid it being updated automatically.
|
||||
SendSQL("UPDATE attachments
|
||||
SET description = $quoteddescription ,
|
||||
mimetype = $quotedcontenttype ,
|
||||
ispatch = $::FORM{'ispatch'} ,
|
||||
isobsolete = $::FORM{'isobsolete'} ,
|
||||
creation_ts = creation_ts
|
||||
WHERE attach_id = $::FORM{'id'}
|
||||
");
|
||||
|
||||
# Record changes in the activity table.
|
||||
if ($olddescription ne $::FORM{'description'}) {
|
||||
my $quotedolddescription = SqlQuote($olddescription);
|
||||
my $fieldid = GetFieldID('attachments.description');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedolddescription, $quoteddescription)");
|
||||
}
|
||||
if ($oldcontenttype ne $::FORM{'contenttype'}) {
|
||||
my $quotedoldcontenttype = SqlQuote($oldcontenttype);
|
||||
my $fieldid = GetFieldID('attachments.mimetype');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedoldcontenttype, $quotedcontenttype)");
|
||||
}
|
||||
if ($oldispatch ne $::FORM{'ispatch'}) {
|
||||
my $fieldid = GetFieldID('attachments.ispatch');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $oldispatch, $::FORM{'ispatch'})");
|
||||
}
|
||||
if ($oldisobsolete ne $::FORM{'isobsolete'}) {
|
||||
my $fieldid = GetFieldID('attachments.isobsolete');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $oldisobsolete, $::FORM{'isobsolete'})");
|
||||
}
|
||||
if ($oldstatuslist ne $newstatuslist) {
|
||||
my ($removed, $added) = DiffStrings($oldstatuslist, $newstatuslist);
|
||||
my $quotedremoved = SqlQuote($removed);
|
||||
my $quotedadded = SqlQuote($added);
|
||||
my $fieldid = GetFieldID('attachstatusdefs.name');
|
||||
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
|
||||
VALUES ($bugid, $::FORM{'id'}, $userid, NOW(), $fieldid, $quotedremoved, $quotedadded)");
|
||||
}
|
||||
|
||||
# Unlock all database tables now that we are finished updating the database.
|
||||
if ($::driver eq 'mysql') {
|
||||
SendSQL("UNLOCK TABLES");
|
||||
}
|
||||
|
||||
# If this installation has enabled the request manager, let the manager know
|
||||
# an attachment was updated so it can check for requests on that attachment
|
||||
# and fulfill them. The request manager allows users to request database
|
||||
# changes of other users and tracks the fulfillment of those requests. When
|
||||
# an attachment record is updated and the request manager is called, it will
|
||||
# fulfill those requests that were requested of the user performing the update
|
||||
# which are requests for the attachment being updated.
|
||||
#my $requests;
|
||||
#if (Param('userequestmanager'))
|
||||
#{
|
||||
# use Request;
|
||||
# # Specify the fieldnames that have been updated.
|
||||
# my @fieldnames = ('description', 'mimetype', 'status', 'ispatch', 'isobsolete');
|
||||
# # Fulfill pending requests.
|
||||
# $requests = Request::fulfillRequest('attachment', $::FORM{'id'}, @fieldnames);
|
||||
# $vars->{'requests'} = $requests;
|
||||
#}
|
||||
|
||||
# If the user submitted a comment while editing the attachment,
|
||||
# add the comment to the bug.
|
||||
if ( $::FORM{'comment'} )
|
||||
{
|
||||
use Text::Wrap;
|
||||
$Text::Wrap::columns = 80;
|
||||
$Text::Wrap::huge = 'wrap';
|
||||
|
||||
# Append a string to the comment to let users know that the comment came from
|
||||
# the "edit attachment" screen.
|
||||
my $comment = qq|(From update of attachment $::FORM{'id'})\n| . $::FORM{'comment'};
|
||||
|
||||
my $wrappedcomment = "";
|
||||
foreach my $line (split(/\r\n|\r|\n/, $comment))
|
||||
{
|
||||
if ( $line =~ /^>/ )
|
||||
{
|
||||
$wrappedcomment .= $line . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$wrappedcomment .= wrap('', '', $line) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Get the user's login name since the AppendComment function needs it.
|
||||
my $who = DBID_to_name($userid);
|
||||
|
||||
# Append the comment to the list of comments in the database.
|
||||
AppendComment($bugid, $who, $wrappedcomment);
|
||||
|
||||
}
|
||||
|
||||
# Send mail to let people know the bug has changed. Uses a special syntax
|
||||
# of the "open" and "exec" commands to capture the output of "processmail",
|
||||
# which "system" doesn't allow, without running the command through a shell,
|
||||
# which backticks (``) do.
|
||||
#system ("./processmail", $bugid , $userid);
|
||||
#my $mailresults = `./processmail $bugid $userid`;
|
||||
my $mailresults = '';
|
||||
open(PMAIL, "-|") or exec('./processmail', $bugid, DBID_to_name($userid));
|
||||
$mailresults .= $_ while <PMAIL>;
|
||||
close(PMAIL);
|
||||
|
||||
# Define the variables and functions that will be passed to the UI template.
|
||||
$vars->{'attachid'} = $::FORM{'id'};
|
||||
$vars->{'bugid'} = $bugid;
|
||||
$vars->{'mailresults'} = $mailresults;
|
||||
|
||||
# Return the appropriate HTTP response headers.
|
||||
print "Content-Type: text/html\n\n";
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("attachment/updated.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
366
mozilla/webtools/bugzilla/bug_form.pl
Normal file
366
mozilla/webtools/bugzilla/bug_form.pl
Normal file
@@ -0,0 +1,366 @@
|
||||
# -*- 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 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>
|
||||
# Dave Miller <justdave@syndicomm.com>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use RelationSet;
|
||||
|
||||
# Use the Attachment module to display attachments for the bug.
|
||||
use Attachment;
|
||||
|
||||
sub show_bug {
|
||||
# Shut up misguided -w warnings about "used only once". For some reason,
|
||||
# "use vars" chokes on me when I try it here.
|
||||
sub bug_form_pl_sillyness {
|
||||
my $zz;
|
||||
$zz = %::FORM;
|
||||
$zz = %::proddesc;
|
||||
$zz = %::prodmaxvotes;
|
||||
$zz = @::enterable_products;
|
||||
$zz = @::settable_resolution;
|
||||
$zz = $::unconfirmedstate;
|
||||
$zz = $::milestoneurl;
|
||||
$zz = $::template;
|
||||
$zz = $::vars;
|
||||
$zz = @::legal_priority;
|
||||
$zz = @::legal_platform;
|
||||
$zz = @::legal_severity;
|
||||
$zz = @::legal_bug_status;
|
||||
$zz = @::target_milestone;
|
||||
$zz = @::components;
|
||||
$zz = @::legal_keywords;
|
||||
$zz = @::versions;
|
||||
$zz = @::legal_opsys;
|
||||
}
|
||||
|
||||
# Use templates
|
||||
my $template = $::template;
|
||||
my $vars = $::vars;
|
||||
|
||||
$vars->{'GetBugLink'} = \&GetBugLink;
|
||||
$vars->{'quoteUrls'} = \"eUrls,
|
||||
$vars->{'lsearch'} = \&lsearch,
|
||||
$vars->{'header_done'} = (@_),
|
||||
|
||||
my $userid = quietly_check_login();
|
||||
|
||||
my $id = $::FORM{'id'};
|
||||
|
||||
if (!defined($id)) {
|
||||
$template->process("bug/choose.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
exit;
|
||||
}
|
||||
|
||||
my %user = %{$vars->{'user'}};
|
||||
my %bug;
|
||||
|
||||
# Populate the bug hash with the info we get directly from the DB.
|
||||
my $query = "
|
||||
SELECT
|
||||
bugs.bug_id,
|
||||
product,
|
||||
version,
|
||||
rep_platform,
|
||||
op_sys,
|
||||
bug_status,
|
||||
resolution,
|
||||
priority,
|
||||
bug_severity,
|
||||
component,
|
||||
assigned_to,
|
||||
reporter,
|
||||
bug_file_loc,
|
||||
short_desc,
|
||||
target_milestone,
|
||||
qa_contact,
|
||||
status_whiteboard, ";
|
||||
|
||||
if ($::driver eq 'mysql') {
|
||||
$query .= "
|
||||
date_format(creation_ts, '%Y-%m-%d %H:%i'),
|
||||
delta_ts, ";
|
||||
} elsif ($::driver eq 'Pg') {
|
||||
$query .= "
|
||||
TO_CHAR(creation_ts, 'YYYY-MM-DD HH24:MI:SS'),
|
||||
TO_CHAR(delta_ts, 'YYYYMMDDHH24MISS'), ";
|
||||
}
|
||||
|
||||
$query .= "
|
||||
SUM(votes.count)
|
||||
FROM
|
||||
bugs LEFT JOIN votes USING(bug_id)
|
||||
WHERE
|
||||
bugs.bug_id = $id
|
||||
GROUP BY
|
||||
bugs.bug_id,
|
||||
product,
|
||||
version,
|
||||
rep_platform,
|
||||
op_sys,
|
||||
bug_status,
|
||||
resolution,
|
||||
priority,
|
||||
bug_severity,
|
||||
component,
|
||||
assigned_to,
|
||||
reporter,
|
||||
bug_file_loc,
|
||||
short_desc,
|
||||
target_milestone,
|
||||
qa_contact,
|
||||
status_whiteboard,
|
||||
creation_ts,
|
||||
delta_ts ";
|
||||
|
||||
SendSQL($query);
|
||||
|
||||
my $value;
|
||||
my @row = FetchSQLData();
|
||||
foreach my $field ("bug_id", "product", "version", "rep_platform",
|
||||
"op_sys", "bug_status", "resolution", "priority",
|
||||
"bug_severity", "component", "assigned_to", "reporter",
|
||||
"bug_file_loc", "short_desc", "target_milestone",
|
||||
"qa_contact", "status_whiteboard", "creation_ts",
|
||||
"delta_ts", "votes")
|
||||
{
|
||||
$value = shift(@row);
|
||||
$bug{$field} = defined($value) ? $value : "";
|
||||
}
|
||||
|
||||
# General arrays of info about the database state
|
||||
GetVersionTable();
|
||||
|
||||
# Fiddle the product list.
|
||||
my $seen_curr_prod;
|
||||
my @prodlist;
|
||||
|
||||
foreach my $product (@::enterable_products) {
|
||||
if ($product eq $bug{'product'}) {
|
||||
# if it's the product the bug is already in, it's ALWAYS in
|
||||
# the popup, period, whether the user can see it or not, and
|
||||
# regardless of the disallownew setting.
|
||||
$seen_curr_prod = 1;
|
||||
push(@prodlist, $product);
|
||||
next;
|
||||
}
|
||||
|
||||
next if !CanSeeProduct($userid, $product);
|
||||
|
||||
push(@prodlist, $product);
|
||||
}
|
||||
|
||||
# The current product is part of the popup, even if new bugs are no longer
|
||||
# allowed for that product
|
||||
if (!$seen_curr_prod) {
|
||||
push (@prodlist, $bug{'product'});
|
||||
@prodlist = sort @prodlist;
|
||||
}
|
||||
|
||||
$vars->{'product'} = \@prodlist;
|
||||
$vars->{'rep_platform'} = \@::legal_platform;
|
||||
$vars->{'priority'} = \@::legal_priority;
|
||||
$vars->{'bug_severity'} = \@::legal_severity;
|
||||
$vars->{'op_sys'} = \@::legal_opsys;
|
||||
$vars->{'bug_status'} = \@::legal_bug_status;
|
||||
|
||||
# Hack - this array contains "" for some reason. See bug 106589.
|
||||
shift @::settable_resolution;
|
||||
$vars->{'resolution'} = \@::settable_resolution;
|
||||
|
||||
$vars->{'component_'} = $::components{$bug{'product'}};
|
||||
$vars->{'version'} = $::versions{$bug{'product'}};
|
||||
$vars->{'target_milestone'} = $::target_milestone{$bug{'product'}};
|
||||
$bug{'milestoneurl'} = $::milestoneurl{$bug{'product'}} ||
|
||||
"notargetmilestone.html";
|
||||
|
||||
$vars->{'use_votes'} = $::prodmaxvotes{$bug{'product'}};
|
||||
|
||||
# Add additional, calculated fields to the bug hash
|
||||
if (@::legal_keywords) {
|
||||
$vars->{'use_keywords'} = 1;
|
||||
|
||||
SendSQL("SELECT keyworddefs.name
|
||||
FROM keyworddefs, keywords
|
||||
WHERE keywords.bug_id = $id
|
||||
AND keyworddefs.id = keywords.keywordid
|
||||
ORDER BY keyworddefs.name");
|
||||
my @keywords;
|
||||
while (MoreSQLData()) {
|
||||
push(@keywords, FetchOneColumn());
|
||||
}
|
||||
|
||||
$bug{'keywords'} = \@keywords;
|
||||
}
|
||||
|
||||
# Attachments
|
||||
$bug{'attachments'} = Attachment::query($id);
|
||||
|
||||
# Dependencies
|
||||
my @list;
|
||||
SendSQL("SELECT dependson FROM dependencies WHERE
|
||||
blocked = $id ORDER BY dependson");
|
||||
while (MoreSQLData()) {
|
||||
my ($i) = FetchSQLData();
|
||||
push(@list, $i);
|
||||
}
|
||||
|
||||
$bug{'dependson'} = \@list;
|
||||
|
||||
my @list2;
|
||||
SendSQL("SELECT blocked FROM dependencies WHERE
|
||||
dependson = $id ORDER BY blocked");
|
||||
while (MoreSQLData()) {
|
||||
my ($i) = FetchSQLData();
|
||||
push(@list2, $i);
|
||||
}
|
||||
|
||||
$bug{'blocked'} = \@list2;
|
||||
|
||||
# Groups
|
||||
my @groups;
|
||||
my (%buggroups, %usergroups);
|
||||
|
||||
# Find out if this bug is private to any group
|
||||
SendSQL("SELECT group_id FROM bug_group_map WHERE bug_id = $id");
|
||||
while (my $group_id = FetchOneColumn()) {
|
||||
$buggroups{$group_id} = 1;
|
||||
}
|
||||
|
||||
# Get a list of active groups the user is in, subject to the above conditions
|
||||
if ($userid) {
|
||||
# NB - the number of groups is likely to be small - should we just select
|
||||
# everything, and weed manually? OTOH, the number of products is likely
|
||||
# to be small, too. This buggroup stuff needs to be rethought
|
||||
SendSQL("SELECT groups.group_id, groups.isactive " .
|
||||
"FROM user_group_map, " .
|
||||
"groups LEFT JOIN products ON groups.name = products.product " .
|
||||
"WHERE groups.group_id = user_group_map.group_id AND " .
|
||||
"user_group_map.user_id = $userid AND groups.isbuggroup != 0 AND " .
|
||||
"(groups.name = " . SqlQuote($bug{'product'}) . " OR " .
|
||||
"products.product IS NULL)");
|
||||
while (my $group_id = FetchOneColumn()) {
|
||||
$usergroups{$group_id} = 1;
|
||||
}
|
||||
|
||||
# Now get information about each group
|
||||
SendSQL("SELECT group_id, name, description " .
|
||||
"FROM groups " .
|
||||
# "WHERE group_id IN (" . join(',', @groups) . ") " .
|
||||
"ORDER BY description");
|
||||
while (MoreSQLData()) {
|
||||
my ($group_id, $name, $description) = FetchSQLData();
|
||||
my ($ison, $ingroup);
|
||||
|
||||
if ($buggroups{$group_id} ||
|
||||
($usergroups{$group_id} && (($name eq $bug{'product'}) ||
|
||||
(!defined $::proddesc{$name}))))
|
||||
{
|
||||
$user{'inallgroups'} &= $ingroup;
|
||||
|
||||
push (@groups, { "bit" => $group_id,
|
||||
"ison" => $buggroups{$group_id},
|
||||
"ingroup" => $usergroups{$group_id},
|
||||
"description" => $description });
|
||||
}
|
||||
}
|
||||
|
||||
# If the bug is restricted to a group, display checkboxes that allow
|
||||
# the user to set whether or not the reporter
|
||||
# and cc list can see the bug even if they are not members of all
|
||||
# groups to which the bug is restricted.
|
||||
if (%buggroups) {
|
||||
$bug{'inagroup'} = 1;
|
||||
|
||||
# Determine whether or not the bug is always accessible by the
|
||||
# reporter, QA contact, and/or users on the cc: list.
|
||||
SendSQL("SELECT reporter_accessible, cclist_accessible
|
||||
FROM bugs
|
||||
WHERE bug_id = $id
|
||||
");
|
||||
($bug{'reporter_accessible'},
|
||||
$bug{'cclist_accessible'}) = FetchSQLData();
|
||||
}
|
||||
}
|
||||
$vars->{'groups'} = \@groups;
|
||||
|
||||
my $movers = Param("movers");
|
||||
$user{'canmove'} = Param("move-enabled")
|
||||
&& (defined $::COOKIE{"Bugzilla_login"})
|
||||
&& ($::COOKIE{"Bugzilla_login"} =~ /\Q$movers\E/);
|
||||
|
||||
# User permissions
|
||||
|
||||
# In the below, if the person hasn't logged in ($::userid == 0), then
|
||||
# we treat them as if they can do anything. That's because we don't
|
||||
# know why they haven't logged in; it may just be because they don't
|
||||
# use cookies. Display everything as if they have all the permissions
|
||||
# in the world; their permissions will get checked when they log in
|
||||
# and actually try to make the change.
|
||||
$user{'canedit'} = $::userid == 0
|
||||
|| $::userid == $bug{'reporter'}
|
||||
|| $::userid == $bug{'qa_contact'}
|
||||
|| $::userid == $bug{'assigned_to'}
|
||||
|| UserInGroup($userid, "editbugs");
|
||||
$user{'canconfirm'} = ($::userid == 0) || UserInGroup($userid, "canconfirm");
|
||||
|
||||
# Bug states
|
||||
$bug{'isunconfirmed'} = ($bug{'bug_status'} eq $::unconfirmedstate);
|
||||
$bug{'isopened'} = IsOpenedState($bug{'bug_status'});
|
||||
|
||||
# People involved with the bug
|
||||
$bug{'assigned_to_email'} = DBID_to_name($bug{'assigned_to'});
|
||||
$bug{'assigned_to'} = DBID_to_real_or_loginname($bug{'assigned_to'});
|
||||
$bug{'reporter'} = DBID_to_real_or_loginname($bug{'reporter'});
|
||||
$bug{'qa_contact'} = $bug{'qa_contact'} > 0 ?
|
||||
DBID_to_name($bug{'qa_contact'}) : "";
|
||||
|
||||
my $ccset = new RelationSet;
|
||||
$ccset->mergeFromDB("SELECT who FROM cc WHERE bug_id=$id");
|
||||
|
||||
my @cc = $ccset->toArrayOfStrings();
|
||||
$bug{'cc'} = \@cc if $cc[0];
|
||||
|
||||
# Next bug in list (if there is one)
|
||||
my @bug_list;
|
||||
if ($::COOKIE{"BUGLIST"} && $id)
|
||||
{
|
||||
@bug_list = split(/:/, $::COOKIE{"BUGLIST"});
|
||||
}
|
||||
$vars->{'bug_list'} = \@bug_list;
|
||||
|
||||
$bug{'comments'} = GetComments($bug{'bug_id'});
|
||||
|
||||
# This is length in number of comments
|
||||
$bug{'longdesclength'} = scalar(@{$bug{'comments'}});
|
||||
|
||||
# Add the bug and user hashes to the variables
|
||||
$vars->{'bug'} = \%bug;
|
||||
$vars->{'user'} = \%user;
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
$template->process("bug/edit.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
}
|
||||
|
||||
1;
|
||||
206
mozilla/webtools/bugzilla/bug_status.html
Executable file
206
mozilla/webtools/bugzilla/bug_status.html
Executable file
@@ -0,0 +1,206 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
|
||||
<!--
|
||||
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):
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<head>
|
||||
<TITLE>A Bug's Life Cycle</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1 ALIGN=CENTER>A Bug's Life Cycle</h1>
|
||||
|
||||
The <B>status</B> and <B>resolution</B> field define and track the
|
||||
life cycle of a bug.
|
||||
|
||||
<a name="status"></a>
|
||||
<p>
|
||||
<TABLE BORDER=1 CELLPADDING=4>
|
||||
|
||||
<TR ALIGN=CENTER VALIGN=TOP>
|
||||
<TD WIDTH="50%"><H1>STATUS</H1> <TD><H1>RESOLUTION</H1>
|
||||
|
||||
<TR VALIGN=TOP>
|
||||
<TD>The <B>status</B> field indicates the general health of a bug. Only
|
||||
certain status transitions are allowed.
|
||||
<TD>The <b>resolution</b> field indicates what happened to this bug.
|
||||
|
||||
<TR VALIGN=TOP><TD>
|
||||
<DL><DT><B>
|
||||
<A HREF="confirmhelp.html">UNCONFIRMED</A></B>
|
||||
<DD> This bug has recently been added to the database. Nobody has
|
||||
validated that this bug is true. Users who have the "canconfirm"
|
||||
permission set may confirm this bug, changing its state to NEW.
|
||||
Or, it may be directly resolved and marked RESOLVED.
|
||||
<DT><B>NEW</B>
|
||||
<DD> This bug has recently been added to the assignee's list of bugs
|
||||
and must be processed. Bugs in this state may be accepted, and
|
||||
become <B>ASSIGNED</B>, passed on to someone else, and remain
|
||||
<B>NEW</B>, or resolved and marked <B>RESOLVED</B>.
|
||||
<DT><B>ASSIGNED</B>
|
||||
<DD> This bug is not yet resolved, but is assigned to the proper
|
||||
person. From here bugs can be given to another person and become
|
||||
<B>NEW</B>, or resolved and become <B>RESOLVED</B>.
|
||||
<DT><B>REOPENED</B>
|
||||
<DD>This bug was once resolved, but the resolution was deemed
|
||||
incorrect. For example, a <B>WORKSFORME</B> bug is
|
||||
<B>REOPENED</B> when more information shows up and the bug is now
|
||||
reproducible. From here bugs are either marked <B>ASSIGNED</B>
|
||||
or <B>RESOLVED</B>.
|
||||
</DL>
|
||||
<TD>
|
||||
<DL>
|
||||
<DD> No resolution yet. All bugs which are in one of these "open" states
|
||||
have the resolution set to blank. All other bugs
|
||||
will be marked with one of the following resolutions.
|
||||
</DL>
|
||||
|
||||
<TR VALIGN=TOP><TD>
|
||||
<DL>
|
||||
<DT><B>RESOLVED</B>
|
||||
<DD> A resolution has been taken, and it is awaiting verification by
|
||||
QA. From here bugs are either re-opened and become
|
||||
<B>REOPENED</B>, are marked <B>VERIFIED</B>, or are closed for good
|
||||
and marked <B>CLOSED</B>.
|
||||
<DT><B>VERIFIED</B>
|
||||
<DD> QA has looked at the bug and the resolution and agrees that the
|
||||
appropriate resolution has been taken. Bugs remain in this state
|
||||
until the product they were reported against actually ships, at
|
||||
which point they become <B>CLOSED</B>.
|
||||
<DT><B>CLOSED</B>
|
||||
<DD> The bug is considered dead, the resolution is correct. Any zombie
|
||||
bugs who choose to walk the earth again must do so by becoming
|
||||
<B>REOPENED</B>.
|
||||
</DL>
|
||||
|
||||
<TD>
|
||||
<DL>
|
||||
<DT><B>FIXED</B>
|
||||
<DD> A fix for this bug is checked into the tree and tested.
|
||||
<DT><B>INVALID</B>
|
||||
<DD> The problem described is not a bug
|
||||
<DT><B>WONTFIX</B>
|
||||
<DD> The problem described is a bug which will never be fixed.
|
||||
<DT><B>LATER</B>
|
||||
<DD> The problem described is a bug which will not be fixed in this
|
||||
version of the product.
|
||||
<DT><B>REMIND</B>
|
||||
<DD> The problem described is a bug which will probably not be fixed in this
|
||||
version of the product, but might still be.
|
||||
<DT><B>DUPLICATE</B>
|
||||
<DD> The problem is a duplicate of an existing bug. Marking a bug
|
||||
duplicate requires the bug# of the duplicating bug and will at
|
||||
least put that bug number in the description field.
|
||||
<DT><B>WORKSFORME</B>
|
||||
<DD> All attempts at reproducing this bug were futile, reading the
|
||||
code produces no clues as to why this behavior would occur. If
|
||||
more information appears later, please re-assign the bug, for
|
||||
now, file it.
|
||||
</DL>
|
||||
</TABLE>
|
||||
|
||||
<H1>Other Fields</H1>
|
||||
|
||||
<table border=1 cellpadding=4><tr><td>
|
||||
<h2><a name="severity">Severity</a></h2>
|
||||
|
||||
This field describes the impact of a bug.
|
||||
|
||||
<p>
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr><th>Blocker</th><td>Blocks development and/or testing work
|
||||
<tr><th>Critical</th><td>crashes, loss of data, severe memory leak
|
||||
<tr><th>Major</th><td>major loss of function
|
||||
<tr><th>Minor</th><td>minor loss of function, or other problem where easy workaround is present
|
||||
<tr><th>Trivial</th><td>cosmetic problem like misspelled words or misaligned text
|
||||
<tr><th>Enhancement</th><td>Request for enhancement
|
||||
</table>
|
||||
|
||||
</td><td>
|
||||
|
||||
<h2><a name="priority">Priority</a></h2>
|
||||
|
||||
This field describes the importance and order in which a bug should be
|
||||
fixed. This field is utilized by the programmers/engineers to
|
||||
prioritize their work to be done. The available priorities are:
|
||||
|
||||
<p>
|
||||
<p>
|
||||
|
||||
<table>
|
||||
<tr><th>P1</th><td>Most important
|
||||
<tr><th>P2</th><td>
|
||||
<tr><th>P3</th><td>
|
||||
<tr><th>P4</th><td>
|
||||
<tr><th>P5</th><td>Least important
|
||||
</table>
|
||||
</tr></table>
|
||||
|
||||
<h2><a name="rep_platform">Platform</a></h2>
|
||||
This is the hardware platform against which the bug was reported. Legal
|
||||
platforms include:
|
||||
|
||||
<UL>
|
||||
<LI> All (happens on all platform; cross-platform bug)
|
||||
<LI> Macintosh
|
||||
<LI> PC
|
||||
<LI> Sun
|
||||
<LI> HP
|
||||
</UL>
|
||||
|
||||
<b>Note:</b> Selecting the option "All" does not select bugs assigned against all platforms. It
|
||||
merely selects bugs that <b>occur</b> on all platforms.
|
||||
|
||||
<h2><a name="op_sys">Operating System</a></h2>
|
||||
This is the operating system against which the bug was reported. Legal
|
||||
operating systems include:
|
||||
|
||||
<UL>
|
||||
<LI> All (happens on all operating systems; cross-platform bug)
|
||||
<LI> Windows 95
|
||||
<LI> Mac System 8.0
|
||||
<LI> Linux
|
||||
</UL>
|
||||
|
||||
Note that the operating system implies the platform, but not always.
|
||||
For example, Linux can run on PC and Macintosh and others.
|
||||
|
||||
<h2><a name="assigned_to">Assigned To</a></h2>
|
||||
|
||||
This is the person in charge of resolving the bug. Every time this
|
||||
field changes, the status changes to <B>NEW</B> to make it easy to see
|
||||
which new bugs have appeared on a person's list.
|
||||
|
||||
The default status for queries is set to NEW, ASSIGNED and REOPENED. When
|
||||
searching for bugs that have been resolved or verified, remember to set the
|
||||
status field appropriately.
|
||||
|
||||
<hr>
|
||||
<!-- hhmts start -->
|
||||
Last modified: Sun Apr 14 12:51:23 EST 2002
|
||||
<!-- hhmts end -->
|
||||
</body> </html>
|
||||
1641
mozilla/webtools/bugzilla/buglist.cgi
Executable file
1641
mozilla/webtools/bugzilla/buglist.cgi
Executable file
File diff suppressed because it is too large
Load Diff
392
mozilla/webtools/bugzilla/bugwritinghelp.html
Normal file
392
mozilla/webtools/bugzilla/bugwritinghelp.html
Normal file
@@ -0,0 +1,392 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>Bug Writing Guidelines</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<h1>Bug Writing Guidelines</h1>
|
||||
</center>
|
||||
|
||||
<h3>Why You Should Read This</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>Simply put, the more effectively you report a bug, the more
|
||||
likely an engineer will actually fix it.</p>
|
||||
|
||||
<p>These guidelines are a general
|
||||
tutorial to teach novice and intermediate bug reporters how to compose effective bug reports. Not every sentence may precisely apply to
|
||||
your software project.</p>
|
||||
</blockquote>
|
||||
|
||||
<h3>How to Write a Useful Bug Report</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>Useful bug reports are ones that get bugs fixed. A useful bug
|
||||
report normally has two qualities:</p>
|
||||
|
||||
<ol>
|
||||
<li><b>Reproducible.</b> If an engineer can't see the bug herself to prove that it exists, she'll probably stamp your bug report "WORKSFORME" or "INVALID" and move on to the next bug. Every detail you can provide helps.<br>
|
||||
<br>
|
||||
</li>
|
||||
|
||||
<li><b>Specific.</b> The quicker the engineer can isolate the bug
|
||||
to a specific area, the more likely she'll expediently fix it.
|
||||
(If a programmer or tester has to decypher a bug, they may spend
|
||||
more time cursing the submitter than solving the problem.)
|
||||
<br>
|
||||
<br>
|
||||
[ <a href="#tips" name="Anchor">Tell Me More</a> ]
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>Let's say the application you're testing is a web browser. You
|
||||
crash at foo.com, and want to write up a bug report:</p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>BAD:</b> "My browser crashed. I think I was on www.foo.com. I play golf with Bill Gates, so you better fix this problem, or I'll report you to him. By the way, your Back icon looks like a squashed rodent. UGGGLY. And my grandmother's home page is all messed up in your browser. Thx 4 UR help."
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>GOOD:</b> "I crashed each time I went to www.foo.com, using
|
||||
the 2002-02-25 build on a Windows 2000 system. I also
|
||||
rebooted into Linux, and reproduced this problem using the 2002-02-24
|
||||
Linux build.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It again crashed each time upon drawing the Foo banner at the top
|
||||
of the page. I broke apart the page, and discovered that the
|
||||
following image link will crash the application reproducibly,
|
||||
unless you remove the "border=0" attribute:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<tt><IMG SRC="http://www.foo.com/images/topics/topicfoos.gif"
|
||||
width="34" height="44" border="0" alt="News"></tt>
|
||||
</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<h3>How to Enter your Useful Bug Report into Bugzilla:</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>Before you enter your bug, use Bugzilla's
|
||||
<a href="query.cgi">search page</a> to determine whether the defect you've discovered is a known, already-reported bug. If your bug is the 37th duplicate of a known issue, you're more likely to annoy the engineer. (Annoyed
|
||||
engineers fix fewer bugs.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Next, be sure to reproduce your bug using a recent
|
||||
build. Engineers tend to be most interested in problems affecting
|
||||
the code base that they're actively working on. After all, the bug you're reporting
|
||||
may already be fixed.
|
||||
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you've discovered a new bug using a current build, report it in
|
||||
Bugzilla:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>From your Bugzilla main page, choose
|
||||
"<a href="enter_bug.cgi">Enter a new bug</a>".</li>
|
||||
|
||||
<li>Select the product that you've found a bug in.</li>
|
||||
|
||||
<li>Enter your e-mail address, password, and press the "Login"
|
||||
button. (If you don't yet have a password, leave the password field empty,
|
||||
and press the "E-mail me a password" button instead.
|
||||
You'll quickly receive an e-mail message with your password.)</li>
|
||||
</ol>
|
||||
|
||||
<p>Now, fill out the form. Here's what it all means:</p>
|
||||
|
||||
<p><b>Where did you find the bug?</b></p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>Product: In which product did you find the bug?</b><br>
|
||||
You just specified this on the last page, so you can't edit it here.</p>
|
||||
|
||||
<p><b>Version: In which product version did you find the
|
||||
bug?</b><br>
|
||||
(If applicable)</p>
|
||||
|
||||
<p><b>Component: In which component does the bug exist?</b><br>
|
||||
Bugzilla requires that you select a component to enter a bug. (Not sure which to choose?
|
||||
Click on the Component link. You'll see a description of each component, to help you make the best choice.)</p>
|
||||
|
||||
<p><b>OS: On which Operating System (OS) did you find this bug?</b>
|
||||
(e.g. Linux, Windows 2000, Mac OS 9.)<br>
|
||||
If you know the bug happens on all OSs, choose 'All'. Otherwise,
|
||||
select the OS that you found the bug on, or "Other" if your OS
|
||||
isn't listed.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>How important is the bug?</b></p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>Severity: How damaging is the bug?</b><br>
|
||||
This item defaults to 'normal'. If you're not sure what severity your bug deserves, click on the Severity link.
|
||||
You'll see a description of each severity rating. <br>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Who will be following up on the bug?</b></p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>Assigned To: Which engineer should be responsible for fixing
|
||||
this bug?</b><br>
|
||||
Bugzilla will automatically assign the bug to a default engineer
|
||||
upon submitting a bug report. If you'd prefer to directly assign the bug to
|
||||
someone else, enter their e-mail address into this field. (To see the list of
|
||||
default engineers for each component, click on the Component
|
||||
link.)</p>
|
||||
|
||||
<p><b>Cc: Who else should receive e-mail updates on changes to this
|
||||
bug?</b><br>
|
||||
List the full e-mail addresses of other individuals who should
|
||||
receive an e-mail update upon every change to the bug report. You
|
||||
can enter as many e-mail addresses as you'd like, separated by spaces or commas, as long as those
|
||||
people have Bugzilla accounts.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>What else can you tell the engineer about the bug?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Summary:</b> <b>How would you describe the bug, in
|
||||
approximately 60 or fewer characters?</b><br>
|
||||
A good summary should <b>quickly and uniquely identify a bug
|
||||
report</b>. Otherwise, an engineer cannot meaningfully identify
|
||||
your bug by its summary, and will often fail to pay attention to
|
||||
your bug report when skimming through a 10 page bug list.<br>
|
||||
<br>
|
||||
A useful summary might be
|
||||
"<tt>PCMCIA install fails on Tosh Tecra 780DVD w/ 3c589C</tt>".
|
||||
"<tt>Software fails</tt>" or "<tt>install problem</tt>" would be
|
||||
examples of a bad summary.<br>
|
||||
<br>
|
||||
[ <a href="#summary">Tell Me More</a> ]<br>
|
||||
<br>
|
||||
<b>Description: </b><br>
|
||||
Please provide a detailed problem report in this field.
|
||||
Your bug's recipients will most likely expect the following information:</p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>Overview Description:</b> More detailed expansion of
|
||||
summary.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Drag-selecting any page crashes Mac builds in NSGetFactory
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Steps to Reproduce:</b> Minimized, easy-to-follow steps that will
|
||||
trigger the bug. Include any special setup steps.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
1) View any web page. (I used the default sample page,
|
||||
resource:/res/samples/test0.html)
|
||||
|
||||
2) Drag-select the page. (Specifically, while holding down
|
||||
the mouse button, drag the mouse pointer downwards from any
|
||||
point in the browser's content region to the bottom of the
|
||||
browser's content region.)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
<b>Actual Results:</b> What the application did after performing
|
||||
the above steps.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
The application crashed. Stack crawl appended below from MacsBug.
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Expected Results:</b> What the application should have done,
|
||||
were the bug not present.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
The window should scroll downwards. Scrolled content should be selected.
|
||||
(Or, at least, the application should not crash.)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Build Date & Platform:</b> Date and platform of the build
|
||||
that you first encountered the bug in.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Build 2002-03-15 on Mac OS 9.0
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Additional Builds and Platforms:</b> Whether or not the bug
|
||||
takes place on other platforms (or browsers, if applicable).</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
- Also Occurs On
|
||||
Mozilla (2002-03-15 build on Windows NT 4.0)
|
||||
|
||||
- Doesn't Occur On
|
||||
Mozilla (2002-03-15 build on Red Hat Linux; feature not supported)
|
||||
Internet Explorer 5.0 (shipping build on Windows NT 4.0)
|
||||
Netscape Communicator 4.5 (shipping build on Mac OS 9.0)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Additional Information:</b> Any other debugging information.
|
||||
For crashing bugs:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Win32:</b> if you receive a Dr. Watson error, please note
|
||||
the type of the crash, and the module that the application crashed
|
||||
in. (e.g. access violation in apprunner.exe)</li>
|
||||
|
||||
<li><b>Mac OS:</b> if you're running MacsBug, please provide the
|
||||
results of a <b>how</b> and an <b>sc</b>:</li>
|
||||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
*** MACSBUG STACK CRAWL OF CRASH (Mac OS)
|
||||
Calling chain using A6/R1 links
|
||||
Back chain ISA Caller
|
||||
00000000 PPC 0BA85E74
|
||||
03AEFD80 PPC 0B742248
|
||||
03AEFD30 PPC 0B50FDDC NSGetFactory+027FC
|
||||
PowerPC unmapped memory exception at 0B512BD0 NSGetFactory+055F0
|
||||
</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<p>You're done!<br>
|
||||
<br>
|
||||
After double-checking your entries for any possible errors, press
|
||||
the "Commit" button, and your bug report will now be in the
|
||||
Bugzilla database.<br>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
<h3>More Information on Writing Good Bugs</h3>
|
||||
|
||||
<blockquote>
|
||||
<p><b><a name="tips"></a> 1. General Tips for a Useful Bug
|
||||
Report</b>
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<b>Use an explicit structure, so your bug reports are easy to
|
||||
skim.</b> Bug report users often need immediate access to specific
|
||||
sections of your bug. If your Bugzilla installation supports the
|
||||
Bugzilla Helper, use it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Avoid cuteness if it costs clarity.</b> Nobody will be laughing
|
||||
at your funny bug title at 3:00 AM when they can't remember how to
|
||||
find your bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>One bug per report.</b> Completely different people typically
|
||||
fix, verify, and prioritize different bugs. If you mix a handful of
|
||||
bugs into a single report, the right people probably won't discover
|
||||
your bugs in a timely fashion, or at all. Certain bugs are also
|
||||
more important than others. It's impossible to prioritize a bug
|
||||
report when it contains four different issues, all of differing
|
||||
importance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>No bug is too trivial to report.</b> Unless you're reading the
|
||||
source code, you can't see actual software bugs, like a dangling
|
||||
pointer -- you'll see their visible manifestations, such as the
|
||||
segfault when the application finally crashes. Severe software
|
||||
problems can manifest themselves in superficially trivial ways.
|
||||
File them anyway.<br>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b><a name="summary"></a>2. How and Why to Write Good Bug Summaries</b>
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p><b>You want to make a good first impression on the bug
|
||||
recipient.</b> Just like a New York Times headline guides readers
|
||||
towards a relevant article from dozens of choices, will your bug summary
|
||||
suggest that your bug report is worth reading from dozens or hundreds of
|
||||
choices?
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Conversely, a vague bug summary like <tt>install problem</tt> forces anyone
|
||||
reviewing installation bugs to waste time opening up your bug to
|
||||
determine whether it matters.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Your bug will often be searched by its summary.</b> Just as
|
||||
you'd find web pages with Google by searching by keywords through
|
||||
intuition, so will other people locate your bugs. Descriptive bug
|
||||
summaries are naturally keyword-rich, and easier to find.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, you'll find a bug titled "<tt>Dragging icons from List View to
|
||||
gnome-terminal doesn't paste path</tt>" if you search on "List",
|
||||
"terminal", or "path". Those search keywords wouldn't have found a
|
||||
bug titled "<tt>Dragging icons
|
||||
doesn't paste</tt>".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Ask yourself, "Would someone understand my bug from just this
|
||||
summary?" If so, you've written a fine summary.
|
||||
</p>
|
||||
|
||||
<p><b>Don't write titles like these:</b></p>
|
||||
|
||||
<ol>
|
||||
<li>"Can't install" - Why can't you install? What happens when you
|
||||
try to install?</li>
|
||||
<li>"Severe Performance Problems" - ...and they occur when you do
|
||||
what?</li>
|
||||
<li>"back button does not work" - Ever? At all?</li>
|
||||
</ol>
|
||||
|
||||
<p><b>Good bug titles:</b></p>
|
||||
<ol>
|
||||
<li>"1.0 upgrade installation fails if Mozilla M18 package present"
|
||||
- Explains problem and the context.</li>
|
||||
<li>"RPM 4 installer crashes if launched on Red Hat 6.2 (RPM 3)
|
||||
system" - Explains what happens, and the context.</li>
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<p>(Written and maintained by
|
||||
<a href="http://www.prometheus-music.com/eli">Eli Goldberg</a>. Claudius
|
||||
Gayle, Gervase Markham, Peter Mock, Chris Pratt, Tom Schutter and Chris Yeh also
|
||||
contributed significant changes. Constructive
|
||||
<a href="mailto:eli@prometheus-music.com">suggestions</a> welcome.)</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
46
mozilla/webtools/bugzilla/bugzilla.dtd
Normal file
46
mozilla/webtools/bugzilla/bugzilla.dtd
Normal file
@@ -0,0 +1,46 @@
|
||||
<!ELEMENT bugzilla (bug+)>
|
||||
<!ATTLIST bugzilla
|
||||
version CDATA #REQUIRED
|
||||
urlbase CDATA #REQUIRED
|
||||
maintainer CDATA #REQUIRED
|
||||
exporter CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT bug (bug_id, (bug_status, product, priority, version, rep_platform, assigned_to, delta_ts, component, reporter, target_milestone?, bug_severity, creation_ts, qa_contact?, op_sys, resolution?, bug_file_loc?, short_desc?, keywords*, status_whiteboard?, dependson*, blocks*, cc*, long_desc*, attachment*)?)>
|
||||
<!ATTLIST bug
|
||||
error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
|
||||
>
|
||||
<!ELEMENT bug_id (#PCDATA)>
|
||||
<!ELEMENT exporter (#PCDATA)>
|
||||
<!ELEMENT urlbase (#PCDATA)>
|
||||
<!ELEMENT bug_status (#PCDATA)>
|
||||
<!ELEMENT product (#PCDATA)>
|
||||
<!ELEMENT priority (#PCDATA)>
|
||||
<!ELEMENT version (#PCDATA)>
|
||||
<!ELEMENT rep_platform (#PCDATA)>
|
||||
<!ELEMENT assigned_to (#PCDATA)>
|
||||
<!ELEMENT delta_ts (#PCDATA)>
|
||||
<!ELEMENT component (#PCDATA)>
|
||||
<!ELEMENT reporter (#PCDATA)>
|
||||
<!ELEMENT target_milestone (#PCDATA)>
|
||||
<!ELEMENT bug_severity (#PCDATA)>
|
||||
<!ELEMENT creation_ts (#PCDATA)>
|
||||
<!ELEMENT qa_contact (#PCDATA)>
|
||||
<!ELEMENT status_whiteboard (#PCDATA)>
|
||||
<!ELEMENT op_sys (#PCDATA)>
|
||||
<!ELEMENT resolution (#PCDATA)>
|
||||
<!ELEMENT bug_file_loc (#PCDATA)>
|
||||
<!ELEMENT short_desc (#PCDATA)>
|
||||
<!ELEMENT keywords (#PCDATA)>
|
||||
<!ELEMENT dependson (#PCDATA)>
|
||||
<!ELEMENT blocks (#PCDATA)>
|
||||
<!ELEMENT cc (#PCDATA)>
|
||||
<!ELEMENT long_desc (who, bug_when, thetext)>
|
||||
<!ELEMENT who (#PCDATA)>
|
||||
<!ELEMENT bug_when (#PCDATA)>
|
||||
<!ELEMENT thetext (#PCDATA)>
|
||||
<!ELEMENT attachment (attachid, date, desc, type?, data?)>
|
||||
<!ELEMENT attachid (#PCDATA)>
|
||||
<!ELEMENT date (#PCDATA)>
|
||||
<!ELEMENT desc (#PCDATA)>
|
||||
<!ELEMENT type (#PCDATA)>
|
||||
<!ELEMENT data (#PCDATA)>
|
||||
39
mozilla/webtools/bugzilla/changepassword.cgi
Executable file
39
mozilla/webtools/bugzilla/changepassword.cgi
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bonsaitools/bin/perl -wT
|
||||
# -*- 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 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>
|
||||
|
||||
use strict;
|
||||
|
||||
print q{Content-type: text/html
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Refresh"
|
||||
CONTENT="0; URL=userprefs.cgi">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
This URL is obsolete. Forwarding you to the correct one.
|
||||
<P>
|
||||
Going to <A HREF="userprefs.cgi">userprefs.cgi</A>
|
||||
<BR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
}
|
||||
3145
mozilla/webtools/bugzilla/checksetup.pl
Executable file
3145
mozilla/webtools/bugzilla/checksetup.pl
Executable file
File diff suppressed because it is too large
Load Diff
156
mozilla/webtools/bugzilla/colchange.cgi
Executable file
156
mozilla/webtools/bugzilla/colchange.cgi
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bonsaitools/bin/perl -wT
|
||||
# -*- 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 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>
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
use lib qw(.);
|
||||
|
||||
use vars qw(
|
||||
@legal_keywords
|
||||
$buffer
|
||||
$template
|
||||
$vars
|
||||
);
|
||||
|
||||
require "CGI.pl";
|
||||
|
||||
# Use the template toolkit (http://www.template-toolkit.org/) to generate
|
||||
# the user interface (HTML pages and mail messages) using templates in the
|
||||
# "template/" subdirectory.
|
||||
use Template;
|
||||
|
||||
# Create the global template object that processes templates and specify
|
||||
# configuration parameters that apply to all templates processed in this script.
|
||||
my $template = Template->new(
|
||||
{
|
||||
# Colon-separated list of directories containing templates.
|
||||
INCLUDE_PATH => "template/custom:template/default",
|
||||
# Allow templates to be specified with relative paths.
|
||||
RELATIVE => 1,
|
||||
PRE_CHOMP => 1,
|
||||
});
|
||||
|
||||
# Define the global variables and functions that will be passed to the UI
|
||||
# template. Individual functions add their own values to this hash before
|
||||
# sending them to the templates they process.
|
||||
my $vars =
|
||||
{
|
||||
# Function for retrieving global parameters.
|
||||
'Param' => \&Param,
|
||||
|
||||
# Function for processing global parameters that contain references
|
||||
# to other global parameters.
|
||||
'PerformSubsts' => \&PerformSubsts,
|
||||
|
||||
# Function to search an array for a value
|
||||
'lsearch' => \&lsearch,
|
||||
};
|
||||
|
||||
print "Content-type: text/html\n";
|
||||
|
||||
# The master list not only says what fields are possible, but what order
|
||||
# they get displayed in.
|
||||
|
||||
ConnectToDatabase();
|
||||
GetVersionTable();
|
||||
|
||||
my @masterlist = ("opendate", "changeddate", "severity", "priority",
|
||||
"platform", "owner", "reporter", "status", "resolution",
|
||||
"product", "component", "version", "os", "votes");
|
||||
|
||||
if (Param("usetargetmilestone")) {
|
||||
push(@masterlist, "target_milestone");
|
||||
}
|
||||
if (Param("useqacontact")) {
|
||||
push(@masterlist, "qa_contact");
|
||||
}
|
||||
if (Param("usestatuswhiteboard")) {
|
||||
push(@masterlist, "status_whiteboard");
|
||||
}
|
||||
if (@::legal_keywords) {
|
||||
push(@masterlist, "keywords");
|
||||
}
|
||||
|
||||
|
||||
push(@masterlist, ("summary", "summaryfull"));
|
||||
|
||||
$vars->{masterlist} = \@masterlist;
|
||||
|
||||
my @collist;
|
||||
if (defined $::FORM{'rememberedquery'}) {
|
||||
my $splitheader = 0;
|
||||
if (defined $::FORM{'resetit'}) {
|
||||
@collist = @::default_column_list;
|
||||
} else {
|
||||
foreach my $i (@masterlist) {
|
||||
if (defined $::FORM{"column_$i"}) {
|
||||
push @collist, $i;
|
||||
}
|
||||
}
|
||||
if (exists $::FORM{'splitheader'}) {
|
||||
$splitheader = $::FORM{'splitheader'};
|
||||
}
|
||||
}
|
||||
my $list = join(" ", @collist);
|
||||
my $urlbase = Param("urlbase");
|
||||
my $cookiepath = Param("cookiepath");
|
||||
print "Set-Cookie: COLUMNLIST=$list ; path=$cookiepath ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
print "Set-Cookie: SPLITHEADER=$::FORM{'splitheader'} ; path=$cookiepath ; expires=Sun, 30-Jun-2029 00:00:00 GMT\n";
|
||||
print "Refresh: 0; URL=buglist.cgi?$::FORM{'rememberedquery'}\n";
|
||||
print "\n";
|
||||
print "<META HTTP-EQUIV=Refresh CONTENT=\"1; URL=$urlbase"."buglist.cgi?$::FORM{'rememberedquery'}\">\n";
|
||||
print "<TITLE>What a hack.</TITLE>\n";
|
||||
PutHeader ("Change columns");
|
||||
print "Resubmitting your query with new columns...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (defined $::COOKIE{'COLUMNLIST'}) {
|
||||
@collist = split(/ /, $::COOKIE{'COLUMNLIST'});
|
||||
} else {
|
||||
@collist = @::default_column_list;
|
||||
}
|
||||
|
||||
$vars->{collist} = \@collist;
|
||||
|
||||
$vars->{splitheader} = 0;
|
||||
if ($::COOKIE{'SPLITHEADER'}) {
|
||||
$vars->{splitheader} = 1;
|
||||
}
|
||||
|
||||
my %desc = ();
|
||||
foreach my $i (@masterlist) {
|
||||
$desc{$i} = $i;
|
||||
}
|
||||
|
||||
$desc{'summary'} = "Summary (first 60 characters)";
|
||||
$desc{'summaryfull'} = "Full Summary";
|
||||
|
||||
$vars->{desc} = \%desc;
|
||||
$vars->{buffer} = $::buffer;
|
||||
|
||||
# Generate and return the UI (HTML page) from the appropriate template.
|
||||
print "Content-type: text/html\n\n";
|
||||
$template->process("list/change-columns.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
||||
202
mozilla/webtools/bugzilla/collectstats.pl
Executable file
202
mozilla/webtools/bugzilla/collectstats.pl
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bonsaitools/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 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>,
|
||||
# Harrison Page <harrison@netscape.com>
|
||||
# Gervase Markham <gerv@gerv.net>
|
||||
|
||||
# Run me out of cron at midnight to collect Bugzilla statistics.
|
||||
|
||||
|
||||
use AnyDBM_File;
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use vars @::legal_product;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
# tidy up after graphing module
|
||||
if (chdir("graphs")) {
|
||||
unlink <./*.gif>;
|
||||
unlink <./*.png>;
|
||||
chdir("..");
|
||||
}
|
||||
|
||||
ConnectToDatabase(1);
|
||||
GetVersionTable();
|
||||
|
||||
my @myproducts;
|
||||
push( @myproducts, "-All-", @::legal_product );
|
||||
|
||||
foreach (@myproducts) {
|
||||
my $dir = "data/mining";
|
||||
|
||||
&check_data_dir ($dir);
|
||||
&collect_stats ($dir, $_);
|
||||
}
|
||||
|
||||
&calculate_dupes();
|
||||
|
||||
sub check_data_dir {
|
||||
my $dir = shift;
|
||||
|
||||
if (! -d) {
|
||||
mkdir $dir, 0777;
|
||||
chmod 0777, $dir;
|
||||
}
|
||||
}
|
||||
|
||||
sub collect_stats {
|
||||
my $dir = shift;
|
||||
my $product = shift;
|
||||
my $when = localtime (time);
|
||||
|
||||
# NB: Need to mangle the product for the filename, but use the real
|
||||
# product name in the query
|
||||
my $file_product = $product;
|
||||
$file_product =~ s/\//-/gs;
|
||||
my $file = join '/', $dir, $file_product;
|
||||
my $exists = -f $file;
|
||||
|
||||
if (open DATA, ">>$file") {
|
||||
push my @row, &today;
|
||||
|
||||
foreach my $status ('NEW', 'ASSIGNED', 'REOPENED', 'UNCONFIRMED', 'RESOLVED', 'VERIFIED', 'CLOSED') {
|
||||
if( $product eq "-All-" ) {
|
||||
SendSQL("select count(bug_status) from bugs where bug_status='$status'");
|
||||
} else {
|
||||
SendSQL("select count(bug_status) from bugs where bug_status='$status' and product='$product'");
|
||||
}
|
||||
|
||||
push @row, FetchOneColumn();
|
||||
}
|
||||
|
||||
foreach my $resolution ('FIXED', 'INVALID', 'WONTFIX', 'LATER', 'REMIND', 'DUPLICATE', 'WORKSFORME', 'MOVED') {
|
||||
if( $product eq "-All-" ) {
|
||||
SendSQL("select count(resolution) from bugs where resolution='$resolution'");
|
||||
} else {
|
||||
SendSQL("select count(resolution) from bugs where resolution='$resolution' and product='$product'");
|
||||
}
|
||||
|
||||
push @row, FetchOneColumn();
|
||||
}
|
||||
|
||||
if (! $exists) {
|
||||
print DATA <<FIN;
|
||||
# Bugzilla Daily Bug Stats
|
||||
#
|
||||
# Do not edit me! This file is generated.
|
||||
#
|
||||
# fields: DATE|NEW|ASSIGNED|REOPENED|UNCONFIRMED|RESOLVED|VERIFIED|CLOSED|FIXED|INVALID|WONTFIX|LATER|REMIND|DUPLICATE|WORKSFORME|MOVED
|
||||
# Product: $product
|
||||
# Created: $when
|
||||
FIN
|
||||
}
|
||||
|
||||
print DATA (join '|', @row) . "\n";
|
||||
close DATA;
|
||||
} else {
|
||||
print "$0: $file, $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub calculate_dupes {
|
||||
SendSQL("SELECT * FROM duplicates");
|
||||
|
||||
my %dupes;
|
||||
my %count;
|
||||
my @row;
|
||||
my $key;
|
||||
my $changed = 1;
|
||||
|
||||
my $today = &today_dash;
|
||||
|
||||
# Save % count here in a date-named file
|
||||
# so we can read it back in to do changed counters
|
||||
# First, delete it if it exists, so we don't add to the contents of an old file
|
||||
if (my @files = <data/duplicates/dupes$today*>) {
|
||||
unlink @files;
|
||||
}
|
||||
|
||||
dbmopen(%count, "data/duplicates/dupes$today", 0644) || die "Can't open DBM dupes file: $!";
|
||||
|
||||
# Create a hash with key "a bug number", value "bug which that bug is a
|
||||
# direct dupe of" - straight from the duplicates table.
|
||||
while (@row = FetchSQLData()) {
|
||||
my $dupe_of = shift @row;
|
||||
my $dupe = shift @row;
|
||||
$dupes{$dupe} = $dupe_of;
|
||||
}
|
||||
|
||||
# Total up the number of bugs which are dupes of a given bug
|
||||
# count will then have key = "bug number",
|
||||
# value = "number of immediate dupes of that bug".
|
||||
foreach $key (keys(%dupes))
|
||||
{
|
||||
my $dupe_of = $dupes{$key};
|
||||
|
||||
if (!defined($count{$dupe_of})) {
|
||||
$count{$dupe_of} = 0;
|
||||
}
|
||||
|
||||
$count{$dupe_of}++;
|
||||
}
|
||||
|
||||
# Now we collapse the dupe tree by iterating over %count until
|
||||
# there is no further change.
|
||||
while ($changed == 1)
|
||||
{
|
||||
$changed = 0;
|
||||
foreach $key (keys(%count)) {
|
||||
# if this bug is actually itself a dupe, and has a count...
|
||||
if (defined($dupes{$key}) && $count{$key} > 0) {
|
||||
# add that count onto the bug it is a dupe of,
|
||||
# and zero the count; the check is to avoid
|
||||
# loops
|
||||
if ($count{$dupes{$key}} != 0) {
|
||||
$count{$dupes{$key}} += $count{$key};
|
||||
$count{$key} = 0;
|
||||
$changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Remove the values for which the count is zero
|
||||
foreach $key (keys(%count))
|
||||
{
|
||||
if ($count{$key} == 0) {
|
||||
delete $count{$key};
|
||||
}
|
||||
}
|
||||
|
||||
dbmclose(%count);
|
||||
}
|
||||
|
||||
sub today {
|
||||
my ($dom, $mon, $year) = (localtime(time))[3, 4, 5];
|
||||
return sprintf "%04d%02d%02d", 1900 + $year, ++$mon, $dom;
|
||||
}
|
||||
|
||||
sub today_dash {
|
||||
my ($dom, $mon, $year) = (localtime(time))[3, 4, 5];
|
||||
return sprintf "%04d-%02d-%02d", 1900 + $year, ++$mon, $dom;
|
||||
}
|
||||
|
||||
168
mozilla/webtools/bugzilla/confirmhelp.html
Normal file
168
mozilla/webtools/bugzilla/confirmhelp.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html><head>
|
||||
|
||||
<!--
|
||||
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) 2000 Netscape Communications Corporation. All
|
||||
Rights Reserved.
|
||||
|
||||
Contributor(s): Terry Weissman <terry@mozilla.org>
|
||||
-->
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Understanding the UNCONFIRMED state, and other recent changes</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Understanding the UNCONFIRMED state, and other recent changes</h1>
|
||||
|
||||
<p>
|
||||
[This document is aimed primarily at people who have used Bugzilla
|
||||
before the UNCONFIRMED state was implemented. It might be helpful for
|
||||
newer users as well.]
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
New bugs in some products will now show up in a new state,
|
||||
UNCONFIRMED. This means that we have nobody has confirmed that the
|
||||
bug is real. Very busy engineers will probably generally ignore
|
||||
UNCONFIRMED that have been assigned to them, until they have been
|
||||
confirmed in one way or another. (Engineers with more time will
|
||||
hopefully glance over their UNCONFIRMED bugs regularly.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="bug_status.html">page describing bug fields</a> has been
|
||||
updated to include UNCONFIRMED.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are two basic ways that a bug can become confirmed (and enter
|
||||
the NEW) state.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> A user with the appropriate permissions (see below for more on
|
||||
permissions) decides that the bug is a valid one, and confirms
|
||||
it. We hope to gather a small army of responsible volunteers
|
||||
to regularly go through bugs for us.</li>
|
||||
<li> The bug gathers a certain number of votes. <b>Any</b> valid Bugzilla user may vote for
|
||||
bugs (each user gets a certain number of bugs); any UNCONFIRMED bug which
|
||||
gets enough votes becomes automatically confirmed, and enters the NEW state.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
One implication of this is that it is worth your time to search the
|
||||
bug system for duplicates of your bug to vote on them, before
|
||||
submitting your own bug. If we can spread around knowledge of this
|
||||
fact, it ought to help cut down the number of duplicate bugs in the
|
||||
system.
|
||||
</p>
|
||||
|
||||
<h2>Permissions.</h2>
|
||||
|
||||
<p>
|
||||
Users now have a certain set of permissions. To see your permissions,
|
||||
check out the
|
||||
<a href="userprefs.cgi?bank=permissions">user preferences</a> page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have the "Can confirm a bug" permission, then you will be able
|
||||
to move UNCONFIRMED bugs into the NEW state.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have the "Can edit all aspects of any bug" permission, then you
|
||||
can tweak anything about any bug. If not, you may only edit those
|
||||
bugs that you have submitted, or that you have assigned to you (or
|
||||
qa-assigned to you). However, anyone may add a comment to any bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some people (initially, the initial owners and initial qa-contacts for
|
||||
components in the system) have the ability to give the above two
|
||||
permissions to other people. So, if you really feel that you ought to
|
||||
have one of these permissions, a good person to ask (via private
|
||||
email, please!) is the person who is assigned a relevant bug.
|
||||
</p>
|
||||
|
||||
<h2>Other details.</h2>
|
||||
|
||||
<p>
|
||||
An initial stab was taken to decide who would be given which of the
|
||||
above permissions. This was determined by some simple heurstics of
|
||||
who was assigned bugs, and who the default owners of bugs were, and a
|
||||
look at people who seem to have submitted several bugs that appear to
|
||||
have been interesting and valid. Inevitably, we have failed to give
|
||||
someone the permissions they deserve. Please don't take it
|
||||
personally; just bear with us as we shake out the new system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
People with one of the two bits above can easily confirm their own
|
||||
bugs, so bugs they submit will actually start out in the NEW state.
|
||||
They can override this when submitting a bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
People can ACCEPT or RESOLVE a bug assigned to them, even if they
|
||||
aren't allowed to confirm it. However, the system remembers, and if
|
||||
the bug gets REOPENED or reassigned to someone else, it will revert
|
||||
back to the UNCONFIRMED state. If the bug has ever been confirmed,
|
||||
then REOPENing or reassigning will cause it to go to the NEW or
|
||||
REOPENED state.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that only some products support the UNCONFIRMED state. In other
|
||||
products, all new bugs will automatically start in the NEW state.
|
||||
</p>
|
||||
|
||||
<h2>Things still to be done.</h2>
|
||||
|
||||
<p>
|
||||
There probably ought to be a way to get a bug back into the
|
||||
UNCONFIRMED state, but there isn't yet.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a person has submitted several bugs that get confirmed, then this
|
||||
is probably a person who understands the system well, and deserves the
|
||||
"Can confirm a bug" permission. This kind of person should be
|
||||
detected and promoted automatically.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There should also be a way to automatically promote people to get the
|
||||
"Can edit all aspects of any bug" permission.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The "enter a new bug" page needs to be revamped with easy ways for new
|
||||
people to educate themselves on the benefit of searching for a bug
|
||||
like the one they're about to submit and voting on it, rather than
|
||||
adding a new useless duplicate.
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<!-- hhmts start -->
|
||||
Last modified: Sun Apr 14 12:55:14 EST 2002
|
||||
<!-- hhmts end -->
|
||||
</p>
|
||||
</body> </html>
|
||||
79
mozilla/webtools/bugzilla/contrib/BugzillaEmail.pm
Normal file
79
mozilla/webtools/bugzilla/contrib/BugzillaEmail.pm
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- 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.
|
||||
#
|
||||
# This code is based on code found in bug_email.pl from the bugzilla
|
||||
# email tracker. Initial contributors are ::
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
# Gregor Fischer <fischer@suse.de>
|
||||
# Klaas Freitag <freitag@suse.de>
|
||||
# Seth Landsman <seth@dworkin.net>
|
||||
|
||||
# The purpose of this module is to abstract out a bunch of the code
|
||||
# that is central to email interfaces to bugzilla and its database
|
||||
|
||||
# Contributor : Seth Landsman <seth@dworkin.net>
|
||||
|
||||
# Initial checkin : 03/15/00 (SML)
|
||||
# findUser() function moved from bug_email.pl to here
|
||||
|
||||
push @INC, "../."; # this script now lives in contrib
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
my $EMAIL_TRANSFORM_NONE = "email_transform_none";
|
||||
my $EMAIL_TRANSFORM_BASE_DOMAIN = "email_transform_base_domain";
|
||||
my $EMAIL_TRANSFORM_NAME_ONLY = "email_transform_name_only";
|
||||
|
||||
# change to do incoming email address fuzzy matching
|
||||
my $email_transform = $EMAIL_TRANSFORM_NAME_ONLY;
|
||||
|
||||
# findUser()
|
||||
# This function takes an email address and returns the user email.
|
||||
# matching is sloppy based on the $email_transform parameter
|
||||
sub findUser($) {
|
||||
my ($address) = @_;
|
||||
# if $email_transform is $EMAIL_TRANSFORM_NONE, return the address, otherwise, return undef
|
||||
if ($email_transform eq $EMAIL_TRANSFORM_NONE) {
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name = \'$address\';";
|
||||
SendSQL($stmt);
|
||||
my $found_address = FetchOneColumn();
|
||||
return $found_address;
|
||||
} elsif ($email_transform eq $EMAIL_TRANSFORM_BASE_DOMAIN) {
|
||||
my ($username) = ($address =~ /(.+)@/);
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
|
||||
SendSQL($stmt);
|
||||
|
||||
my $domain;
|
||||
my $found = undef;
|
||||
my $found_address;
|
||||
my $new_address = undef;
|
||||
while ((!$found) && ($found_address = FetchOneColumn())) {
|
||||
($domain) = ($found_address =~ /.+@(.+)/);
|
||||
if ($address =~ /$domain/) {
|
||||
$found = 1;
|
||||
$new_address = $found_address;
|
||||
}
|
||||
}
|
||||
return $new_address;
|
||||
} elsif ($email_transform eq $EMAIL_TRANSFORM_NAME_ONLY) {
|
||||
my ($username) = ($address =~ /(.+)@/);
|
||||
my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
|
||||
SendSQL($stmt);
|
||||
my $found_address = FetchOneColumn();
|
||||
return $found_address;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
22
mozilla/webtools/bugzilla/contrib/README
Normal file
22
mozilla/webtools/bugzilla/contrib/README
Normal file
@@ -0,0 +1,22 @@
|
||||
This directory contains contributed software related to Bugzilla.
|
||||
Things in here have not necessarily been tested or tried by anyone
|
||||
except the original contributor, so tred carefully. But it may still
|
||||
be useful to you.
|
||||
|
||||
This directory includes:
|
||||
|
||||
mysqld-watcher.pl -- This script can be installed as a frequent cron
|
||||
job to clean up stalled/dead queries.
|
||||
gnats2bz.pl -- A perl script to help import bugs from a GNATS
|
||||
database into a Bugzilla database. Contributed by
|
||||
Tom Schutter <tom@platte.com>
|
||||
|
||||
bug_email.pl -- A perl script that can receive email containing
|
||||
bug reports (email-interface). Contributed by
|
||||
Klaas Freitag <freitag@SuSE.de>
|
||||
|
||||
README.Mailif -- Readme describing the mail interface.
|
||||
bugmail_help.html -- User help page for the mail interface.
|
||||
|
||||
yp_nomail.sh -- Script you can run via cron that regularly updates
|
||||
the nomail file for terminated employees
|
||||
80
mozilla/webtools/bugzilla/contrib/README.Mailif
Normal file
80
mozilla/webtools/bugzilla/contrib/README.Mailif
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
The Bugzilla Mail interface
|
||||
===========================
|
||||
|
||||
(UPDATE 03/14/00 to better reflect reality by SML)
|
||||
|
||||
The Bugzilla Mail interface allows to submit bugs to Bugzilla by email.
|
||||
|
||||
The Mail Interface Contribution consists of three files:
|
||||
README.Mailif - this readme.
|
||||
bug_email.pl - the script
|
||||
bugmail_help.html - a user help html site
|
||||
|
||||
Installation:
|
||||
|
||||
Next is to add a user who receives the bugmails, e. g. bugmail. Create a
|
||||
mail account and a home directory for the user.
|
||||
|
||||
The mailinterface script bug_email.pl needs to get the mail through stdin.
|
||||
I use procmail for that, with the following line in the .procmailrc:
|
||||
|
||||
BUGZILLA_HOME=/usr/local/httpd/htdocs/bugzilla
|
||||
:0 c
|
||||
|(cd $BUGZILLA_HOME/contrib; ./bug_email.pl)
|
||||
|
||||
This defines the Bugzilla directory as the variable BUGZILLA_HOME and passes
|
||||
all incoming mail to the script after cd'ing into the bugzilla home.
|
||||
|
||||
In some cases, it is necessary to alter the headers of incoming email. The
|
||||
additional line to procmail :
|
||||
|
||||
:0 fhw
|
||||
| formail -I "From " -a "From "
|
||||
|
||||
fixes many problems.
|
||||
|
||||
See bugzilla.procmailrc for a sample procmailrc that works for me (SML) and
|
||||
also deals with bugzilla_email_append.pl
|
||||
|
||||
Customation:
|
||||
|
||||
There are some values inside the script which need to be customized for your
|
||||
needs:
|
||||
|
||||
1. In sub-routine Reply (search 'sub Reply':
|
||||
there is the line
|
||||
print MAIL "From: Bugzilla Mailinterface<yourmail\@here.com>\n";
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
Fill in your correct mail here. That will make it easy for people to reply
|
||||
to the mail.
|
||||
|
||||
2. check, if your sendmail resides in /usr/sbin/sendmail, change the path if neccessary.
|
||||
Search the script after 'default' - you find some default-Settings for bug
|
||||
reports, which are used, if the sender did not send a field for it. The defaults
|
||||
should be checked and changed.
|
||||
|
||||
Thats hopefully all, we will come up with any configuration file or something.
|
||||
|
||||
|
||||
If your mail works, your script will insert mails from now on.
|
||||
|
||||
The mailinterface supports two commandline switches:
|
||||
|
||||
There are two command line switches :
|
||||
|
||||
-t: Testmode
|
||||
The mailinterface does not really insert the bug into the database, but
|
||||
writes some debug output to stdout and writes the mail into the file
|
||||
bug_email_test.log in the data-dir.
|
||||
|
||||
-r: restricted mode
|
||||
All lines before the first line with a keyword character are skipped.
|
||||
In not restricted, default mode, these lines are added to the long
|
||||
description of the bug.
|
||||
|
||||
|
||||
02/2000 - Klaas Freitag, SuSE GmbH <freitag@suse.de>
|
||||
03/2000 - Seth M. Landsman <seth@cs.brandeis.edu>
|
||||
bug_email.pl now lives out of bugzilla/contrib
|
||||
added line about formail
|
||||
1283
mozilla/webtools/bugzilla/contrib/bug_email.pl
Executable file
1283
mozilla/webtools/bugzilla/contrib/bug_email.pl
Executable file
File diff suppressed because it is too large
Load Diff
223
mozilla/webtools/bugzilla/contrib/bugmail_help.html
Normal file
223
mozilla/webtools/bugzilla/contrib/bugmail_help.html
Normal file
@@ -0,0 +1,223 @@
|
||||
<HTML>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<!--
|
||||
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.
|
||||
|
||||
Contributor(s): Klaas Freitag <Freitag@SuSE.de>
|
||||
-->
|
||||
|
||||
<HEAD> <TITLE>Bugzilla Mail Interface</TITLE> </HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
<CENTER><H1>The Bugzilla Mail Interface</H1>
|
||||
Contributor: <A HREF="mailto:freitag@suse.de">Klaas Freitag</A>, SuSE GmbH
|
||||
</CENTER>
|
||||
<P>
|
||||
The bugzilla Mail interface allows the registered bugzilla users to submit bugs by
|
||||
sending email with a bug description. This is usefull for people, who do not work
|
||||
inhouse and want to submitt bugs to the bugzilla system.
|
||||
<p>
|
||||
|
||||
|
||||
I know, show me the <A HREF="#examplemail">example-mail !</A>
|
||||
|
||||
|
||||
<H2>What do you need to do to submitt a bug by mail ?</H2>
|
||||
You need to send a email in the described format to the bugmail-user of the
|
||||
bugzilla-system. This is <A HREF="mailto:our_bugzilla@xyz.com">yourbugzilla@here.com</A>
|
||||
|
||||
You receive a reply mail with the new bug-ID if your request was ok.
|
||||
If not, you get a mail with
|
||||
some help on the bugmail system and a specific analysis of your request.
|
||||
<P>
|
||||
Please dont refuse to send one or two wrong mails, you will get all the information
|
||||
you need in the replies, and <I>only</I> in the mail replies. The information on this
|
||||
page, concerning available products, versions and so on, is not dynamicly generated and
|
||||
may be old therefore.
|
||||
|
||||
<H1>The Mail Format</H1>
|
||||
The bugmail needs a special format , which consists of some keywords and suitable
|
||||
values for them and a description text. Note that the keyword block needs to be
|
||||
above of the description text.
|
||||
|
||||
<H2>Keywords</H2>
|
||||
You need to tell bugzilla some properties of the bugs. This is done by keywords, which
|
||||
start on a new line with a @, followed by the keyword and and equal-sign, followed by a
|
||||
hopefully valid value.
|
||||
|
||||
|
||||
<TABLE BORDER=4 FRAME=box CELLSPACING="5" width=95%> <COLGROUP> <col width="2*">
|
||||
<col width="5*"> <col width="1*"> </COLGROUP>
|
||||
<TR>
|
||||
<TH>Keyword</TH>
|
||||
<TH>Value description</TH>
|
||||
<TH>required and default value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@product</TD>
|
||||
<TD>The product which has a bug</TD>
|
||||
<TD>yes. <br> This is the most important information. Many other
|
||||
fields depend on the product.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@component</TD>
|
||||
<TD>the desired component which is affected by the bug</TD>
|
||||
<TD>yes. <br> As the @product, this is a very important
|
||||
field.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@version</TD>
|
||||
<TD>The version of the product</TD>
|
||||
<TD>yes. <br>See @product and @component</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@short_desc</TD>
|
||||
<TD>A summary of your bug report</TD>
|
||||
<TD>yes. <br>This summary of the error you want to report
|
||||
describes what happen. You may skip the long description,
|
||||
but not this summary.<br>
|
||||
<b>Note:</b>The short description may be given in the mail subject
|
||||
instead of using the keyword !</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@rep_platform</TD>
|
||||
<TD>The desired platform</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>All</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@bug_severity</TD>
|
||||
<TD>The severity of the bug</TD>
|
||||
<TD>no. <br> If you dont give a value, this field is set to
|
||||
<I>normal</I></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@priority</TD>
|
||||
<TD>The priority of the bug</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>P3</I></TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@op_sys</TD>
|
||||
<TD>The operating system</TD>
|
||||
<TD>no.<br>If you dont give a value, this field is set to <I>Linux</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@assigned_to</TD>
|
||||
<TD>The one to whom the bug is assigned to</TD>
|
||||
<TD>no. <br>There is an initial owner for every product/version/component.
|
||||
He owns the bug by default. The initial owner can only be found if
|
||||
product, version and component are valid.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@bug_file_loc</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@status_whiteboard</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@target_milestone</TD>
|
||||
<TD>?</TD>
|
||||
<TD>no.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@groupset</TD>
|
||||
<TD>rules the visibility of the bug.</TD>
|
||||
<TD>no.<br>This value defaults to the smallest of the available groups,
|
||||
which is <I>readInternal</I>.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>@qa_contact</TD>
|
||||
<TD>the quality manager for the product</TD>
|
||||
<TD>no.<br>This value can be retrieved from product, component and
|
||||
version</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
<H2>Valid values</H2>
|
||||
Give string values for the most keys above. Some keywords require special values:<br>
|
||||
<ol>
|
||||
<li>E-Mail adresses: If you want to set the qa-contact, specify a email-adress for @qa_contact. The email must be known by bugzilla of course.</li>
|
||||
<li>Listvalues: Most of the values have to be one of a list of valid values. Try by sending
|
||||
a mail and read the reply. Skip fields if you dont get help for them unless you dont know
|
||||
which values you may choose.</li>
|
||||
<li>free Text: The descriptions may be free text. </li>
|
||||
<li>Special: The field groupset may be specified in different in three different kinds:
|
||||
<ol>
|
||||
<li> A plain numeric way, which is one usually huge number, e. g. <I>65536</I></li>
|
||||
<li> a string with added numbers e.g. <I>65536+131072</I></li>
|
||||
<li> a string list, e.g. <I>ReadInternal, ReadBeta </I></li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
|
||||
But most of them need <b>valid</b> values.
|
||||
<p>
|
||||
Sorry, you will not find lists of valid products, components and the other stuff
|
||||
here. Send a mail to with any text, and you will get a list of valid keywords in the reply.
|
||||
|
||||
<p>
|
||||
Some of the values must be choosen from a list:<br>
|
||||
<ol>
|
||||
<li>bug_severity: blocker, critical, major, normal, minor, trivial, enhancement</li>
|
||||
<li>op_sys: Linux </li>
|
||||
<li>priority: P1, P2, P3, P4, P5</li>
|
||||
<li>rep_platform: All, i386, AXP, i686, Other</li></ol>
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
After you have specified the required keywords and maybe some other value, you may
|
||||
describe your bug. You dont need a keyword for starting your bug description. All
|
||||
text which follows the keyword block is handled as long description of the bug.
|
||||
<p>
|
||||
|
||||
The bugmail interface is able to find required information by itself. E.g. if you specify
|
||||
a product which has exactly one component, this component will be found by the interface
|
||||
automatically.
|
||||
|
||||
<H1>Attachments</H1>
|
||||
|
||||
The mail interface is able to cope with MIME-attachments.
|
||||
People could for example add a logfile as a mail attachment, and it will appear in
|
||||
bugzilla as attachment. A comment for the attachment should be added, it will describe
|
||||
the attachment in bugzilla.
|
||||
|
||||
<H1><A NAME="examplemail">Example Mail</A></H1>
|
||||
|
||||
See the example of the mail <b>body</b> (Dont forget to specify the short description
|
||||
in the mail subject):<hr><pre>
|
||||
|
||||
@product = Bugzilla
|
||||
@component = general
|
||||
@version = All
|
||||
@groupset = ReadWorld ReadPartners
|
||||
@op_sys = Linux
|
||||
@priority = P3
|
||||
@rep_platform = i386
|
||||
|
||||
|
||||
This is the description of the bug I found. It is not neccessary to start
|
||||
it with a keyword.
|
||||
|
||||
Note: The short_description is neccessary and may be given with the keyword
|
||||
@short_description or will be retrieved from the mail subject.
|
||||
|
||||
|
||||
</pre><hr>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
30
mozilla/webtools/bugzilla/contrib/bugzilla.procmailrc
Normal file
30
mozilla/webtools/bugzilla/contrib/bugzilla.procmailrc
Normal file
@@ -0,0 +1,30 @@
|
||||
:0 fhw
|
||||
| formail -I "From " -a "From "
|
||||
|
||||
BUGZILLA_HOME=/home/bugzilla/WEB/bugzilla/contrib
|
||||
|
||||
:0
|
||||
* ^Subject: .*\[Bug .*\]
|
||||
RESULT=|(cd $BUGZILLA_HOME && ./bugzilla_email_append.pl)
|
||||
|
||||
|
||||
# Feed mail to stdin of bug_email.pl
|
||||
:0 Ec
|
||||
#* !^Subject: .*[Bug .*]
|
||||
RESULT=|(cd $BUGZILLA_HOME && ./bug_email.pl )
|
||||
|
||||
# write result to a logfile
|
||||
:0 c
|
||||
|echo `date '+%d.%m.%y %H:%M: '` $RESULT >> $HOME/bug_email.log
|
||||
|
||||
|
||||
:0 c
|
||||
|echo "----------------------------------" >> $HOME/bug_email.log
|
||||
|
||||
:0 c
|
||||
$HOME/bug_email.log
|
||||
|
||||
# Move mail to the inbox
|
||||
:0
|
||||
$HOME/Mail/INBOX
|
||||
|
||||
189
mozilla/webtools/bugzilla/contrib/bugzilla_email_append.pl
Executable file
189
mozilla/webtools/bugzilla/contrib/bugzilla_email_append.pl
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/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 purpose of this script is to take an email message, which
|
||||
# specifies a bugid and append it to the bug as part of the longdesc
|
||||
# table
|
||||
|
||||
# Contributor : Seth M. Landsman <seth@dworkin.net>
|
||||
|
||||
# 03/15/00 : Initial version by SML
|
||||
# 03/15/00 : processmail gets called
|
||||
|
||||
# Email subject must be of format :
|
||||
# .* Bug ### .*
|
||||
# replying to a typical bugzilla email should be valid
|
||||
|
||||
# TODO :
|
||||
# 1. better way to get the body text (I don't know what dump_entity() is
|
||||
# actually doing
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use MIME::Parser;
|
||||
|
||||
push @INC, "../."; # this script lives in contrib
|
||||
require "globals.pl";
|
||||
require "BugzillaEmail.pm";
|
||||
|
||||
# Create a new MIME parser:
|
||||
my $parser = new MIME::Parser;
|
||||
|
||||
my $Comment = "";
|
||||
|
||||
# Create and set the output directory:
|
||||
# FIXME: There should be a $BUGZILLA_HOME variable (SML)
|
||||
(-d "../data/mimedump-tmp") or mkdir "../data/mimedump-tmp",0755 or die "mkdir: $!";
|
||||
(-w "../data/mimedump-tmp") or die "can't write to directory";
|
||||
|
||||
$parser->output_dir("../data/mimedump-tmp");
|
||||
|
||||
# Read the MIME message:
|
||||
my $entity = $parser->read(\*STDIN) or die "couldn't parse MIME stream";
|
||||
$entity->remove_sig(10); # Removes the signature in the last 10 lines
|
||||
|
||||
# Getting values from parsed mail
|
||||
my $Sender = $entity->get( 'From' );
|
||||
$Sender ||= $entity->get( 'Reply-To' );
|
||||
my $Message_ID = $entity->get( 'Message-Id' );
|
||||
|
||||
die (" *** Cant find Sender-adress in sent mail ! ***\n" ) unless defined( $Sender );
|
||||
chomp( $Sender );
|
||||
chomp( $Message_ID );
|
||||
|
||||
print "Dealing with the sender $Sender\n";
|
||||
|
||||
ConnectToDatabase();
|
||||
|
||||
my $SenderShort = $Sender;
|
||||
$SenderShort =~ s/^.*?([a-zA-Z0-9_.-]+?\@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+).*$/$1/;
|
||||
|
||||
$SenderShort = findUser($SenderShort);
|
||||
|
||||
print "SenderShort is $SenderShort\n";
|
||||
if (!defined($SenderShort)) {
|
||||
$SenderShort = $Sender;
|
||||
$SenderShort =~ s/^.*?([a-zA-Z0-9_.-]+?\@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+).*$/$1/;
|
||||
}
|
||||
print "The sendershort is now $SenderShort\n";
|
||||
|
||||
if (!defined($SenderShort)) {
|
||||
DealWithError("No such user $SenderShort exists.");
|
||||
}
|
||||
|
||||
my $Subject = $entity->get('Subject');
|
||||
print "The subject is $Subject\n";
|
||||
|
||||
my ($bugid) = ($Subject =~ /\[Bug ([\d]+)\]/);
|
||||
print "The bugid is $bugid\n";
|
||||
|
||||
# make sure the bug exists
|
||||
|
||||
SendSQL("SELECT bug_id FROM bugs WHERE bug_id = $bugid;");
|
||||
my $found_id = FetchOneColumn();
|
||||
print "Did we find the bug? $found_id-\n";
|
||||
if (!defined($found_id)) {
|
||||
DealWithError("Bug $bugid does not exist");
|
||||
}
|
||||
|
||||
# get the user id
|
||||
SendSQL("SELECT userid FROM profiles WHERE login_name = \'$SenderShort\';");
|
||||
my $userid = FetchOneColumn();
|
||||
if (!defined($userid)) {
|
||||
DealWithError("Userid not found for $SenderShort");
|
||||
}
|
||||
|
||||
# parse out the text of the message
|
||||
dump_entity($entity);
|
||||
|
||||
# Get rid of the bug id
|
||||
$Subject =~ s/\[Bug [\d]+\]//;
|
||||
#my $Comment = "This is only a test ...";
|
||||
my $Body = "Subject: " . $Subject . "\n" . $Comment;
|
||||
|
||||
# shove it in the table
|
||||
my $long_desc_query = "INSERT INTO longdescs SET bug_id=$found_id, who=$userid, bug_when=NOW(), thetext=" . SqlQuote($Body) . ";";
|
||||
SendSQL($long_desc_query);
|
||||
|
||||
system("cd .. ; ./processmail $found_id '$SenderShort'");
|
||||
|
||||
sub DealWithError {
|
||||
my ($reason) = @_;
|
||||
print $reason . "\n";
|
||||
}
|
||||
|
||||
# Yanking this wholesale from bug_email, 'cause I know this works. I'll
|
||||
# figure out what it really does later
|
||||
#------------------------------
|
||||
#
|
||||
# dump_entity ENTITY, NAME
|
||||
#
|
||||
# Recursive routine for parsing a mime coded mail.
|
||||
# One mail may contain more than one mime blocks, which need to be
|
||||
# handled. Therefore, this function is called recursively.
|
||||
#
|
||||
# It gets the for bugzilla important information from the mailbody and
|
||||
# stores them into the global attachment-list @attachments. The attachment-list
|
||||
# is needed in storeAttachments.
|
||||
#
|
||||
sub dump_entity {
|
||||
my ($entity, $name) = @_;
|
||||
defined($name) or $name = "'anonymous'";
|
||||
my $IO;
|
||||
|
||||
|
||||
# Output the body:
|
||||
my @parts = $entity->parts;
|
||||
if (@parts) { # multipart...
|
||||
my $i;
|
||||
foreach $i (0 .. $#parts) { # dump each part...
|
||||
dump_entity($parts[$i], ("$name, part ".(1+$i)));
|
||||
}
|
||||
} else { # single part...
|
||||
|
||||
# Get MIME type, and display accordingly...
|
||||
my $msg_part = $entity->head->get( 'Content-Disposition' );
|
||||
|
||||
$msg_part ||= "";
|
||||
|
||||
my ($type, $subtype) = split('/', $entity->head->mime_type);
|
||||
my $body = $entity->bodyhandle;
|
||||
my ($data, $on_disk );
|
||||
|
||||
if( $msg_part =~ /^attachment/ ) {
|
||||
# Attached File
|
||||
my $des = $entity->head->get('Content-Description');
|
||||
$des ||= "";
|
||||
|
||||
if( defined( $body->path )) { # Data is on disk
|
||||
$on_disk = 1;
|
||||
$data = $body->path;
|
||||
|
||||
} else { # Data is in core
|
||||
$on_disk = 0;
|
||||
$data = $body->as_string;
|
||||
}
|
||||
# push ( @attachments, [ $data, $entity->head->mime_type, $on_disk, $des ] );
|
||||
} else {
|
||||
# Real Message
|
||||
if ($type =~ /^(text|message)$/) { # text: display it...
|
||||
if ($IO = $body->open("r")) {
|
||||
$Comment .= $_ while (defined($_ = $IO->getline));
|
||||
$IO->close;
|
||||
} else { # d'oh!
|
||||
print "$0: couldn't find/open '$name': $!";
|
||||
}
|
||||
} else { print "Oooops - no Body !\n"; }
|
||||
}
|
||||
}
|
||||
}
|
||||
94
mozilla/webtools/bugzilla/contrib/cmdline/buglist
Executable file
94
mozilla/webtools/bugzilla/contrib/cmdline/buglist
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
# 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
|
||||
# Andreas Franke <afranke@ags.uni-sb.de>.
|
||||
# Corporation. Portions created by Andreas Franke are
|
||||
# Copyright (C) 2001 Andreas Franke. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
conf="`dirname $0`/query.conf"
|
||||
|
||||
query="http://bugzilla.mozilla.org/buglist.cgi?cmd=doit"
|
||||
defaultcolumnlist="severity priority platform status resolution target_milestone status_whiteboard keywords summaryfull"
|
||||
|
||||
chart=0
|
||||
and=0
|
||||
while test "$1" != ""; do
|
||||
arg=$1
|
||||
arg_len=`expr length ${arg}`
|
||||
if test `expr substr "${arg}" 1 2` == "--"; then
|
||||
eq_pos=`expr match ${arg} '--.*='`
|
||||
if test "${eq_pos}" == "0"; then
|
||||
echo 'Missing value for long option '"${arg}"' ("=" not found)' 1>&2
|
||||
exit 1;
|
||||
fi
|
||||
# extract option name
|
||||
let name_len=${eq_pos}-3
|
||||
name=`expr substr ${arg} 3 ${name_len}`
|
||||
# extract option value
|
||||
let val_start=${eq_pos}+1
|
||||
let val_len=${arg_len}-${eq_pos}
|
||||
val=`expr substr ${arg} ${val_start} ${val_len}`
|
||||
elif test `expr substr ${arg} 1 1` == "-" &&
|
||||
test "`expr substr ${arg} 2 1`" != ""; then
|
||||
# extract
|
||||
name=`expr substr ${arg} 2 1`
|
||||
let val_len=${arg_len}-2
|
||||
val=`expr substr ${arg} 3 ${val_len}`
|
||||
else
|
||||
name="default"
|
||||
val="${arg}"
|
||||
#echo "Unrecognized option ${arg}" 1>&2
|
||||
#exit 1
|
||||
fi
|
||||
|
||||
# find field and comparison type for option ${name}
|
||||
field=`grep '"'${name}'"' ${conf} | awk '{printf $1}'`
|
||||
type=`grep '"'${name}'"' ${conf} | awk '{printf $2}'`
|
||||
if test "${field}" == "" || test "${type}" == ""; then
|
||||
echo "Field name & comparison type not found for option ${name}." 1>&2
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
or=0
|
||||
while test "${val}" != ""; do
|
||||
comma_idx=`expr index ${val} ,`
|
||||
if test ${comma_idx} == "0"; then
|
||||
val1="${val}"
|
||||
val=""
|
||||
else
|
||||
let val1_len=${comma_idx}-1
|
||||
val1=`expr substr ${val} 1 ${val1_len}`
|
||||
val_len=`expr length ${val}`
|
||||
let rest_start=${comma_idx}+1
|
||||
let rest_len=${val_len}-${comma_idx}
|
||||
val=`expr substr ${val} ${rest_start} ${rest_len}`
|
||||
fi
|
||||
query="${query}&field${chart}-${and}-${or}=${field}"
|
||||
query="${query}&type${chart}-${and}-${or}=${type}"
|
||||
query="${query}&value${chart}-${and}-${or}=${val1}"
|
||||
#echo "----- ${name} : ${field} : ${type} : ${val1} -----" 1>&2
|
||||
let or=${or}+1
|
||||
done
|
||||
let chart=${chart}+1
|
||||
shift
|
||||
done
|
||||
|
||||
outputfile="/dev/stdout"
|
||||
#outputfile="buglist.html"
|
||||
#\rm -f ${outputfile}
|
||||
wget -q -O ${outputfile} --header="Cookie: COLUMNLIST=${COLUMNLIST-${defaultcolumnlist}}" "${query}"
|
||||
|
||||
31
mozilla/webtools/bugzilla/contrib/cmdline/bugs
Executable file
31
mozilla/webtools/bugzilla/contrib/cmdline/bugs
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
# 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
|
||||
# Andreas Franke <afranke@ags.uni-sb.de>.
|
||||
# Corporation. Portions created by Andreas Franke are
|
||||
# Copyright (C) 2001 Andreas Franke. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
buglist="`dirname $0`/buglist"
|
||||
htmlfile="`dirname $0`/buglist.html"
|
||||
|
||||
${buglist} "$@" 2>&1 1>${htmlfile}
|
||||
if test ${?} == "0"; then
|
||||
echo `grep 'TR VALIGN=TOP ALIGN=LEFT CLASS=' ${htmlfile} | sed -e 's/<TR.*id=//' | sed -e 's/".*//'` | sed -e 's/ /\,/g'
|
||||
else
|
||||
cat ${htmlfile} 1>&2
|
||||
exit 1
|
||||
fi
|
||||
49
mozilla/webtools/bugzilla/contrib/cmdline/query.conf
Normal file
49
mozilla/webtools/bugzilla/contrib/cmdline/query.conf
Normal file
@@ -0,0 +1,49 @@
|
||||
# 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
|
||||
# Andreas Franke <afranke@ags.uni-sb.de>.
|
||||
# Corporation. Portions created by Andreas Franke are
|
||||
# Copyright (C) 2001 Andreas Franke. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
#
|
||||
# This is `query.conf', the config file for `buglist'.
|
||||
#
|
||||
# Columns: 1: field_name, 2: comparison_type, 3: cmd-line options
|
||||
#
|
||||
bug_status substring "s","status"
|
||||
resolution substring "r","resolution"
|
||||
rep_platform substring "p","platform"
|
||||
op_sys substring "o","os","opsys"
|
||||
priority substring "p","priority"
|
||||
bug_severity substring "S","severity"
|
||||
assigned_to substring "A","O","owner","assignedto"
|
||||
reporter substring "R","reporter"
|
||||
qa_contact substring "Q","qa","qacontact"
|
||||
cc substring "C","cc"
|
||||
product substring "product"
|
||||
version substring "V","version"
|
||||
component substring "c","component"
|
||||
target_milestone substring "M","milestone"
|
||||
short_desc substring "default","summary"
|
||||
longdesc substring "d","description","longdesc"
|
||||
bug_file_loc substring "u","url"
|
||||
status_whiteboard substring "w","whiteboard"
|
||||
keywords substring "k","K","keywords"
|
||||
attachments.description substring "attachdesc"
|
||||
attachments.thedata substring "attachdata"
|
||||
attachments.mimetype substring "attachmime"
|
||||
dependson substring # bug 30823
|
||||
blocked substring # bug 30823
|
||||
40
mozilla/webtools/bugzilla/contrib/cvs-update.sh
Normal file
40
mozilla/webtools/bugzilla/contrib/cvs-update.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# 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): Dawn Endico <endico@mozilla.org>
|
||||
|
||||
|
||||
# Keep a record of all cvs updates made from a given directory.
|
||||
#
|
||||
# Later, if changes need to be backed out, look at the log file
|
||||
# and run the cvs command with the date that you want to back
|
||||
# out to. (Probably the second to last entry).
|
||||
|
||||
#DATE=`date +%e/%m/%Y\ %k:%M:%S\ %Z`
|
||||
DATE=`date`
|
||||
COMMAND="cvs update -d -P -D"
|
||||
echo $COMMAND \"$DATE\" >> cvs-update.log
|
||||
$COMMAND "$DATE"
|
||||
|
||||
|
||||
# sample log file
|
||||
#cvs update -P -D "11/04/2000 20:22:08 PDT"
|
||||
#cvs update -P -D "11/05/2000 20:22:22 PDT"
|
||||
#cvs update -P -D "11/07/2000 20:26:29 PDT"
|
||||
#cvs update -P -D "11/08/2000 20:27:10 PDT"
|
||||
1069
mozilla/webtools/bugzilla/contrib/gnats2bz.pl
Executable file
1069
mozilla/webtools/bugzilla/contrib/gnats2bz.pl
Executable file
File diff suppressed because it is too large
Load Diff
303
mozilla/webtools/bugzilla/contrib/jb2bz.py
Executable file
303
mozilla/webtools/bugzilla/contrib/jb2bz.py
Executable file
@@ -0,0 +1,303 @@
|
||||
#!/usr/local/bin/python
|
||||
# -*- mode: python -*-
|
||||
|
||||
"""
|
||||
jb2bz.py - a nonce script to import bugs from JitterBug to Bugzilla
|
||||
Written by Tom Emerson, tree@basistech.com
|
||||
|
||||
This script is provided in the hopes that it will be useful. No
|
||||
rights reserved. No guarantees expressed or implied. Use at your own
|
||||
risk. May be dangerous if swallowed. If it doesn't work for you, don't
|
||||
blame me. It did what I needed it to do.
|
||||
|
||||
This code requires a recent version of Andy Dustman's MySQLdb interface,
|
||||
|
||||
http://sourceforge.net/projects/mysql-python
|
||||
|
||||
Share and enjoy.
|
||||
"""
|
||||
|
||||
import rfc822, mimetools, multifile, mimetypes
|
||||
import sys, re, glob, StringIO, os, stat, time
|
||||
import MySQLdb, getopt
|
||||
|
||||
# mimetypes doesn't include everything we might encounter, yet.
|
||||
if not mimetypes.types_map.has_key('.doc'):
|
||||
mimetypes.types_map['.doc'] = 'application/msword'
|
||||
|
||||
if not mimetypes.encodings_map.has_key('.bz2'):
|
||||
mimetypes.encodings_map['.bz2'] = "bzip2"
|
||||
|
||||
bug_status='NEW'
|
||||
component="default"
|
||||
version=""
|
||||
product="" # this is required, the rest of these are defaulted as above
|
||||
|
||||
"""
|
||||
Each bug in JitterBug is stored as a text file named by the bug number.
|
||||
Additions to the bug are indicated by suffixes to this:
|
||||
|
||||
<bug>
|
||||
<bug>.followup.*
|
||||
<bug>.reply.*
|
||||
<bug>.notes
|
||||
|
||||
The dates on the files represent the respective dates they were created/added.
|
||||
|
||||
All <bug>s and <bug>.reply.*s include RFC 822 mail headers. These could include
|
||||
MIME file attachments as well that would need to be extracted.
|
||||
|
||||
There are other additions to the file names, such as
|
||||
|
||||
<bug>.notify
|
||||
|
||||
which are ignored.
|
||||
|
||||
Bugs in JitterBug are organized into directories. At Basis we used the following
|
||||
naming conventions:
|
||||
|
||||
<product>-bugs Open bugs
|
||||
<product>-requests Open Feature Requests
|
||||
<product>-resolved Bugs/Features marked fixed by engineering, but not verified
|
||||
<product>-verified Resolved defects that have been verified by QA
|
||||
|
||||
where <product> is either:
|
||||
|
||||
<product-name>
|
||||
|
||||
or
|
||||
|
||||
<product-name>-<version>
|
||||
"""
|
||||
|
||||
def process_notes_file(current, fname):
|
||||
try:
|
||||
new_note = {}
|
||||
notes = open(fname, "r")
|
||||
s = os.fstat(notes.fileno())
|
||||
|
||||
new_note['text'] = notes.read()
|
||||
new_note['timestamp'] = time.gmtime(s[stat.ST_MTIME])
|
||||
|
||||
notes.close()
|
||||
|
||||
current['notes'].append(new_note)
|
||||
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
def process_reply_file(current, fname):
|
||||
new_note = {}
|
||||
reply = open(fname, "r")
|
||||
msg = rfc822.Message(reply)
|
||||
new_note['text'] = "%s\n%s" % (msg['From'], msg.fp.read())
|
||||
new_note['timestamp'] = rfc822.parsedate_tz(msg['Date'])
|
||||
current["notes"].append(new_note)
|
||||
|
||||
def add_notes(current):
|
||||
"""Add any notes that have been recorded for the current bug."""
|
||||
process_notes_file(current, "%d.notes" % current['number'])
|
||||
|
||||
for f in glob.glob("%d.reply.*" % current['number']):
|
||||
process_reply_file(current, f)
|
||||
|
||||
for f in glob.glob("%d.followup.*" % current['number']):
|
||||
process_reply_file(current, f)
|
||||
|
||||
def maybe_add_attachment(current, file, submsg):
|
||||
"""Adds the attachment to the current record"""
|
||||
cd = submsg["Content-Disposition"]
|
||||
m = re.search(r'filename="([^"]+)"', cd)
|
||||
if m == None:
|
||||
return
|
||||
attachment_filename = m.group(1)
|
||||
if (submsg.gettype() == 'application/octet-stream'):
|
||||
# try get a more specific content-type for this attachment
|
||||
type, encoding = mimetypes.guess_type(m.group(1))
|
||||
if type == None:
|
||||
type = submsg.gettype()
|
||||
else:
|
||||
type = submsg.gettype()
|
||||
|
||||
try:
|
||||
data = StringIO.StringIO()
|
||||
mimetools.decode(file, data, submsg.getencoding())
|
||||
except:
|
||||
return
|
||||
|
||||
current['attachments'].append( ( attachment_filename, type, data.getvalue() ) )
|
||||
|
||||
def process_mime_body(current, file, submsg):
|
||||
data = StringIO.StringIO()
|
||||
mimetools.decode(file, data, submsg.getencoding())
|
||||
current['description'] = data.getvalue()
|
||||
|
||||
|
||||
|
||||
def process_text_plain(msg, current):
|
||||
print "Processing: %d" % current['number']
|
||||
current['description'] = msg.fp.read()
|
||||
|
||||
def process_multi_part(file, msg, current):
|
||||
print "Processing: %d" % current['number']
|
||||
mf = multifile.MultiFile(file)
|
||||
mf.push(msg.getparam("boundary"))
|
||||
while mf.next():
|
||||
submsg = mimetools.Message(file)
|
||||
if submsg.has_key("Content-Disposition"):
|
||||
maybe_add_attachment(current, mf, submsg)
|
||||
else:
|
||||
# This is the message body itself (always?), so process
|
||||
# accordingly
|
||||
process_mime_body(current, mf, submsg)
|
||||
|
||||
def process_jitterbug(filename):
|
||||
current = {}
|
||||
current['number'] = int(filename)
|
||||
current['notes'] = []
|
||||
current['attachments'] = []
|
||||
current['description'] = ''
|
||||
current['date-reported'] = ()
|
||||
current['short-description'] = ''
|
||||
|
||||
file = open(filename, "r")
|
||||
msg = mimetools.Message(file)
|
||||
|
||||
msgtype = msg.gettype()
|
||||
|
||||
add_notes(current)
|
||||
current['date-reported'] = rfc822.parsedate_tz(msg['Date'])
|
||||
current['short-description'] = msg['Subject']
|
||||
|
||||
if msgtype[:5] == 'text/':
|
||||
process_text_plain(msg, current)
|
||||
elif msgtype[:10] == "multipart/":
|
||||
process_multi_part(file, msg, current)
|
||||
else:
|
||||
# Huh? This should never happen.
|
||||
print "Unknown content-type: %s" % msgtype
|
||||
sys.exit(1)
|
||||
|
||||
# At this point we have processed the message: we have all of the notes and
|
||||
# attachments stored, so it's time to add things to the database.
|
||||
# The schema for JitterBug 2.14 can be found at:
|
||||
#
|
||||
# http://www.trilobyte.net/barnsons/html/dbschema.html
|
||||
#
|
||||
# The following fields need to be provided by the user:
|
||||
#
|
||||
# bug_status
|
||||
# product
|
||||
# version
|
||||
# reporter
|
||||
# component
|
||||
# resolution
|
||||
|
||||
# change this to the user_id of the Bugzilla user who is blessed with the
|
||||
# imported defects
|
||||
reporter=6
|
||||
|
||||
# the resolution will need to be set manually
|
||||
resolution=""
|
||||
|
||||
db = MySQLdb.connect(db='bugs',user='root',host='localhost')
|
||||
cursor = db.cursor()
|
||||
|
||||
cursor.execute( "INSERT INTO bugs SET " \
|
||||
"bug_id=%s," \
|
||||
"bug_severity='normal'," \
|
||||
"bug_status=%s," \
|
||||
"creation_ts=%s," \
|
||||
"short_desc=%s," \
|
||||
"product=%s," \
|
||||
"rep_platform='All'," \
|
||||
"assigned_to=%s,"
|
||||
"reporter=%s," \
|
||||
"version=%s," \
|
||||
"component=%s," \
|
||||
"resolution=%s",
|
||||
[ current['number'],
|
||||
bug_status,
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", current['date-reported'][:9]),
|
||||
current['short-description'],
|
||||
product,
|
||||
reporter,
|
||||
reporter,
|
||||
version,
|
||||
component,
|
||||
resolution] )
|
||||
|
||||
# This is the initial long description associated with the bug report
|
||||
cursor.execute( "INSERT INTO longdescs VALUES (%s,%s,%s,%s)",
|
||||
[ current['number'],
|
||||
reporter,
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", current['date-reported'][:9]),
|
||||
current['description'] ] )
|
||||
|
||||
# Add whatever notes are associated with this defect
|
||||
for n in current['notes']:
|
||||
cursor.execute( "INSERT INTO longdescs VALUES (%s,%s,%s,%s)",
|
||||
[current['number'],
|
||||
reporter,
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", n['timestamp'][:9]),
|
||||
n['text']])
|
||||
|
||||
# add attachments associated with this defect
|
||||
for a in current['attachments']:
|
||||
cursor.execute( "INSERT INTO attachments SET " \
|
||||
"bug_id=%s, creation_ts=%s, description='', mimetype=%s," \
|
||||
"filename=%s, thedata=%s, submitter_id=%s",
|
||||
[ current['number'],
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", current['date-reported'][:9]),
|
||||
a[1], a[0], a[2], reporter ])
|
||||
|
||||
cursor.close()
|
||||
db.close()
|
||||
|
||||
def usage():
|
||||
print """Usage: jb2bz.py [OPTIONS] Product
|
||||
|
||||
Where OPTIONS are one or more of the following:
|
||||
|
||||
-h This help information.
|
||||
-s STATUS One of UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED
|
||||
(default is NEW)
|
||||
-c COMPONENT The component to attach to each bug as it is important. This should be
|
||||
valid component for the Product.
|
||||
-v VERSION Version to assign to these defects.
|
||||
|
||||
Product is the Product to assign these defects to.
|
||||
|
||||
All of the JitterBugs in the current directory are imported, including replies, notes,
|
||||
attachments, and similar noise.
|
||||
"""
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
global bug_status, component, version, product
|
||||
opts, args = getopt.getopt(sys.argv[1:], "hs:c:v:")
|
||||
|
||||
for o,a in opts:
|
||||
if o == "-s":
|
||||
if a in ('UNCONFIRMED','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED'):
|
||||
bug_status = a
|
||||
elif o == '-c':
|
||||
component = a
|
||||
elif o == '-v':
|
||||
version = a
|
||||
elif o == '-h':
|
||||
usage()
|
||||
|
||||
if len(args) != 1:
|
||||
sys.stderr.write("Must specify the Product.\n")
|
||||
sys.exit(1)
|
||||
|
||||
product = args[0]
|
||||
|
||||
for bug in filter(lambda x: re.match(r"\d+$", x), glob.glob("*")):
|
||||
process_jitterbug(bug)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
102
mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl
Executable file
102
mozilla/webtools/bugzilla/contrib/mysqld-watcher.pl
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bonsaitools/bin/perl -w
|
||||
#
|
||||
# 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) 2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
|
||||
#
|
||||
|
||||
# mysqld-watcher.pl - a script that watches the running instance of
|
||||
# mysqld and kills off any long-running SELECTs against the shadow_db
|
||||
#
|
||||
use diagnostics;
|
||||
use strict;
|
||||
|
||||
require "globals.pl";
|
||||
|
||||
# some configurables:
|
||||
|
||||
# length of time before a thread is eligible to be killed, in seconds
|
||||
#
|
||||
my $long_query_time = 600;
|
||||
#
|
||||
# the From header for any messages sent out
|
||||
#
|
||||
my $mail_from = "root\@lounge.mozilla.org";
|
||||
#
|
||||
# mail transfer agent. this should probably really be converted to a Param().
|
||||
#
|
||||
my $mta_program = "/usr/lib/sendmail -t -ODeliveryMode=deferred";
|
||||
|
||||
# and STDIN is where we get the info about running threads
|
||||
#
|
||||
close(STDIN);
|
||||
open(STDIN, "/usr/bonsaitools/bin/mysqladmin processlist |");
|
||||
|
||||
# iterate through the running threads
|
||||
#
|
||||
my @LONGEST = (0,0,0,0,0,0,0,0,0);
|
||||
while ( <STDIN> ) {
|
||||
my @F = split(/\|/);
|
||||
|
||||
# if this line is not the correct number of fields, or if the thread-id
|
||||
# field contains Id, skip this line. both these cases indicate that this
|
||||
# line contains pretty-printing gunk and not thread info.
|
||||
#
|
||||
next if ( $#F != 9 || $F[1] =~ /Id/);
|
||||
|
||||
if ( $F[4] =~ /shadow_bugs/ # shadowbugs database in use
|
||||
&& $F[5] =~ /Query/ # this is actually a query
|
||||
&& $F[6] > $long_query_time # this query has taken too long
|
||||
&& $F[8] =~ /(select|SELECT)/ # only kill a select
|
||||
&& $F[6] > $LONGEST[6] ) { # the longest running query seen
|
||||
@LONGEST = @F;
|
||||
}
|
||||
}
|
||||
|
||||
# send an email message
|
||||
#
|
||||
# should perhaps be moved to somewhere more global for use in bugzilla as a
|
||||
# whole; should also do more error-checking
|
||||
#
|
||||
sub sendEmail($$$$) {
|
||||
($#_ == 3) || die("sendEmail: invalid number of arguments");
|
||||
my ($from, $to, $subject, $body) = @_;
|
||||
|
||||
open(MTA, "|$mta_program");
|
||||
print MTA "From: $from\n";
|
||||
print MTA "To: $to\n";
|
||||
print MTA "Subject: $subject\n";
|
||||
print MTA "\n";
|
||||
print MTA $body;
|
||||
print MTA "\n";
|
||||
close(MTA);
|
||||
|
||||
}
|
||||
|
||||
# if we found anything, kill the database thread and send mail about it
|
||||
#
|
||||
if ($LONGEST[6] != 0) {
|
||||
|
||||
system ("/usr/bonsaitools/bin/mysqladmin", "kill", $LONGEST[1]);
|
||||
|
||||
# fire off an email telling the maintainer that we had to kill a thread
|
||||
#
|
||||
sendEmail($mail_from, Param("maintainer"),
|
||||
"long running MySQL thread killed",
|
||||
join(" ", @LONGEST) . "\n");
|
||||
}
|
||||
78
mozilla/webtools/bugzilla/contrib/yp_nomail.sh
Executable file
78
mozilla/webtools/bugzilla/contrib/yp_nomail.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
# -*- Mode: ksh -*-
|
||||
##############################################################################
|
||||
# $Id: yp_nomail.sh,v 1.1 2000-09-12 23:50:31 cyeh%bluemartini.com Exp $
|
||||
# yp_nomail
|
||||
#
|
||||
# Our mail admins got annoyed when bugzilla kept sending email
|
||||
# to people who'd had bugzilla entries and left the company. They
|
||||
# were no longer in the list of valid email users so it'd bounce.
|
||||
# Maintaining the 'data/nomail' file was a pain. Luckily, our UNIX
|
||||
# admins list all the users that ever were, but the people who've left
|
||||
# have a distinct marker in their password file. For example:
|
||||
#
|
||||
# fired:*LK*:2053:1010:You're Fired Dude:/home/loser:/bin/false
|
||||
#
|
||||
# This script takes advantage of the "*LK*" convention seen via
|
||||
# ypcat passwd and dumps those people into the nomail file. Any
|
||||
# manual additions are kept in a "nomail.(domainname)" file and
|
||||
# appended to the list of yp lockouts every night via Cron
|
||||
#
|
||||
# 58 23 * * * /export/bugzilla/contrib/yp_nomail.sh > /dev/null 2>&1
|
||||
#
|
||||
# Tak ( Mark Takacs ) 08/2000
|
||||
#
|
||||
# XXX: Maybe should crosscheck w/bugzilla users?
|
||||
##############################################################################
|
||||
|
||||
####
|
||||
# Configure this section to suite yer installation
|
||||
####
|
||||
|
||||
DOMAIN=`domainname`
|
||||
MOZILLA_HOME="/export/mozilla"
|
||||
BUGZILLA_HOME="${MOZILLA_HOME}/bugzilla"
|
||||
NOMAIL_DIR="${BUGZILLA_HOME}/data"
|
||||
NOMAIL="${NOMAIL_DIR}/nomail"
|
||||
NOMAIL_ETIME="${NOMAIL}.${DOMAIN}"
|
||||
NOMAIL_YP="${NOMAIL}.yp"
|
||||
FIRED_FLAG="\*LK\*"
|
||||
|
||||
YPCAT="/usr/bin/ypcat"
|
||||
GREP="/usr/bin/grep"
|
||||
SORT="/usr/bin/sort"
|
||||
|
||||
########################## no more config needed #################
|
||||
|
||||
# This dir comes w/Bugzilla. WAY too paranoid
|
||||
if [ ! -d ${NOMAIL_DIR} ] ; then
|
||||
echo "Creating $date_dir"
|
||||
mkdir -p ${NOMAIL_DIR}
|
||||
fi
|
||||
|
||||
#
|
||||
# Do some (more) paranoid checking
|
||||
#
|
||||
touch ${NOMAIL}
|
||||
if [ ! -w ${NOMAIL} ] ; then
|
||||
echo "Can't write nomail file: ${NOMAIL} -- exiting"
|
||||
exit
|
||||
fi
|
||||
if [ ! -r ${NOMAIL_ETIME} ] ; then
|
||||
echo "Can't access custom nomail file: ${NOMAIL_ETIME} -- skipping"
|
||||
NOMAIL_ETIME=""
|
||||
fi
|
||||
|
||||
#
|
||||
# add all the people with '*LK*' password to the nomail list
|
||||
# XXX: maybe I should customize the *LK* string. Doh.
|
||||
#
|
||||
|
||||
LOCKOUT=`$YPCAT passwd | $GREP "${FIRED_FLAG}" | cut -d: -f1 | sort > ${NOMAIL_YP}`
|
||||
`cat ${NOMAIL_YP} ${NOMAIL_ETIME} > ${NOMAIL}`
|
||||
|
||||
exit
|
||||
|
||||
|
||||
# end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user