f625063cf6
* Merge recent fixes from trunk
2372 lines
75 KiB
C
2372 lines
75 KiB
C
/****************************************************************************
|
|
* <Novell-copyright>
|
|
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, contact Novell, Inc.
|
|
*
|
|
* To contact Novell about this file by physical or electronic mail, you
|
|
* may find current contact information at www.novell.com.
|
|
* </Novell-copyright>
|
|
****************************************************************************/
|
|
|
|
/* Product defines */
|
|
|
|
#define PRODUCT_NAME "Bongo API Library"
|
|
#define PRODUCT_VERSION "$Revision: 1.6 $"
|
|
#define PRODUCT_SHORT_NAME "msgapi.nlm"
|
|
|
|
#define CURRENT_PRODUCT_VERSION 3
|
|
#define CURRENT_PRODUCT_VERSION_MAJOR 5
|
|
#define CURRENT_PRODUCT_VERSION_MINOR 3
|
|
|
|
#include <config.h>
|
|
#include <xpl.h>
|
|
#include <xplresolve.h>
|
|
#include <connio.h>
|
|
|
|
#include <nmap.h>
|
|
#include <nmlib.h>
|
|
#include <msgapi.h>
|
|
#include "msgapip.h"
|
|
|
|
#include <bongo-buildinfo.h>
|
|
#include <bongoutil.h>
|
|
#include <bongostore.h>
|
|
#include <curl/curl.h>
|
|
|
|
#define MSGAPI_FLAG_EXITING (1 << 0)
|
|
#define MSGAPI_FLAG_STANDALONE (1 << 1)
|
|
#define MSGAPI_FLAG_SUPPORT_CONNMGR (1 << 2)
|
|
#define MSGAPI_FLAG_CLUSTERED (1 << 3)
|
|
#define MSGAPI_FLAG_BOUND (1 << 4)
|
|
#define MSGAPI_FLAG_INTERNET_EMAIL_ADDRESS (1 << 5)
|
|
#define MSGAPI_FLAG_MONITOR_RUNNING (1 << 6)
|
|
|
|
#define LOOPBACK_ADDRESS 0x0100007F
|
|
#define EMPTY_CHAR 0x01
|
|
|
|
#define CONNMGR_STRUCT_SIZE (sizeof(ConnectionManagerCommand) + MAXEMAILNAMESIZE)
|
|
|
|
#define CONNMGR_REPLY_NOT_FOUND 0
|
|
#define CONNMGR_REPLY_FOUND 1
|
|
#define CONNMGR_REPLY_FOUND_NAME 2
|
|
|
|
#define CONNMGR_REQ_STORE 0
|
|
#define CONNMGR_REQ_CHECK 1
|
|
#define CONNMGR_REQ_STORE_NAME 2
|
|
#define CONNMGR_REQ_CHECK_NAME 3
|
|
|
|
enum LibraryStates {
|
|
LIBRARY_LOADED = 0,
|
|
LIBRARY_INITIALIZING,
|
|
LIBRARY_RUNNING,
|
|
LIBRARY_SHUTTING_DOWN,
|
|
LIBRARY_SHUTDOWN,
|
|
|
|
LIBRARY_MAX_STATES
|
|
} MSGAPIState = LIBRARY_LOADED;
|
|
|
|
struct {
|
|
unsigned long flags;
|
|
|
|
MDBHandle directoryHandle;
|
|
|
|
XplThreadID groupID;
|
|
|
|
struct {
|
|
XplSemaphore version;
|
|
XplSemaphore shutdown;
|
|
XplMutex uid;
|
|
} sem;
|
|
|
|
struct {
|
|
unsigned char dn[MDB_MAX_OBJECT_CHARS + 1];
|
|
} server;
|
|
|
|
struct {
|
|
MDBValueStruct *storePaths;
|
|
MDBValueStruct *storeDNs;
|
|
|
|
struct {
|
|
MDBValueStruct *names;
|
|
MDBValueStruct *contexts;
|
|
struct sockaddr_in *addr;
|
|
} server;
|
|
|
|
#ifdef PARENTOBJECT_STORE
|
|
struct {
|
|
MDBValueStruct *objects;
|
|
MDBValueStruct *stores;
|
|
MDBValueSTruct *indices;
|
|
} parent;
|
|
#endif
|
|
} vs;
|
|
|
|
unsigned long connManager;
|
|
|
|
XplRWLock configLock;
|
|
|
|
struct {
|
|
unsigned char work[XPL_MAX_PATH + 1];
|
|
unsigned char nls[XPL_MAX_PATH + 1];
|
|
unsigned char dbf[XPL_MAX_PATH + 1];
|
|
unsigned char bin[XPL_MAX_PATH + 1];
|
|
unsigned char lib[XPL_MAX_PATH + 1];
|
|
unsigned char certificate[XPL_MAX_PATH + 1];
|
|
unsigned char key[XPL_MAX_PATH + 1];
|
|
} paths;
|
|
|
|
struct {
|
|
unsigned long local;
|
|
|
|
unsigned char string[16];
|
|
} address;
|
|
|
|
struct {
|
|
unsigned char moduleName[XPL_MAX_PATH + 1];
|
|
unsigned char fileName[XPL_MAX_PATH + 1];
|
|
|
|
XplPluginHandle handle;
|
|
|
|
FindObjectCacheInitType init;
|
|
FindObjectCacheShutdownType shutdown;
|
|
FindObjectCacheType find;
|
|
FindObjectCacheExType findEx;
|
|
FindObjectStoreCacheType store;
|
|
} cache;
|
|
|
|
struct {
|
|
unsigned char domain[MAXEMAILNAMESIZE + 1];
|
|
unsigned long domainLength;
|
|
} official;
|
|
|
|
XplAtomic useCount;
|
|
} MsgGlobal;
|
|
|
|
typedef struct _ConnectionManagerCommand {
|
|
unsigned long request;
|
|
unsigned long address;
|
|
unsigned long nameLen;
|
|
unsigned long counter;
|
|
unsigned char name[1];
|
|
} ConnectionManagerCommand;
|
|
|
|
/* private */
|
|
BOOL
|
|
MsgGetUpdateStatus(char *record, int record_length);
|
|
|
|
/* I tried to remove this, but it's still needed :(
|
|
* Python server for Dragonfly needs a way to authenticate itself
|
|
* to the queue...
|
|
*/
|
|
void
|
|
MsgNmapChallenge(const unsigned char *response, unsigned char *reply, size_t length)
|
|
{
|
|
unsigned char *ptr;
|
|
unsigned char *salt;
|
|
static unsigned char access[NMAP_HASH_SIZE] = { '\0' };
|
|
MDBValueStruct *v;
|
|
xpl_hash_context ctx;
|
|
|
|
if (access[0] == '\0') {
|
|
if (MsgGlobal.directoryHandle) {
|
|
v = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
if (v) {
|
|
MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, v);
|
|
if (v->Used) {
|
|
HashCredential(MsgGlobal.server.dn, v->Value[0], access);
|
|
}
|
|
|
|
MDBDestroyValueStruct(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (access[0] && reply && (length > 32) && ((ptr = strchr(response, '<')) != NULL)) {
|
|
salt = ++ptr;
|
|
|
|
if ((ptr = strchr(ptr, '>')) != NULL) {
|
|
*ptr = '\0';
|
|
}
|
|
|
|
XplHashNew(&ctx, XPLHASH_MD5);
|
|
XplHashWrite(&ctx, salt, strlen(salt));
|
|
XplHashWrite(&ctx, access, NMAP_HASH_SIZE);
|
|
XplHashFinal(&ctx, XPLHASH_LOWERCASE, reply, XPLHASH_MD5_LENGTH);
|
|
} else if (reply) {
|
|
*reply = '\0';
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetServerDN(unsigned char *buffer)
|
|
{
|
|
if (buffer) {
|
|
return(strcpy(buffer, MsgGlobal.server.dn));
|
|
}
|
|
return(MsgGlobal.server.dn);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgFindUserNmap(const unsigned char *user, unsigned char *nmap, int nmap_len, unsigned short *port)
|
|
{
|
|
struct sockaddr_in nmap_tmp;
|
|
|
|
BOOL retVal = FALSE;
|
|
retVal = MsgFindObject(user, NULL, NULL, &nmap_tmp, NULL);
|
|
|
|
if (retVal) {
|
|
strncpy(nmap, inet_ntoa(nmap_tmp.sin_addr), nmap_len);
|
|
*port = ntohs(nmap_tmp.sin_port);
|
|
return retVal;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgFindObject(const unsigned char *user, unsigned char *dn, unsigned char *userType, struct sockaddr_in *nmap, MDBValueStruct *v)
|
|
{
|
|
BOOL retVal = FALSE;
|
|
|
|
if (MsgGlobal.cache.find == NULL) {
|
|
MDBValueStruct *userCtx;
|
|
MDBValueStruct *types;
|
|
unsigned long i, j;
|
|
unsigned char rdn[MDB_MAX_OBJECT_CHARS + 1];
|
|
|
|
BOOL isUser = FALSE;
|
|
BOOL isGroup = FALSE;
|
|
BOOL isResource = FALSE;
|
|
BOOL isOrgRole = FALSE;
|
|
BOOL isDynGroup = FALSE;
|
|
|
|
/* FIXME: handle failure to create ValueStructs */
|
|
userCtx = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
types = MDBShareContext(userCtx);
|
|
|
|
XplRWReadLockAcquire(&MsgGlobal.configLock);
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], userCtx);
|
|
if (MDBGetObjectDetailsEx(user, types, rdn, dn, userCtx)) {
|
|
|
|
/* determine relevant types now so we don't have to loop
|
|
throught the list everytime. */
|
|
for (j = 0; j < types->Used; j++) {
|
|
if (strcmp(types->Value[j], C_USER) == 0) {
|
|
isUser = TRUE;
|
|
} else if (strcmp(types->Value[j],
|
|
MSGSRV_C_RESOURCE) == 0) {
|
|
isResource = TRUE;
|
|
} else if (strcmp(types->Value[j], MSGSRV_C_GROUP) == 0 ||
|
|
strcmp(types->Value[j], C_GROUP) == 0) {
|
|
isGroup = TRUE;
|
|
} else if (strcmp(types->Value[j],
|
|
MSGSRV_C_ORGANIZATIONAL_ROLE) == 0 ||
|
|
strcmp(types->Value[j],
|
|
C_ORGANIZATIONAL_ROLE) == 0) {
|
|
isOrgRole = TRUE;
|
|
} else if (strcmp(types->Value[j], "dynamicGroup") == 0) {
|
|
isDynGroup = TRUE;
|
|
}
|
|
}
|
|
|
|
if (MsgGetUserSetting(user, MSGSRV_A_MESSAGING_DISABLED,
|
|
userCtx) > 0) {
|
|
if (userCtx->Value[userCtx->Used-1][0] == '1') {
|
|
break;
|
|
} else {
|
|
MDBFreeValue(userCtx->Used - 1, userCtx);
|
|
}
|
|
}
|
|
|
|
if (isUser || isResource) {
|
|
if (v) {
|
|
MDBAddValue(rdn, v);
|
|
}
|
|
if (nmap) {
|
|
memcpy(nmap, &MsgGlobal.vs.server.addr[i], sizeof(struct sockaddr_in));
|
|
}
|
|
if (userType) {
|
|
if (isUser) {
|
|
strcpy(userType, C_USER);
|
|
} else if (isResource) {
|
|
strcpy(userType, MSGSRV_C_RESOURCE);
|
|
}
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isGroup) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_MEMBER, v);
|
|
|
|
/* This removes any context from a group member's name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr = strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, C_GROUP);
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isOrgRole) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_ROLE_OCCUPANT, v);
|
|
|
|
/* This removes any context from a the roles name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr = strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, C_ORGANIZATIONAL_ROLE);
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isDynGroup) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_MEMBER, v);
|
|
|
|
/* This removes any context from a group member's name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr=strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, "dynamicGroup");
|
|
}
|
|
retVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
|
|
MDBDestroyValueStruct(userCtx);
|
|
MDBDestroyValueStruct(types);
|
|
} else {
|
|
retVal = MsgGlobal.cache.find(user, dn, userType, nmap, v);
|
|
}
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgFindObjectEx(const unsigned char *user, unsigned char *dn, unsigned char *userType, struct sockaddr_in *nmap, BOOL *disabled, MDBValueStruct *v)
|
|
{
|
|
BOOL retVal = FALSE;
|
|
|
|
if (MsgGlobal.cache.findEx == NULL) {
|
|
MDBValueStruct *userCtx;
|
|
MDBValueStruct *types;
|
|
unsigned long i, j;
|
|
unsigned char rdn[MDB_MAX_OBJECT_CHARS + 1];
|
|
|
|
BOOL isUser = FALSE;
|
|
BOOL isGroup = FALSE;
|
|
BOOL isResource = FALSE;
|
|
BOOL isOrgRole = FALSE;
|
|
BOOL isDynGroup = FALSE;
|
|
|
|
userCtx = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
types = MDBShareContext(userCtx);
|
|
|
|
XplRWReadLockAcquire(&MsgGlobal.configLock);
|
|
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], userCtx);
|
|
|
|
if (MDBGetObjectDetailsEx(user, types, rdn, dn, userCtx)) {
|
|
for (j = 0; j < types->Used; j++) {
|
|
if (strcmp(types->Value[j], C_USER) == 0) {
|
|
isUser = TRUE;
|
|
} else if (strcmp(types->Value[j],
|
|
MSGSRV_C_RESOURCE) == 0) {
|
|
isResource = TRUE;
|
|
} else if (strcmp(types->Value[j], MSGSRV_C_GROUP) == 0 ||
|
|
strcmp(types->Value[j], C_GROUP) == 0) {
|
|
isGroup = TRUE;
|
|
} else if (strcmp(types->Value[j],
|
|
MSGSRV_C_ORGANIZATIONAL_ROLE) == 0 ||
|
|
strcmp(types->Value[j],
|
|
C_ORGANIZATIONAL_ROLE) == 0) {
|
|
isOrgRole = TRUE;
|
|
} else if (strcmp(types->Value[j], "dynamicGroup") == 0) {
|
|
isDynGroup = TRUE;
|
|
}
|
|
}
|
|
|
|
if (MsgGetUserSetting(user, MSGSRV_A_MESSAGING_DISABLED,
|
|
userCtx) > 0) {
|
|
if (userCtx->Value[userCtx->Used - 1][0] == '1') {
|
|
*disabled = TRUE;
|
|
} else {
|
|
*disabled = FALSE;
|
|
}
|
|
MDBFreeValue(userCtx->Used - 1, userCtx);
|
|
} else {
|
|
*disabled = FALSE;
|
|
}
|
|
|
|
if (isUser || isResource) {
|
|
if (v) {
|
|
MDBAddValue(rdn, v);
|
|
}
|
|
if (nmap) {
|
|
memcpy(nmap, &MsgGlobal.vs.server.addr[i], sizeof(struct sockaddr_in));
|
|
}
|
|
if (userType) {
|
|
if (isUser) {
|
|
strcpy(userType, C_USER);
|
|
} else if (isResource) {
|
|
strcpy(userType, MSGSRV_C_RESOURCE);
|
|
}
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isGroup) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_MEMBER, v);
|
|
|
|
/* This removes any context from a group member's name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr = strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, C_GROUP);
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isOrgRole) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_ROLE_OCCUPANT, v);
|
|
|
|
/* This removes any context from a the roles name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr = strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, C_ORGANIZATIONAL_ROLE);
|
|
}
|
|
retVal = TRUE;
|
|
} else if (isDynGroup) {
|
|
if (v) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v);
|
|
MDBRead(user, A_MEMBER, v);
|
|
|
|
/* This removes any context from a group member's name */
|
|
for (j = 0; j < v->Used; j++) {
|
|
unsigned char *ptr;
|
|
ptr = strrchr(v->Value[j], '\\');
|
|
if (ptr) {
|
|
memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
if (userType) {
|
|
strcpy(userType, "dynamicGroup");
|
|
}
|
|
retVal = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
|
|
MDBDestroyValueStruct(userCtx);
|
|
} else {
|
|
retVal = MsgGlobal.cache.findEx(user, dn, userType, nmap, disabled, v);
|
|
}
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgFindUserStore(const unsigned char *user, const unsigned char *defaultPath)
|
|
{
|
|
if (MsgGlobal.cache.store == NULL) {
|
|
MDBValueStruct *context;
|
|
unsigned long i;
|
|
|
|
XplRWReadLockAcquire(&MsgGlobal.configLock);
|
|
context = MDBCreateValueStruct(MsgGlobal.directoryHandle, MsgGlobal.vs.server.contexts->Value[0]);
|
|
|
|
i = 0;
|
|
do {
|
|
if (MDBIsObject(user, context)) {
|
|
MDBDestroyValueStruct(context);
|
|
if (MsgGlobal.vs.storePaths->Value[i][0] != EMPTY_CHAR) {
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
return(MsgGlobal.vs.storePaths->Value[i]);
|
|
} else {
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
return(defaultPath);
|
|
}
|
|
} else {
|
|
i++;
|
|
if (i != MsgGlobal.vs.server.contexts->Used) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], context);
|
|
}
|
|
}
|
|
} while (i != MsgGlobal.vs.server.contexts->Used);
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
|
|
MDBDestroyValueStruct(context);
|
|
return(defaultPath);
|
|
}
|
|
|
|
return MsgGlobal.cache.store(user, defaultPath);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgReadIP(const unsigned char *object, unsigned char *type, MDBValueStruct *v)
|
|
{
|
|
int first,last, i;
|
|
unsigned char *ptr;
|
|
|
|
if (!v || !type) {
|
|
return(FALSE);
|
|
}
|
|
|
|
first=v->Used;
|
|
|
|
if (!object) {
|
|
if (!MDBReadDN(MsgGlobal.server.dn, type, v)) {
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
if (!MDBReadDN(object, type, v)) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
last = v->Used;
|
|
|
|
for (i = first; i < last; i++) {
|
|
if ((ptr = strrchr(v->Value[i], '\\')) != NULL) {
|
|
*ptr = '\0';
|
|
}
|
|
MDBRead(v->Value[i], MSGSRV_A_IP_ADDRESS, v);
|
|
}
|
|
|
|
/* The following loop removes the names read by the ReadDN above,
|
|
* but keeps the IP addresses added afterwards :-) */
|
|
for (i = first; i < last; i++) {
|
|
MDBFreeValue(0, v);
|
|
}
|
|
|
|
if (v->Used > 0) {
|
|
return(TRUE);
|
|
} else {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgDomainExists(const unsigned char *domain, unsigned char *domainObjectDN)
|
|
{
|
|
MDBValueStruct *domains;
|
|
unsigned long i;
|
|
unsigned long j;
|
|
|
|
/* FIXME later; when we handle parent objects */
|
|
return(FALSE);
|
|
|
|
domains = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
|
|
XplRWReadLockAcquire(&MsgGlobal.configLock);
|
|
|
|
for (i = 0; i < MsgGlobal.vs.server.names->Used; i++) {
|
|
MDBSetValueStructContext(MsgGlobal.vs.server.names->Value[i], domains);
|
|
if(MDBRead(MSGSRV_AGENT_SMTP, MSGSRV_A_DOMAIN, domains) > 0) {
|
|
for (j = 0; j < domains->Used; j++) {
|
|
if (XplStrCaseCmp(domain, domains->Value[j])==0) {
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
MDBDestroyValueStruct(domains);
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
MDBFreeValues(domains);
|
|
}
|
|
MDBDestroyValueStruct(domains);
|
|
XplRWReadLockRelease(&MsgGlobal.configLock);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
EXPORT int
|
|
MsgGetParentAttribute(const unsigned char *userDN, unsigned char *attribute, MDBValueStruct *vOut)
|
|
{
|
|
char configDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
unsigned long index;
|
|
int result = 0;
|
|
|
|
configDn[0] = '\0';
|
|
|
|
if (MsgGetUserSettingsDN(userDN, configDn, vOut, FALSE)) {
|
|
if (MDBRead(configDn, MSGSRV_A_PARENT_OBJECT, vOut) > 0) {
|
|
index = vOut->Used - 1;
|
|
if (MDBRead(vOut->Value[index], attribute, vOut)>0) {
|
|
MDBFreeValue(index, vOut);
|
|
result = vOut->Used;
|
|
} else {
|
|
MDBFreeValue(index, vOut);
|
|
result = MDBRead(userDN, attribute, vOut);
|
|
}
|
|
} else {
|
|
result = MDBRead(userDN, attribute, vOut);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
EXPORT unsigned char *
|
|
MsgGetUserEmailAddress(const unsigned char *userDNin, MDBValueStruct *userData, unsigned char *buffer, unsigned long bufLen)
|
|
{
|
|
unsigned char *emailAddress = NULL;
|
|
unsigned long originalValueCount = userData->Used;
|
|
unsigned long lastValueCount = originalValueCount;
|
|
unsigned char *user = NULL;
|
|
unsigned char userDN[MDB_MAX_OBJECT_CHARS + 1];
|
|
unsigned char configDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
unsigned char *delim;
|
|
|
|
/* Make a copy so we don't edit the const string */
|
|
strcpy(userDN, userDNin);
|
|
|
|
if (!(MsgGlobal.flags & MSGAPI_FLAG_INTERNET_EMAIL_ADDRESS)) {
|
|
MDBRead(userDN, A_INTERNET_EMAIL_ADDRESS, userData);
|
|
if (userData->Used > lastValueCount) {
|
|
|
|
if (strchr(userData->Value[userData->Used - 1], '@')) {
|
|
/* The user object has a value in the Internet Email Address Attribute */
|
|
if (buffer) {
|
|
if (bufLen > strlen(userData->Value[userData->Used - 1])) {
|
|
emailAddress = buffer;
|
|
strcpy(emailAddress, userData->Value[userData->Used - 1]);
|
|
}
|
|
} else {
|
|
emailAddress = MemStrdup(userData->Value[userData->Used - 1]);
|
|
}
|
|
|
|
while (originalValueCount < userData->Used){
|
|
MDBFreeValue(userData->Used - 1, userData);
|
|
}
|
|
return(emailAddress);
|
|
} else {
|
|
user = userData->Value[userData->Used - 1];
|
|
lastValueCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The value in the Internet Email Address Attribute still needs a domain */
|
|
|
|
delim = strrchr(userDN, '\\' );
|
|
if (delim) {
|
|
if (strchr(delim + 1, '@')) {
|
|
/* The username is an address */
|
|
if (buffer) {
|
|
if (bufLen > strlen(delim + 1)) {
|
|
emailAddress = buffer;
|
|
strcpy(emailAddress, delim + 1);
|
|
}
|
|
} else {
|
|
emailAddress = MemStrdup(delim + 1);
|
|
}
|
|
|
|
while (originalValueCount < userData->Used) {
|
|
MDBFreeValue(userData->Used - 1, userData);
|
|
}
|
|
|
|
return(emailAddress);
|
|
}
|
|
|
|
if (!user) {
|
|
user = delim + 1;
|
|
}
|
|
|
|
|
|
if (MsgGetParentAttribute(userDN, MSGSRV_A_DOMAIN, userData)) {
|
|
/* The user or parent has a domain defined */
|
|
if (buffer) {
|
|
if (bufLen > (strlen(user) + strlen(userData->Value[userData->Used - 1]) + 1)) {
|
|
emailAddress = buffer;
|
|
sprintf(emailAddress, "%s@%s", user, userData->Value[userData->Used - 1]);
|
|
}
|
|
} else {
|
|
emailAddress = MemMalloc(strlen(user) + strlen(userData->Value[userData->Used - 1]) + 2);
|
|
if (emailAddress) {
|
|
sprintf(emailAddress, "%s@%s", user, userData->Value[userData->Used - 1]);
|
|
}
|
|
}
|
|
|
|
while (originalValueCount < userData->Used){
|
|
MDBFreeValue(userData->Used - 1, userData);
|
|
}
|
|
|
|
return(emailAddress);
|
|
}
|
|
|
|
*delim = '\0';
|
|
if (MsgGetUserSettingsDN(userDN, configDn, userData, FALSE)) {
|
|
MDBRead(configDn, MSGSRV_A_DOMAIN, userData);
|
|
}
|
|
|
|
if (userData->Used > lastValueCount) {
|
|
/* The container has a domain defined */
|
|
if (buffer) {
|
|
if (bufLen > (strlen(user) + strlen(userData->Value[userData->Used - 1]) + 1)) {
|
|
emailAddress = buffer;
|
|
sprintf(emailAddress, "%s@%s", user, userData->Value[userData->Used - 1]);
|
|
}
|
|
} else {
|
|
emailAddress = MemMalloc(strlen(user) + strlen(userData->Value[userData->Used - 1]) + 2);
|
|
if (emailAddress) {
|
|
sprintf(emailAddress, "%s@%s", user, userData->Value[userData->Used - 1]);
|
|
}
|
|
}
|
|
} else {
|
|
/* Default user@official */
|
|
if (buffer) {
|
|
if (bufLen > (strlen(user) + MsgGlobal.official.domainLength + 1)) {
|
|
emailAddress = buffer;
|
|
sprintf(emailAddress, "%s@%s", user, MsgGlobal.official.domain);
|
|
}
|
|
} else {
|
|
emailAddress = MemMalloc(strlen(user) + MsgGlobal.official.domainLength + 2);
|
|
if (emailAddress) {
|
|
sprintf(emailAddress, "%s@%s", user, MsgGlobal.official.domain);
|
|
}
|
|
}
|
|
}
|
|
|
|
*delim = '\\';
|
|
|
|
for (;originalValueCount < userData->Used;){
|
|
MDBFreeValue(userData->Used - 1, userData);
|
|
}
|
|
return(emailAddress);
|
|
}
|
|
|
|
/* The dn does not appear valid. Treat it as rdn and do our best */
|
|
if (buffer) {
|
|
if (bufLen > (strlen(userDN) + MsgGlobal.official.domainLength + 1)) {
|
|
emailAddress = buffer;
|
|
sprintf(emailAddress, "%s@%s", userDN, MsgGlobal.official.domain);
|
|
}
|
|
} else {
|
|
emailAddress = MemMalloc(strlen(userDN) + MsgGlobal.official.domainLength + 2);
|
|
if (emailAddress) {
|
|
sprintf(emailAddress, "%s@%s", userDN, MsgGlobal.official.domain);
|
|
}
|
|
}
|
|
|
|
while (originalValueCount < userData->Used) {
|
|
MDBFreeValue(userData->Used - 1, userData);
|
|
}
|
|
return(emailAddress);
|
|
}
|
|
|
|
EXPORT unsigned char *
|
|
MsgGetUserDisplayName(const unsigned char *userDN, MDBValueStruct *userData)
|
|
{
|
|
unsigned char *displayName = NULL;
|
|
unsigned long index = userData->Used;
|
|
unsigned char *rdn;
|
|
|
|
/* Read the Display Name */
|
|
if ((MDBRead(userDN, A_FULL_NAME, userData) > 0) && (userData->Value[index][0] != '\0')) {
|
|
displayName = MemStrdup(userData->Value[index]);
|
|
while (index < userData->Used){
|
|
MDBFreeValue(index, userData);
|
|
}
|
|
return(displayName);
|
|
}
|
|
|
|
/* Create full name using First and Last */
|
|
MDBRead(userDN, A_GIVEN_NAME, userData);
|
|
MDBRead(userDN, A_SURNAME, userData);
|
|
if (userData->Used == (index + 2)) {
|
|
if ((userData->Value[index][0] != '\0') && (userData->Value[index + 1][0] != '\0')) {
|
|
displayName = MemMalloc (strlen (userData->Value[index]) + strlen (userData->Value[index + 1]) + 2);
|
|
sprintf(displayName, "%s %s", userData->Value[index], userData->Value[index + 1]);
|
|
} else if (userData->Value[index][0] != '\0') {
|
|
displayName = MemStrdup(userData->Value[index]);
|
|
} else if (userData->Value[index + 1][0] != '\0') {
|
|
displayName = MemStrdup(userData->Value[index + 1]);
|
|
} else {
|
|
if ((rdn = strrchr(userDN, '\\'))) {
|
|
displayName = MemStrdup(rdn + 1);
|
|
} else {
|
|
|
|
displayName = MemStrdup("");
|
|
}
|
|
}
|
|
} else if (userData->Used == (index + 1)) {
|
|
if (!(userData->Value[index][0] == ' ' && userData->Value[index][1] == '\0')) {
|
|
displayName = MemStrdup(userData->Value[index]);
|
|
} else {
|
|
/* FIXME: is this right? */
|
|
if ((rdn = strrchr (userDN, '\\'))) {
|
|
displayName = MemStrdup(rdn + 1);
|
|
} else {
|
|
displayName = MemStrdup("");
|
|
}
|
|
}
|
|
} else {
|
|
if ((rdn = strrchr(userDN, '\\'))) {
|
|
displayName = MemStrdup(rdn + 1);
|
|
} else {
|
|
displayName = MemStrdup("");
|
|
}
|
|
|
|
}
|
|
|
|
while (index < userData->Used) {
|
|
MDBFreeValue(index, userData);
|
|
}
|
|
|
|
|
|
return(displayName);
|
|
|
|
}
|
|
|
|
/* Get the container DN where a given user's settings object should exist.
|
|
This function is responsible for sorting BongoUserSettings objects into
|
|
various partitions under the root BongoUserSettingsContainer. */
|
|
EXPORT BOOL
|
|
MsgGetUserSettingsContainerDN(const unsigned char *userDn,
|
|
unsigned char *containerDn, MDBValueStruct *v,
|
|
BOOL create)
|
|
{
|
|
MDBValueStruct *attr, *data;
|
|
char servicesDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
char dn[MDB_MAX_OBJECT_CHARS + 1];
|
|
BOOL result = FALSE;
|
|
char *bucket;
|
|
|
|
/* Use the first letter of the user's name to sort them into containers.
|
|
This is not the most optimal solution, but it should allow admins to
|
|
find corresponding config objects more easily. */
|
|
|
|
if (MsgGetConfigProperty(servicesDn, MSGSRV_CONFIG_PROP_BONGO_SERVICES)) {
|
|
bucket = strrchr(userDn, '\\');
|
|
|
|
if (bucket) {
|
|
bucket++;
|
|
} else {
|
|
bucket = userDn;
|
|
}
|
|
|
|
sprintf(dn, "%s\\%s\\%c", servicesDn, MSGSRV_USER_SETTINGS_ROOT,
|
|
*bucket);
|
|
|
|
if (MDBIsObject(dn, v)) {
|
|
result = TRUE;
|
|
} else if (create) {
|
|
attr = MDBShareContext(v);
|
|
data = MDBShareContext(v);
|
|
|
|
if (attr && data) {
|
|
result = MDBCreateObject(dn, MSGSRV_C_USER_SETTINGS_CONTAINER,
|
|
attr, data, v);
|
|
MDBDestroyValueStruct(attr);
|
|
MDBDestroyValueStruct(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
strcpy(containerDn, dn);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* User settings are stored on a corresponding BongoUserSettings object that
|
|
* can be discovered by following the SeeAlso attribute on the User.
|
|
* This function is for convenience in discovering the config object DN.
|
|
*/
|
|
EXPORT BOOL
|
|
MsgGetUserSettingsDN(const unsigned char *userDn, unsigned char *configDn,
|
|
MDBValueStruct *v, BOOL create)
|
|
{
|
|
int i;
|
|
char type[MDB_MAX_ATTRIBUTE_VALUE_CHARS + 1];
|
|
char containerDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
char *cn;
|
|
MDBValueStruct *vTmp, *attr, *data;
|
|
BOOL result = FALSE;
|
|
|
|
vTmp = MDBShareContext(v);
|
|
|
|
if (vTmp) {
|
|
if (MDBReadDN(userDn, A_SEE_ALSO, vTmp)) {
|
|
for (i = 0; i < vTmp->Used; i++) {
|
|
if (!MDBGetObjectDetails(vTmp->Value[i], type, NULL, NULL,
|
|
vTmp)) {
|
|
break;
|
|
}
|
|
|
|
if (!strcasecmp(type, MSGSRV_C_USER_SETTINGS)) {
|
|
strcpy(configDn, vTmp->Value[i]);
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result && create) {
|
|
cn = strrchr(userDn, '\\');
|
|
attr = MDBShareContext(vTmp);
|
|
data = MDBShareContext(vTmp);
|
|
|
|
if (cn && attr && data &&
|
|
MsgGetUserSettingsContainerDN(userDn, containerDn, vTmp,
|
|
TRUE)) {
|
|
sprintf(configDn, "%s\\%s", containerDn, ++cn);
|
|
|
|
if (MDBCreateObject(configDn, MSGSRV_C_USER_SETTINGS,
|
|
attr, data, vTmp) &&
|
|
MDBAddDN(userDn, A_SEE_ALSO, configDn, vTmp)) {
|
|
result = TRUE;
|
|
} else {
|
|
configDn[0] = '\0';
|
|
}
|
|
|
|
MDBDestroyValueStruct(attr);
|
|
MDBDestroyValueStruct(data);
|
|
}
|
|
}
|
|
|
|
MDBDestroyValueStruct(vTmp);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Try to get the setting first from the user object, then from the user's
|
|
* settings object. Parent object may override values on settings object.
|
|
*/
|
|
EXPORT long
|
|
MsgGetUserSetting(const unsigned char *userDn, unsigned char *attribute,
|
|
MDBValueStruct *vOut)
|
|
{
|
|
char configDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
char parentDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
MDBValueStruct *v;
|
|
long result = 0;
|
|
|
|
configDn[0] = '\0';
|
|
parentDn[0] = '\0';
|
|
v = MDBShareContext(vOut);
|
|
|
|
if (v) {
|
|
if (MsgGetUserSettingsDN(userDn, configDn, v, FALSE)) {
|
|
if (MDBReadDN(configDn, MSGSRV_A_PARENT_OBJECT, v)) {
|
|
strcpy(parentDn, v->Value[0]);
|
|
MDBFreeValues(v);
|
|
|
|
if (MDBRead(parentDn, MSGSRV_A_FEATURE_INHERITANCE, v)) {
|
|
if (v->Value[0][0] != FEATURE_PARENT_FIRST) {
|
|
/* child takes precedence */
|
|
parentDn[0] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* try parent object */
|
|
if (*parentDn) {
|
|
result = MDBRead(parentDn, attribute, vOut);
|
|
}
|
|
|
|
/* try user object */
|
|
if (!result) {
|
|
result = MDBRead(userDn, attribute, vOut);
|
|
}
|
|
|
|
/* try settings object */
|
|
if (!result && *configDn) {
|
|
result = MDBRead(configDn, attribute, vOut);
|
|
}
|
|
MDBDestroyValueStruct(v);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Use these functions to ensure that the correct MDB function is used
|
|
* for strings or DNs.
|
|
*/
|
|
static BOOL
|
|
MsgMdbWriteAny(const unsigned char *dn, const unsigned char *attribute,
|
|
MDBValueStruct *v)
|
|
{
|
|
if (v->Used > 0 && strchr(v->Value[0], '\\')) {
|
|
return MDBWriteDN(dn, attribute, v);
|
|
}
|
|
|
|
return MDBWrite(dn, attribute, v);
|
|
}
|
|
|
|
static BOOL
|
|
MsgMdbAddAny(const unsigned char *dn, const unsigned char *attribute,
|
|
const unsigned char *value, MDBValueStruct *v)
|
|
{
|
|
if (v->Used > 0 && strchr(v->Value[0], '\\')) {
|
|
return MDBAddDN(dn, attribute, value, v);
|
|
}
|
|
|
|
return MDBAdd(dn, attribute, value, v);
|
|
}
|
|
|
|
/*
|
|
* Try to apply changes to the user object first then the config object. If
|
|
* the config object doesn't exist, create it.
|
|
*/
|
|
EXPORT BOOL
|
|
MsgSetUserSetting(const unsigned char *userDn, unsigned char *attribute,
|
|
MDBValueStruct *v)
|
|
{
|
|
char configDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
BOOL result = FALSE;
|
|
|
|
if (MDBIsObject(userDn, v) &&
|
|
!(result = MsgMdbWriteAny(userDn, attribute, v))) {
|
|
if (MsgGetUserSettingsDN(userDn, configDn, v, TRUE)) {
|
|
/* config objects are created on demand */
|
|
result = MsgMdbWriteAny(configDn, attribute, v);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgAddUserSetting(const unsigned char *userDn, unsigned char *attribute,
|
|
unsigned char *value, MDBValueStruct *v)
|
|
{
|
|
char configDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
BOOL result = FALSE;
|
|
|
|
if (MDBIsObject(userDn, v) &&
|
|
!(result = MsgMdbAddAny(userDn, attribute, value, v))) {
|
|
/* config objects are created on demand */
|
|
if (!MsgGetUserSettingsDN(userDn, configDn, v, TRUE)) {
|
|
result = MsgMdbAddAny(configDn, attribute, value, v);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Here's the logic:
|
|
*
|
|
* Step 1: We get the DN from the caller; we check if there's a parent DN,
|
|
* Step 2: If we have inheritance DN, so we read the inheritance configuration of the parent, if not, go to step 4c
|
|
* Step 3a: Inheritance is Parent->User; read features attribute from parent
|
|
* Step 3b: Inheritance is User->Parent; read features attribute from user
|
|
* Step 4a: If feature disabled return disabled state
|
|
* Step 4b: If feature from parent, read parent data attribute
|
|
* Step 4c: If feature from user, read user data attribute
|
|
* Step 5: If data attribute empty, try opposite DN attribute
|
|
*
|
|
*/
|
|
EXPORT BOOL
|
|
MsgGetUserFeature(const unsigned char *userDN, unsigned char featureRow, unsigned long featureCol, unsigned char *attribute, MDBValueStruct *vOut)
|
|
{
|
|
MDBValueStruct *v;
|
|
unsigned char inheritance = '\0';
|
|
unsigned char parentDN[MDB_MAX_OBJECT_CHARS+1];
|
|
unsigned char configDN[MDB_MAX_OBJECT_CHARS+1];
|
|
const unsigned char *objectDN;
|
|
unsigned long i;
|
|
BOOL looped;
|
|
|
|
v = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
|
|
configDN[0] = '\0';
|
|
MsgGetUserSettingsDN(userDN, configDN, v, FALSE);
|
|
|
|
/* Step 1 */
|
|
if (configDN && MDBRead(configDN, MSGSRV_A_PARENT_OBJECT, v) > 0) {
|
|
/* We have a parent */
|
|
|
|
/* Step 2 */
|
|
strcpy(parentDN, v->Value[0]);
|
|
|
|
if (MDBRead(v->Value[0], MSGSRV_A_FEATURE_INHERITANCE, v) > 0) {
|
|
/* We have a configured inheritance */
|
|
if ((inheritance = v->Value[1][0]) == FEATURE_PARENT_FIRST) {
|
|
objectDN = parentDN;
|
|
} else {
|
|
objectDN = configDN;
|
|
}
|
|
} else {
|
|
/* No inheritance configured */
|
|
objectDN = configDN;
|
|
}
|
|
MDBFreeValues(v);
|
|
} else {
|
|
parentDN[0] = '\0';
|
|
objectDN = configDN;
|
|
}
|
|
|
|
/* objectDN now contains the DN we have determined we need to read first */
|
|
|
|
looped=FALSE;
|
|
|
|
/* Step 3 */
|
|
ReadFeatureAttribute:
|
|
if (MDBRead(objectDN, MSGSRV_A_FEATURE_SET, v) > 0) {
|
|
/* We have features defined on the object */
|
|
for (i = 0; i < v->Used; i++) {
|
|
/* Find our feature */
|
|
if (v->Value[i][0] == featureRow) {
|
|
switch (v->Value[i][featureCol]) {
|
|
case FEATURE_NOT_AVAILABLE: {
|
|
/* Feature disabled; return */
|
|
MDBDestroyValueStruct(v);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
case FEATURE_AVAILABLE: {
|
|
/* Feature enabled */
|
|
i = v->Used;
|
|
break;
|
|
}
|
|
|
|
case FEATURE_USE_PARENT:
|
|
/* Feature enabled via parent */
|
|
case FEATURE_USE_USER: {
|
|
/* Feature enabled via user */
|
|
if (!looped && (parentDN[0] != '\0')) {
|
|
if (objectDN == parentDN) {
|
|
objectDN = configDN;
|
|
} else {
|
|
objectDN = parentDN;
|
|
}
|
|
|
|
MDBFreeValues(v);
|
|
looped=TRUE;
|
|
goto ReadFeatureAttribute;
|
|
} else {
|
|
/* If loop exists, use user object */
|
|
objectDN = configDN;
|
|
i = v->Used;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We now have the DN of the object we need to read the data attribute from in ObjectDN */
|
|
MDBFreeValues(v);
|
|
} else {
|
|
/* We didn't find a feature set configuration */
|
|
if (inheritance == FEATURE_PARENT_FIRST) {
|
|
/* We read the parent, didn't have feature config, let's read the user's feature set */
|
|
inheritance = FEATURE_USER_FIRST;
|
|
objectDN = configDN;
|
|
goto ReadFeatureAttribute;
|
|
} else {
|
|
/* We read the user, don't have inheritance and don't have a feature set -> return enabled feature! */
|
|
goto ReadDataAttribute;
|
|
}
|
|
}
|
|
|
|
ReadDataAttribute:
|
|
/* Beyond this point, we can return success; we returned failure above */
|
|
|
|
/* Clean up */
|
|
MDBDestroyValueStruct(v);
|
|
|
|
/* If Attribute NULL we just check if feature disabled */
|
|
if (!attribute) {
|
|
return(TRUE);
|
|
}
|
|
|
|
return MsgGetUserSetting(configDN, attribute, vOut);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgCleanPath(unsigned char *path)
|
|
{
|
|
unsigned char *ptr;
|
|
unsigned char *ptr2;
|
|
|
|
/* This code strips off any server names that might be configured in the Path */
|
|
ptr = path;
|
|
while((ptr = strchr(ptr, '\\')) != NULL) {
|
|
*ptr = '/';
|
|
}
|
|
|
|
ptr=strchr(path, ':');
|
|
if (ptr) {
|
|
*ptr = '\0';
|
|
ptr2 = strchr(path, '/');
|
|
if (ptr2) {
|
|
*ptr=':';
|
|
memmove(path, ptr2+1, strlen(ptr2+1)+1);
|
|
} else {
|
|
*ptr=':';
|
|
}
|
|
}
|
|
|
|
/* If you want all pathnames lowercase, uncomment the following */
|
|
#if 0
|
|
ptr = path;
|
|
while (*ptr) {
|
|
if (isupper(*ptr)) {
|
|
*ptr = tolower(*ptr);
|
|
}
|
|
ptr++;
|
|
}
|
|
#endif
|
|
|
|
/* strip off trailing /, to allow other code reliable appending of files by using %s/%s */
|
|
ptr = path + strlen(path) - 1;
|
|
if (*ptr == '/') {
|
|
*ptr = '\0';
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
EXPORT void
|
|
MsgMakePath(unsigned char *path)
|
|
{
|
|
unsigned char *ptr = path;
|
|
unsigned char *ptr2;
|
|
struct stat sb;
|
|
|
|
ptr = strchr(path, '/');
|
|
if (!ptr)
|
|
ptr=strchr(path, '\\');
|
|
|
|
while (ptr) {
|
|
*ptr = '\0';
|
|
if (stat(path, &sb) != 0) {
|
|
XplMakeDir(path);
|
|
}
|
|
|
|
*ptr = '/';
|
|
ptr2 = ptr;
|
|
ptr = strchr(ptr2 + 1, '/');
|
|
if (!ptr)
|
|
ptr = strchr(ptr2 + 1, '\\');
|
|
}
|
|
|
|
if (stat(path, &sb) != 0) {
|
|
XplMakeDir(path);
|
|
}
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetDBFDir(char *directory)
|
|
{
|
|
if (directory) {
|
|
strcpy(directory, MsgGlobal.paths.dbf);
|
|
}
|
|
return(MsgGlobal.paths.dbf);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetWorkDir(char *directory)
|
|
{
|
|
if (directory) {
|
|
strcpy(directory, MsgGlobal.paths.work);
|
|
}
|
|
return(MsgGlobal.paths.work);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetNLSDir(char *directory)
|
|
{
|
|
if (directory) {
|
|
strcpy(directory, MsgGlobal.paths.nls);
|
|
}
|
|
return(MsgGlobal.paths.nls);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetBinDir(char *directory)
|
|
{
|
|
if (directory) {
|
|
strcpy(directory, MsgGlobal.paths.bin);
|
|
}
|
|
return(MsgGlobal.paths.bin);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetLibDir(char *directory)
|
|
{
|
|
if (directory) {
|
|
strcpy(directory, MsgGlobal.paths.lib);
|
|
}
|
|
return(MsgGlobal.paths.bin);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetTLSCertPath(char *path)
|
|
{
|
|
if (path) {
|
|
strcpy(path, MsgGlobal.paths.certificate);
|
|
}
|
|
return(MsgGlobal.paths.certificate);
|
|
}
|
|
|
|
EXPORT const unsigned char *
|
|
MsgGetTLSKeyPath(char *path)
|
|
{
|
|
if (path) {
|
|
strcpy(path, MsgGlobal.paths.key);
|
|
}
|
|
return(MsgGlobal.paths.key);
|
|
}
|
|
|
|
EXPORT unsigned long
|
|
MsgGetAgentBindIPAddress(void)
|
|
{
|
|
if ((MsgGlobal.flags & MSGAPI_FLAG_BOUND)) {
|
|
return(MsgGlobal.address.local);
|
|
} else {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
EXPORT unsigned long
|
|
MsgGetHostIPAddress(void)
|
|
{
|
|
return(MsgGlobal.address.local);
|
|
}
|
|
|
|
EXPORT const char *
|
|
MsgGetUnprivilegedUser(void)
|
|
{
|
|
if (BONGO_USER[0] == '\0') {
|
|
return NULL;
|
|
} else {
|
|
return BONGO_USER;
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
LoadContextList(MDBValueStruct *config)
|
|
{
|
|
unsigned char emptyString[] = " ";
|
|
unsigned char storeObjectDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
MDBValueStruct *ports;
|
|
MDBValueStruct *addresses;
|
|
char storePortText[6];
|
|
unsigned long i;
|
|
unsigned long j;
|
|
unsigned long count;
|
|
unsigned long realUsed;
|
|
|
|
ports = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
if (!ports) {
|
|
return(FALSE);
|
|
}
|
|
|
|
addresses = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
if (!addresses) {
|
|
MDBDestroyValueStruct(ports);
|
|
return(FALSE);
|
|
}
|
|
|
|
MDBFreeValues(MsgGlobal.vs.server.names);
|
|
MDBFreeValues(MsgGlobal.vs.server.contexts);
|
|
MDBFreeValues(MsgGlobal.vs.storePaths);
|
|
MDBFreeValues(MsgGlobal.vs.storeDNs);
|
|
if (MsgGlobal.vs.server.addr) {
|
|
MemFree(MsgGlobal.vs.server.addr);
|
|
MsgGlobal.vs.server.addr = NULL;
|
|
}
|
|
|
|
/* This puts the local context always first */
|
|
sprintf(storeObjectDn, "%s\\%s", MsgGlobal.server.dn, MSGSRV_AGENT_STORE);
|
|
if(MDBIsObject(storeObjectDn, MsgGlobal.vs.server.contexts)) {
|
|
MDBReadDN(MsgGlobal.server.dn, MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts);
|
|
if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) {
|
|
strcpy(storePortText, config->Value[0]);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
sprintf(storePortText, "%d", (BONGO_STORE_DEFAULT_PORT));
|
|
}
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
MDBRead(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, addresses);
|
|
MDBAddValue(storePortText, ports);
|
|
MDBAddValue(MsgGlobal.server.dn, MsgGlobal.vs.storeDNs);
|
|
}
|
|
}
|
|
|
|
#ifdef PARENTOBJECT_STORE
|
|
/* Read the parent object store configuration */
|
|
if (MDBEnumerateObjects(MSGSRV_ROOT"\\"MSGSRV_PARENT_ROOT, MSGSRV_C_PARENTOBJECT, &MsgGlobal.vs.parent.objects)) {
|
|
for (i=0; i<MsgGlobal.vs.parent.objects.Used; i++) {
|
|
if (MDBRead(MsgGlobal.vs.parent.objects.Value[i], MSGSRV_A_MESSAGE_STORE, &MsgGlobal.vs.parent.stores)==0) {
|
|
MDBAddValue(EmptyString, &MsgGlobal.vs.parent.stores);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* FIXME: This code turns off distributed automatically if the server is not in internet services */
|
|
/* We might not always want this? */
|
|
#if 0
|
|
if (strstr(storeObjectDn, MSGSRV_ROOT)==NULL) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_STANDALONE;
|
|
}
|
|
#endif
|
|
|
|
if (!(MsgGlobal.flags & MSGAPI_FLAG_STANDALONE)) {
|
|
/* First time around we check all "real" classes */
|
|
if (MDBEnumerateObjects(MSGSRV_ROOT, MSGSRV_C_SERVER, NULL, MsgGlobal.vs.server.names)) {
|
|
/* Put the local context(s) first */
|
|
for (i = 0; i < MsgGlobal.vs.server.names->Used; i++) {
|
|
/* MsgGlobal.server.dn is absolute, MsgGlobal.vs.server.names->Value isn't */
|
|
if (XplStrCaseCmp(MsgGlobal.server.dn + strlen(MsgGlobal.server.dn) - strlen(MsgGlobal.vs.server.names->Value[i]), MsgGlobal.vs.server.names->Value[i]) != 0) {
|
|
count = MsgGlobal.vs.server.contexts->Used;
|
|
if ((MDBRead(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_IP_ADDRESS, addresses) > 0) &&
|
|
(MDBReadDN(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts) > 0)) {
|
|
sprintf(storeObjectDn, "%s\\%s", MsgGlobal.vs.server.names->Value[i], MSGSRV_AGENT_STORE);
|
|
if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) {
|
|
strcpy(storePortText, config->Value[0]);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
sprintf(storePortText, "%d", (BONGO_STORE_DEFAULT_PORT));
|
|
}
|
|
MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs);
|
|
for (j = count + 1; j < MsgGlobal.vs.server.contexts->Used; j++) {
|
|
MDBAddValue(addresses->Value[count], addresses);
|
|
MDBAddValue(storePortText, ports);
|
|
MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now check any aliases that might be in the Internet Services container */
|
|
realUsed = MsgGlobal.vs.server.names->Used;
|
|
if (MDBEnumerateObjects(MSGSRV_ROOT, C_ALIAS, NULL, MsgGlobal.vs.server.names)) {
|
|
unsigned char realDn[MDB_MAX_OBJECT_CHARS + 1];
|
|
unsigned char realType[MDB_MAX_ATTRIBUTE_CHARS + 1];
|
|
|
|
/* Put the local context(s) first */
|
|
for (i = realUsed; i < MsgGlobal.vs.server.names->Used; i++) {
|
|
MDBGetObjectDetails(MsgGlobal.vs.server.names->Value[i], realType, NULL, realDn, MsgGlobal.vs.server.names);
|
|
|
|
/* MsgGlobal.server.dn is absolute, MsgGlobal.vs.server.names->Value isn't */
|
|
if ((XplStrCaseCmp(realType, MSGSRV_C_SERVER) == 0) && (XplStrCaseCmp(MsgGlobal.server.dn + strlen(MsgGlobal.server.dn) - strlen(realDn), realDn) != 0)) {
|
|
count = MsgGlobal.vs.server.contexts->Used;
|
|
if ((MDBRead(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_IP_ADDRESS, addresses) > 0) &&
|
|
(MDBReadDN(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts) > 0)) {
|
|
sprintf(storeObjectDn, "%s\\%s", MsgGlobal.vs.server.names->Value[i], MSGSRV_AGENT_STORE);
|
|
if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) {
|
|
strcpy(storePortText, config->Value[0]);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
sprintf(storePortText, "%d", BONGO_STORE_DEFAULT_PORT);
|
|
}
|
|
MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs);
|
|
for (j = count + 1; j < MsgGlobal.vs.server.contexts->Used; j++) {
|
|
MDBAddValue(addresses->Value[count], addresses);
|
|
MDBAddValue(storePortText, ports);
|
|
MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* MDBAddValue doesn't add empty values, so fake it */
|
|
/* with a ^A in the string */
|
|
emptyString[0]=EMPTY_CHAR;
|
|
/* Now read all the store path values */
|
|
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
if (MDBRead(MsgGlobal.vs.server.contexts->Value[i], MSGSRV_A_MESSAGE_STORE, MsgGlobal.vs.storePaths) == 0) {
|
|
/* Add an empty string, no context store specified */
|
|
MDBAddValue(emptyString, MsgGlobal.vs.storePaths);
|
|
} else {
|
|
MsgCleanPath(MsgGlobal.vs.storePaths->Value[i]);
|
|
}
|
|
}
|
|
|
|
/* Initialize addr structure for each context */
|
|
MsgGlobal.vs.server.addr = MemMalloc0(MsgGlobal.vs.server.contexts->Used * sizeof(struct sockaddr_in));
|
|
if (!MsgGlobal.vs.server.addr) {
|
|
MDBDestroyValueStruct(ports);
|
|
return(FALSE);
|
|
}
|
|
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
MsgGlobal.vs.server.addr[i].sin_addr.s_addr = inet_addr(addresses->Value[i]);
|
|
MsgGlobal.vs.server.addr[i].sin_port = htons(atol(ports->Value[i]));
|
|
MsgGlobal.vs.server.addr[i].sin_family = AF_INET;
|
|
}
|
|
|
|
|
|
#if 0
|
|
for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) {
|
|
XplConsolePrintf("\rCtx:%-35s IP:%-15s Path:%s\n", MsgGlobal.vs.server.contexts->Value[i], addresses->Value[i], MsgGlobal.vs.storePaths->Value[i]);
|
|
XplConsolePrintf("\rDN :%-35s\n\n", MsgGlobal.vs.storeDNs->Value[i]);
|
|
}
|
|
#endif
|
|
|
|
MDBDestroyValueStruct(addresses);
|
|
MDBDestroyValueStruct(ports);
|
|
return(TRUE);
|
|
}
|
|
|
|
static void
|
|
MsgConfigMonitor(void)
|
|
{
|
|
MDBValueStruct *config;
|
|
unsigned long i;
|
|
long prevConfigNumber = 0;
|
|
struct tm *timeStruct;
|
|
time_t utcTime;
|
|
long tmp;
|
|
|
|
MsgGlobal.flags |= MSGAPI_FLAG_MONITOR_RUNNING;
|
|
|
|
XplRenameThread(XplGetThreadID(), "MsgAPI Config Monitor");
|
|
|
|
config = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
if (!config) {
|
|
printf("WARNING: MsgConfigMonitor() couldn't create value struct: directory handle %p\n",
|
|
MsgGlobal.directoryHandle);
|
|
return;
|
|
}
|
|
|
|
if (MDBRead(MSGSRV_ROOT, MSGSRV_A_CONFIG_CHANGED, config) > 0) {
|
|
prevConfigNumber = atol(config->Value[0]);
|
|
}
|
|
|
|
while (!(MsgGlobal.flags & MSGAPI_FLAG_EXITING)) {
|
|
for (i = 0; (i < 300) && !(MsgGlobal.flags & MSGAPI_FLAG_EXITING); i++) {
|
|
XplDelay(1000);
|
|
}
|
|
|
|
/* Get Server Time Zone Offset */
|
|
tzset();
|
|
utcTime = time(NULL);
|
|
timeStruct = localtime(&utcTime);
|
|
if (timeStruct) {
|
|
tmp = (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60;
|
|
timeStruct = gmtime(&utcTime);
|
|
tmp -= (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60;
|
|
MsgDateSetUTCOffset(tmp);
|
|
}
|
|
|
|
MDBFreeValues(config);
|
|
|
|
if (!(MsgGlobal.flags & MSGAPI_FLAG_EXITING) && (MDBRead(MSGSRV_ROOT, MSGSRV_A_CONFIG_CHANGED, config)>0) && (atol(config->Value[0]) != prevConfigNumber)) {
|
|
/* Clear what we just read */
|
|
prevConfigNumber = atol(config->Value[0]);
|
|
MDBFreeValues(config);
|
|
|
|
/* Acquire Write Lock */
|
|
XplRWWriteLockAcquire(&MsgGlobal.configLock);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_CONNMGR_CONFIG, config)) {
|
|
if (atoi(config->Value[0]) == 1) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_SUPPORT_CONNMGR;
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MsgReadIP(MsgGlobal.server.dn, MSGSRV_A_CONNMGR, config)) {
|
|
MsgGlobal.connManager = inet_addr(config->Value[0]);
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
LoadContextList(config);
|
|
|
|
XplRWWriteLockRelease(&MsgGlobal.configLock);
|
|
}
|
|
}
|
|
MDBDestroyValueStruct(config);
|
|
|
|
MsgGlobal.flags &= ~MSGAPI_FLAG_MONITOR_RUNNING;
|
|
|
|
XplExitThread(TSR_THREAD, 0);
|
|
}
|
|
|
|
static BOOL
|
|
MsgLibraryStop(void)
|
|
{
|
|
while (MsgGlobal.flags & MSGAPI_FLAG_MONITOR_RUNNING) {
|
|
XplDelay(1000);
|
|
}
|
|
|
|
MDBDestroyValueStruct(MsgGlobal.vs.storeDNs);
|
|
MDBDestroyValueStruct(MsgGlobal.vs.storePaths);
|
|
MDBDestroyValueStruct(MsgGlobal.vs.server.contexts);
|
|
MDBDestroyValueStruct(MsgGlobal.vs.server.names);
|
|
if (MsgGlobal.vs.server.addr) {
|
|
MemFree(MsgGlobal.vs.server.addr);
|
|
MsgGlobal.vs.server.addr = NULL;
|
|
}
|
|
|
|
|
|
#ifdef PARENTOBJECT_STORE
|
|
MDBDestroyValueStruct(MsgGlobal.vs.parent.stores);
|
|
MDBDestroyValueStruct(MsgGlobal.vs.parent.objects);
|
|
#endif
|
|
|
|
if (MsgGlobal.cache.handle) {
|
|
MsgGlobal.cache.shutdown();
|
|
|
|
XplReleaseDLLFunction(MsgGlobal.cache.fileName, "MsgGlobal.cache.init", MsgGlobal.cache.handle);
|
|
XplReleaseDLLFunction(MsgGlobal.cache.fileName, "MsgGlobal.cache.shutdown", MsgGlobal.cache.handle);
|
|
XplReleaseDLLFunction(MsgGlobal.cache.fileName, "FindObjectCache", MsgGlobal.cache.handle);
|
|
XplReleaseDLLFunction(MsgGlobal.cache.fileName, "FindObjectStoreCache", MsgGlobal.cache.handle);
|
|
|
|
XplUnloadDLL(MsgGlobal.cache.fileName, MsgGlobal.cache.handle);
|
|
}
|
|
|
|
XplRWLockDestroy(&MsgGlobal.configLock);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/**
|
|
* Get a config property from global configuration file. Removes dependency
|
|
* on NCPServer object in the directory (as well as others). See msgapi.h for
|
|
* possible properties.
|
|
*/
|
|
BOOL
|
|
MsgGetConfigProperty(unsigned char *Buffer, unsigned char *Property)
|
|
{
|
|
int result = FALSE;
|
|
char line[512];
|
|
char *ptr;
|
|
FILE *fh;
|
|
int len;
|
|
char conf_path[FILENAME_MAX];
|
|
|
|
snprintf(conf_path, FILENAME_MAX, "%s/%s", XPL_DEFAULT_CONF_DIR,
|
|
MSGSRV_CONFIG_FILENAME);
|
|
|
|
if (!(fh = fopen(conf_path, "r"))) {
|
|
return result;
|
|
}
|
|
|
|
while (fgets(line, 512, fh)) {
|
|
if (line[0] != '#') {
|
|
if ((ptr = strchr(line, '='))) {
|
|
*ptr++ = '\0';
|
|
len = strlen(ptr);
|
|
|
|
if (!strcmp(line, Property)) {
|
|
if (ptr[len - 1] == '\n') {
|
|
ptr[len - 1] = '\0';
|
|
}
|
|
|
|
strncpy(Buffer, ptr, MSGSRV_CONFIG_MAX_PROP_CHARS);
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fh);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
MsgGetUid(char *buffer, int buflen)
|
|
{
|
|
static int serial = 0;
|
|
static char hostname[512] = "";
|
|
int thisSerial;
|
|
|
|
XplMutexLock(MsgGlobal.sem.uid);
|
|
|
|
if (hostname[0] == '\0') {
|
|
if ((gethostname(hostname, sizeof(hostname) - 1) != 0) ||
|
|
hostname[0] == '\0') {
|
|
strcpy(hostname, "localhost");
|
|
}
|
|
}
|
|
|
|
thisSerial = serial++;
|
|
|
|
XplMutexUnlock(MsgGlobal.sem.uid);
|
|
|
|
snprintf(buffer, buflen, "%lu.%lu.%d@%s",
|
|
(unsigned long) time(NULL),
|
|
(unsigned long) getpid(),
|
|
thisSerial,
|
|
hostname);
|
|
}
|
|
|
|
static BOOL
|
|
MsgLibraryStart(void)
|
|
{
|
|
unsigned long i;
|
|
struct sockaddr_in server_sockaddr;
|
|
unsigned char path[XPL_MAX_PATH + 1];
|
|
MDBValueStruct *config;
|
|
XplThreadID ID;
|
|
|
|
/* Prepare later config updates */
|
|
XplRWLockInit(&MsgGlobal.configLock);
|
|
|
|
/* Read generic configuration info */
|
|
config = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_CONNMGR_CONFIG, config)) {
|
|
if (atoi(config->Value[0]) == 1) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_SUPPORT_CONNMGR;
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_CERTIFICATE_LOCATION, config)) {
|
|
strcpy(MsgGlobal.paths.certificate, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.certificate);
|
|
} else {
|
|
if (MDBRead(MSGSRV_ROOT, MSGSRV_A_CERTIFICATE_LOCATION, config)) {
|
|
strcpy(MsgGlobal.paths.certificate, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.certificate);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.certificate, XPL_DEFAULT_CERT_PATH);
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_PRIVATE_KEY_LOCATION, config)) {
|
|
strcpy(MsgGlobal.paths.key, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.key);
|
|
} else {
|
|
if (MDBRead(MSGSRV_ROOT, MSGSRV_A_PRIVATE_KEY_LOCATION, config)) {
|
|
strcpy(MsgGlobal.paths.key, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.key);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.key, XPL_DEFAULT_KEY_PATH);
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_CLUSTERED, config)>0) {
|
|
if (atol (config->Value[0])) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_CLUSTERED;
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_FORCE_BIND, config)>0) {
|
|
if (atol (config->Value[0])) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_BOUND;
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
if (!(MsgGlobal.flags & MSGAPI_FLAG_CLUSTERED)) {
|
|
MsgGlobal.flags &= ~MSGAPI_FLAG_BOUND;
|
|
}
|
|
/* Config is free'd further down */
|
|
MDBFreeValues(config);
|
|
|
|
/* Read "context" related stuff */
|
|
|
|
MsgGlobal.vs.server.names = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
MsgGlobal.vs.server.contexts = MDBShareContext(MsgGlobal.vs.server.names);
|
|
MsgGlobal.vs.storePaths = MDBShareContext(MsgGlobal.vs.server.names);
|
|
MsgGlobal.vs.storeDNs = MDBShareContext(MsgGlobal.vs.server.names);
|
|
MsgGlobal.vs.server.addr = NULL;
|
|
|
|
#ifdef PARENTOBJECT_STORE
|
|
MsgGlobal.vs.parent.objects = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
MsgGlobal.vs.parent.stores = MDBShareContext(MsgGlobal.vs.parent.objects);
|
|
#endif
|
|
|
|
server_sockaddr.sin_addr.s_addr=XplGetHostIPAddress();
|
|
sprintf(MsgGlobal.address.string,"%d.%d.%d.%d",
|
|
server_sockaddr.sin_addr.s_net,
|
|
server_sockaddr.sin_addr.s_host,
|
|
server_sockaddr.sin_addr.s_lh,
|
|
server_sockaddr.sin_addr.s_impno);
|
|
|
|
MDBAddValue(MsgGlobal.address.string, MsgGlobal.vs.server.names);
|
|
if (!(MsgGlobal.flags & MSGAPI_FLAG_CLUSTERED)) {
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, MsgGlobal.vs.server.names);
|
|
} else {
|
|
MDBFreeValues(MsgGlobal.vs.server.names);
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, MsgGlobal.vs.server.names)>0) {
|
|
strcpy(MsgGlobal.address.string, MsgGlobal.vs.server.names->Value[0]);
|
|
}
|
|
}
|
|
|
|
MDBFreeValues(MsgGlobal.vs.server.names);
|
|
MsgGlobal.address.local = inet_addr(MsgGlobal.address.string);
|
|
|
|
/* This stuff is here to prevent a catch-22 with the IP address configuration above */
|
|
if (MsgReadIP(MsgGlobal.server.dn, MSGSRV_A_CONNMGR, config)) {
|
|
MsgGlobal.connManager = inet_addr(config->Value[0]);
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
LoadContextList(config);
|
|
|
|
MDBDestroyValueStruct(config);
|
|
|
|
XplBeginThread(&ID, MsgConfigMonitor, 32767, NULL, i);
|
|
|
|
/* Attempt to load the plugable cache mechanism */
|
|
sprintf(MsgGlobal.cache.fileName, "%s%s", MsgGlobal.cache.moduleName, XPL_DLL_EXTENSION);
|
|
sprintf(path, "%s/%s", XPL_DEFAULT_BIN_DIR, MsgGlobal.cache.fileName);
|
|
|
|
MsgGlobal.cache.handle = XplLoadDLL(path);
|
|
if (MsgGlobal.cache.handle != NULL) {
|
|
MsgGlobal.cache.init = (FindObjectCacheInitType)XplGetDLLFunction(MsgGlobal.cache.fileName, "MsgGlobal.cache.init", MsgGlobal.cache.handle);
|
|
MsgGlobal.cache.shutdown = (FindObjectCacheShutdownType)XplGetDLLFunction(MsgGlobal.cache.fileName, "MsgGlobal.cache.shutdown", MsgGlobal.cache.handle);
|
|
MsgGlobal.cache.find = (FindObjectCacheType)XplGetDLLFunction(MsgGlobal.cache.fileName, "FindObjectCache", MsgGlobal.cache.handle);
|
|
MsgGlobal.cache.findEx = (FindObjectCacheExType)XplGetDLLFunction(MsgGlobal.cache.fileName, "FindObjectExCache", MsgGlobal.cache.handle);
|
|
MsgGlobal.cache.store = (FindObjectStoreCacheType)XplGetDLLFunction(MsgGlobal.cache.fileName, "FindObjectStoreCache", MsgGlobal.cache.handle);
|
|
|
|
if (!MsgGlobal.cache.init || !MsgGlobal.cache.shutdown || !MsgGlobal.cache.find || !MsgGlobal.cache.findEx || !MsgGlobal.cache.store) {
|
|
MsgGlobal.cache.init = NULL;
|
|
MsgGlobal.cache.shutdown = NULL;
|
|
MsgGlobal.cache.find = NULL;
|
|
MsgGlobal.cache.findEx = NULL;
|
|
MsgGlobal.cache.store = NULL;
|
|
}
|
|
|
|
if (MsgGlobal.cache.init) {
|
|
MSGCacheInitStruct initData;
|
|
|
|
initData.DirectoryHandle = MsgGlobal.directoryHandle;
|
|
initData.ServerContexts = MsgGlobal.vs.server.contexts;
|
|
initData.ServerAddr = MsgGlobal.vs.server.addr;
|
|
initData.StorePath = MsgGlobal.vs.storePaths;
|
|
initData.ConfigLock = &MsgGlobal.configLock;
|
|
initData.DefaultFindObject = MsgFindObject;
|
|
initData.DefaultFindObjectEx = MsgFindObjectEx;
|
|
initData.DefaultFindObjectStore = MsgFindUserStore;
|
|
initData.DefaultPathChar = EMPTY_CHAR;
|
|
|
|
if (!MsgGlobal.cache.init(&initData, path)) {
|
|
MsgGlobal.cache.init = NULL;
|
|
MsgGlobal.cache.shutdown = NULL;
|
|
MsgGlobal.cache.find = NULL;
|
|
MsgGlobal.cache.findEx = NULL;
|
|
MsgGlobal.cache.store = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
MDBHandle
|
|
MsgGetSystemDirectoryHandle(void)
|
|
{
|
|
MDBHandle systemHandle;
|
|
unsigned char buffer[XPL_MAX_PATH + 1];
|
|
unsigned char credential[128];
|
|
FILE *eclients;
|
|
|
|
memset(credential, 0, sizeof(credential));
|
|
|
|
sprintf(buffer, "%s/eclients.dat", XPL_DEFAULT_DBF_DIR);
|
|
eclients = fopen(buffer, "rb");
|
|
if (eclients) {
|
|
fread(credential, sizeof(unsigned char), sizeof(credential), eclients);
|
|
|
|
fclose(eclients);
|
|
eclients = NULL;
|
|
} else {
|
|
XplConsolePrintf("Insufficient privileges; shutting down.\n");
|
|
return(NULL);
|
|
}
|
|
|
|
if (!MsgGetConfigProperty(MsgGlobal.server.dn,
|
|
MSGSRV_CONFIG_PROP_MESSAGING_SERVER)) {
|
|
XplConsolePrintf("Messaging server not configured. Shutdown.\n");
|
|
return(NULL);
|
|
}
|
|
|
|
systemHandle = MDBAuthenticate("Bongo", MsgGlobal.server.dn, credential);
|
|
if (systemHandle == NULL) {
|
|
XplConsolePrintf("Messaging server credentials are invalid; shutting down.\n");
|
|
return(NULL);
|
|
}
|
|
|
|
return(systemHandle);
|
|
}
|
|
|
|
BOOL
|
|
MsgGetBuildVersion(int *version, BOOL *custom)
|
|
{
|
|
/* Get the version of this build of bongo.
|
|
* version - what SVN rev or branch minor this is
|
|
* custom - whether or not this is a custom build
|
|
*/
|
|
int len = 0;
|
|
char *ptr = BONGO_BUILD_VER;
|
|
|
|
*version = strtol(ptr, NULL, 10);
|
|
len = strlen(ptr);
|
|
|
|
*custom = FALSE;
|
|
if (ptr[len] == 'M') *custom = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MsgGetAvailableVersion(int *version)
|
|
{
|
|
/* Get the information about latest version of bongo available
|
|
* version - what SVN rev or branch minor is available
|
|
*/
|
|
char record[500];
|
|
char *ptr;
|
|
int v;
|
|
|
|
if (!MsgGetUpdateStatus(record, 499))
|
|
return FALSE;
|
|
|
|
ptr = strchr(record, '|');
|
|
if (ptr == NULL) return FALSE;
|
|
|
|
*version = strtol(record, &ptr, 10);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MsgGetUpdateStatus(char *record, int record_length)
|
|
{
|
|
char *branch = BONGO_BUILD_BRANCH;
|
|
char *zone = "revisions.bongo-project.com";
|
|
char hostname[256];
|
|
XplDnsRecord *result = NULL;
|
|
int status;
|
|
|
|
snprintf(hostname, 255, "%s.%s", branch, zone);
|
|
|
|
status = XplDnsResolve(hostname, &result, XPL_RR_TXT);
|
|
switch(status) {
|
|
case XPL_DNS_SUCCESS:
|
|
snprintf(record, record_length, "%s", result[0].TXT.txt);
|
|
MemFree(result);
|
|
return TRUE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
MsgReadConfiguration(void)
|
|
{
|
|
MDBValueStruct *config;
|
|
unsigned long i;
|
|
struct tm *timeStruct;
|
|
time_t utcTime;
|
|
long tmp;
|
|
|
|
/* Get Server Time Zone Offset */
|
|
tzset();
|
|
utcTime = time(NULL);
|
|
timeStruct = localtime(&utcTime);
|
|
if (timeStruct) {
|
|
tmp = (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60;
|
|
timeStruct = gmtime(&utcTime);
|
|
tmp -= (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60;
|
|
|
|
MsgDateSetUTCOffset(tmp);
|
|
}
|
|
|
|
/* Read operating parameters, this is so complicated because in version 2.5
|
|
* we changed the configuration of directories - before 2.5 we would always
|
|
* append novonyx/mail to any given path, now we don't. The code tries to
|
|
* automatically detect pre2.5 installs and change the DS attribute...
|
|
*/
|
|
|
|
config = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
|
|
if (!config) {
|
|
XplConsolePrintf("Messaging server out of memory; shutting down.\n");
|
|
MDBRelease(MsgGlobal.directoryHandle);
|
|
MsgGlobal.directoryHandle = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_NLS_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.nls, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.nls);
|
|
MsgMakePath(MsgGlobal.paths.nls);
|
|
MDBFreeValues(config);
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_DBF_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.dbf, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.dbf);
|
|
MsgMakePath(MsgGlobal.paths.dbf);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.dbf, XPL_DEFAULT_DBF_DIR);
|
|
MsgMakePath(MsgGlobal.paths.dbf);
|
|
}
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_BIN_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.bin, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.bin);
|
|
MsgMakePath(MsgGlobal.paths.bin);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.bin, XPL_DEFAULT_BIN_DIR);
|
|
MsgMakePath(MsgGlobal.paths.bin);
|
|
}
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_LIB_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.lib, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.lib);
|
|
MsgMakePath(MsgGlobal.paths.lib);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.lib, XPL_DEFAULT_LIB_DIR);
|
|
MsgMakePath(MsgGlobal.paths.lib);
|
|
}
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_WORK_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.work, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.work);
|
|
MsgMakePath(MsgGlobal.paths.work);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.work, XPL_DEFAULT_WORK_DIR);
|
|
MsgMakePath(MsgGlobal.paths.work);
|
|
}
|
|
} else {
|
|
strcpy(MsgGlobal.paths.dbf, XPL_DEFAULT_DBF_DIR);
|
|
MsgMakePath(MsgGlobal.paths.dbf);
|
|
MDBAddValue(MsgGlobal.paths.dbf, config);
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_DBF_DIRECTORY, config);
|
|
MDBFreeValues(config);
|
|
|
|
strcpy(MsgGlobal.paths.nls, XPL_DEFAULT_NLS_DIR);
|
|
MsgMakePath(MsgGlobal.paths.nls);
|
|
MDBAddValue(MsgGlobal.paths.nls, config);
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_NLS_DIRECTORY, config);
|
|
MDBFreeValues(config);
|
|
|
|
strcpy(MsgGlobal.paths.bin, XPL_DEFAULT_BIN_DIR);
|
|
MsgMakePath(MsgGlobal.paths.bin);
|
|
MDBAddValue(MsgGlobal.paths.bin, config);
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_BIN_DIRECTORY, config);
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_WORK_DIRECTORY, config)) {
|
|
strcpy(MsgGlobal.paths.work, config->Value[0]);
|
|
MsgCleanPath(MsgGlobal.paths.work);
|
|
strcat(MsgGlobal.paths.work, "/novonyx/mail");
|
|
MsgMakePath(MsgGlobal.paths.work);
|
|
MDBFreeValues(config);
|
|
|
|
MDBAddValue(MsgGlobal.paths.work, config);
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_WORK_DIRECTORY, config);
|
|
MDBFreeValues(config);
|
|
} else {
|
|
strcpy(MsgGlobal.paths.work, XPL_DEFAULT_WORK_DIR);
|
|
MsgMakePath(MsgGlobal.paths.work);
|
|
MDBAddValue(MsgGlobal.paths.work, config);
|
|
MDBWrite(MsgGlobal.server.dn, MSGSRV_A_WORK_DIRECTORY, config);
|
|
MDBFreeValues(config);
|
|
}
|
|
}
|
|
|
|
/* Official Name */
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_OFFICIAL_NAME, config)) {
|
|
strcpy(MsgGlobal.official.domain, config->Value[0]);
|
|
MsgGlobal.official.domainLength = strlen(MsgGlobal.official.domain);
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_CONFIGURATION, config)) {
|
|
for (i = 0; i < config->Used; i++) {
|
|
if (XplStrNCaseCmp(config->Value[i], "FindObjectModule=", 17) == 0) {
|
|
strcpy(MsgGlobal.cache.moduleName, config->Value[i]+17);
|
|
} else if (XplStrNCaseCmp(config->Value[i], "IgnoreInternetEmailAddressAttribute", 35) == 0) {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_INTERNET_EMAIL_ADDRESS;
|
|
}
|
|
}
|
|
}
|
|
MDBFreeValues(config);
|
|
|
|
if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_SERVER_STANDALONE, config)) {
|
|
if (config->Value[0][0]=='1') {
|
|
MsgGlobal.flags |= MSGAPI_FLAG_STANDALONE;
|
|
}
|
|
}
|
|
MDBDestroyValueStruct(config);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
static int
|
|
MsgLibraryInit(void)
|
|
{
|
|
MsgGlobal.flags = 0;
|
|
|
|
XplSafeWrite(MsgGlobal.useCount, 0);
|
|
|
|
MsgGlobal.groupID = XplGetThreadGroupID();
|
|
|
|
MsgGlobal.directoryHandle = NULL;
|
|
|
|
MsgGlobal.connManager = 0x0100007F;
|
|
|
|
strcpy(MsgGlobal.cache.moduleName, "msgcache");
|
|
MsgGlobal.cache.init = NULL;
|
|
MsgGlobal.cache.shutdown = NULL;
|
|
MsgGlobal.cache.find = NULL;
|
|
MsgGlobal.cache.findEx = NULL;
|
|
MsgGlobal.cache.store = NULL;
|
|
|
|
MsgGlobal.official.domain[0] = '\0';
|
|
MsgGlobal.official.domainLength = 0;
|
|
|
|
XplOpenLocalSemaphore(MsgGlobal.sem.shutdown, 0);
|
|
XplMutexInit(MsgGlobal.sem.uid);
|
|
|
|
MemoryManagerOpen(NULL);
|
|
|
|
if (!MDBInit()) {
|
|
MemoryManagerClose(NULL);
|
|
return 0;
|
|
}
|
|
|
|
MsgGlobal.directoryHandle = MsgGetSystemDirectoryHandle();
|
|
if (!(MsgGlobal.directoryHandle)) {
|
|
MemoryManagerClose(NULL);
|
|
return 0;
|
|
}
|
|
|
|
if (!MsgReadConfiguration()) {
|
|
XplConsolePrintf("Cannot read configuration. Shutting down.\n");
|
|
|
|
MemoryManagerClose(NULL);
|
|
|
|
return(0);
|
|
}
|
|
|
|
MsgResolveStart();
|
|
MsgLibraryStart();
|
|
MsgDateStart();
|
|
|
|
if (curl_global_init(CURL_GLOBAL_ALL)) {
|
|
XplConsolePrintf("Could not initialize curl.\r\n");
|
|
return 0;
|
|
}
|
|
|
|
MSGAPIState = LIBRARY_RUNNING;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
MsgLibraryShutdown(void)
|
|
{
|
|
XplThreadID oldGid;
|
|
|
|
if (MSGAPIState == LIBRARY_RUNNING) {
|
|
MSGAPIState = LIBRARY_SHUTTING_DOWN;
|
|
|
|
MsgGlobal.flags |= MSGAPI_FLAG_EXITING;
|
|
|
|
oldGid = XplSetThreadGroupID(MsgGlobal.groupID);
|
|
|
|
MsgResolveStop();
|
|
MsgLibraryStop();
|
|
|
|
MemoryManagerClose(NULL);
|
|
|
|
MSGAPIState = LIBRARY_SHUTDOWN;
|
|
|
|
XplSetThreadGroupID(oldGid);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
MDBHandle
|
|
MsgDirectoryHandle(void)
|
|
{
|
|
return(MsgGlobal.directoryHandle);
|
|
}
|
|
|
|
BOOL
|
|
MsgResolveStart(void)
|
|
{
|
|
MDBValueStruct *config;
|
|
unsigned long i;
|
|
|
|
if (!XplResolveStart()) {
|
|
return FALSE;
|
|
}
|
|
|
|
config = MDBCreateValueStruct(MsgDirectoryHandle(), NULL);
|
|
if (MDBRead(MsgGetServerDN(NULL), MSGSRV_A_RESOLVER, config) > 0) {
|
|
for (i = 0; i < config->Used; i++) {
|
|
XplDnsAddResolver(config->Value[i]);
|
|
/* XplConsolePrintf("[%04d] MSGSRV_A_RESOLVER:%s", __LINE__, config->Value[i]);*/
|
|
}
|
|
} else {
|
|
MDBSetValueStructContext(MsgGetServerDN(NULL), config);
|
|
if (MDBRead(MSGSRV_AGENT_SMTP, MSGSRV_A_RESOLVER, config)>0) {
|
|
for (i = 0; i < config->Used; i++) {
|
|
XplDnsAddResolver(config->Value[i]);
|
|
/* XplConsolePrintf("[%04d] MSGSRV_A_RESOLVER:%s", __LINE__, config->Value[i]);*/
|
|
}
|
|
MDBSetValueStructContext(NULL, config);
|
|
MDBWrite(MsgGetServerDN(NULL), MSGSRV_A_RESOLVER, config);
|
|
}
|
|
}
|
|
MDBDestroyValueStruct(config);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
MsgResolveStop(void)
|
|
{
|
|
return XplResolveStop();
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MsgExiting(void)
|
|
{
|
|
if (MsgGlobal.flags & MSGAPI_FLAG_EXITING) {
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgShutdown(void)
|
|
{
|
|
XplSafeDecrement(MsgGlobal.useCount);
|
|
|
|
if (XplSafeRead(MsgGlobal.useCount) > 0) {
|
|
return(FALSE);
|
|
}
|
|
|
|
MsgLibraryShutdown();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
EXPORT MDBHandle
|
|
MsgInit(void)
|
|
{
|
|
if (MSGAPIState == LIBRARY_LOADED) {
|
|
MSGAPIState = LIBRARY_INITIALIZING;
|
|
|
|
if (!MsgLibraryInit()) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
while (MSGAPIState < LIBRARY_RUNNING) {
|
|
XplDelay(100);
|
|
}
|
|
|
|
if (MSGAPIState == LIBRARY_RUNNING) {
|
|
XplSafeIncrement(MsgGlobal.useCount);
|
|
}
|
|
|
|
return((MSGAPIState == LIBRARY_RUNNING) ? MsgGlobal.directoryHandle : NULL);
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgSetRecoveryFlag(void)
|
|
{
|
|
// FIXME: TODO :)
|
|
return FALSE;
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgGetRecoveryFlag(void)
|
|
{
|
|
// FIXME: TODO :)
|
|
return FALSE;
|
|
}
|
|
|
|
EXPORT BOOL
|
|
MsgGetServerCredential(char *buffer)
|
|
{
|
|
MDBValueStruct *v;
|
|
|
|
if (MsgGlobal.directoryHandle) {
|
|
v = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL);
|
|
if (v) {
|
|
MDBRead(MSGSRV_ROOT, MSGSRV_A_ACL, v);
|
|
if (v->Used) {
|
|
HashCredential(MsgGlobal.server.dn, v->Value[0], buffer);
|
|
}
|
|
MDBDestroyValueStruct(v);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|