Compare commits

..

3 Commits

Author SHA1 Message Date
dkl%redhat.com
b52a1dc48a Various fixes. Added CanSeeProduct functionality back in but also left in old style product groups. Removed references to usebuggroupsentry and usebuggroups since we want it on all the time.
git-svn-id: svn://10.0.0.236/branches/Bugzilla_PgSQL_Groups_Branch@122814 18797224-902f-48f8-a5cc-f745e15eee43
2002-06-06 18:07:41 +00:00
dkl%redhat.com
48b5f960fd Initial creation of Bugzilla_PgSQL_Groups_Branch 2002/05/23
git-svn-id: svn://10.0.0.236/branches/Bugzilla_PgSQL_Groups_Branch@122087 18797224-902f-48f8-a5cc-f745e15eee43
2002-05-23 19:34:21 +00:00
(no author)
73bf11394f This commit was manufactured by cvs2svn to create branch
'Bugzilla_PgSQL_Groups_Branch'.

git-svn-id: svn://10.0.0.236/branches/Bugzilla_PgSQL_Groups_Branch@122018 18797224-902f-48f8-a5cc-f745e15eee43
2002-05-22 09:21:37 +00:00
332 changed files with 104276 additions and 9137 deletions

View File

@@ -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

View File

@@ -1,12 +0,0 @@
DAEMON ONLY DIRECTORIES:
daemon/
testmodule/
CLIENT ONLY DIRECTORIES:
public/
src/
build/
test/
SHARED CODE DIRECTORY:
common/

View File

@@ -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

View File

@@ -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__

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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));
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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

View File

@@ -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

View File

@@ -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__

View File

@@ -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);
}
}
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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;
}
}

View File

@@ -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__

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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__

View File

@@ -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);
}
}

View File

@@ -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__

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
%}

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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)

View File

@@ -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__

View File

@@ -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);
}

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

View 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
View 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/&/&amp;/g;
$_[0] =~ s/</&lt;/g;
$_[0] =~ s/>/&gt;/g;
$_[0] =~ s/'/&apos;/g;
$_[0] =~ s/"/&quot;/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;

File diff suppressed because it is too large Load Diff

View 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.

View 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;

View 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;

View 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.

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View 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&nbsp;$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());
}

View 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'} = \&quoteUrls,
$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;

View 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>

File diff suppressed because it is too large Load Diff

View 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>&lt;IMG SRC="http://www.foo.com/images/topics/topicfoos.gif"
width="34" height="44" border="0" alt="News"&gt;</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 &amp; 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>

View 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)>

View 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>
}

File diff suppressed because it is too large Load Diff

View 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());

View 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;
}

View 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>

View 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;

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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>

View 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

View 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"; }
}
}
}

View 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}"

View 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

View 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

View 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"

File diff suppressed because it is too large Load Diff

View 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()

View 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");
}

View 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