1758 lines
57 KiB
C
1758 lines
57 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>
|
|
****************************************************************************/
|
|
|
|
#include <config.h>
|
|
|
|
#include <xpl.h>
|
|
#include <memmgr.h>
|
|
#include <logger.h>
|
|
#include <bongoutil.h>
|
|
#include <nmap.h>
|
|
#include <nmlib.h>
|
|
#include <msgapi.h>
|
|
#include <connio.h>
|
|
|
|
#include "pluspack.h"
|
|
|
|
#if defined(RELEASE_BUILD)
|
|
#define PlusPackClientAlloc() MemPrivatePoolGetEntry(PlusPack.nmap.pool)
|
|
#else
|
|
#define PlusPackClientAlloc() MemPrivatePoolGetEntryDebug(PlusPack.nmap.pool, __FILE__, __LINE__)
|
|
#endif
|
|
|
|
static void SignalHandler(int sigtype);
|
|
|
|
#define QUEUE_WORK_TO_DO(c, id, r) \
|
|
{ \
|
|
XplWaitOnLocalSemaphore(PlusPack.nmap.semaphore); \
|
|
if (XplSafeRead(PlusPack.nmap.queue.idle)) { \
|
|
(c)->queue.previous = NULL; \
|
|
if (((c)->queue.next = PlusPack.nmap.queue.head) != NULL) { \
|
|
(c)->queue.next->queue.previous = (c); \
|
|
} else { \
|
|
PlusPack.nmap.queue.tail = (c); \
|
|
} \
|
|
PlusPack.nmap.queue.head = (c); \
|
|
(r) = 0; \
|
|
} else { \
|
|
XplSafeIncrement(PlusPack.nmap.queue.active); \
|
|
XplSignalBlock(); \
|
|
XplBeginThread(&(id), HandleConnection, 24 * 1024, XPL_INT_TO_PTR(XplSafeRead(PlusPack.nmap.queue.active)), (r)); \
|
|
XplSignalHandler(SignalHandler); \
|
|
if (!(r)) { \
|
|
(c)->queue.previous = NULL; \
|
|
if (((c)->queue.next = PlusPack.nmap.queue.head) != NULL) { \
|
|
(c)->queue.next->queue.previous = (c); \
|
|
} else { \
|
|
PlusPack.nmap.queue.tail = (c); \
|
|
} \
|
|
PlusPack.nmap.queue.head = (c); \
|
|
} else { \
|
|
XplSafeDecrement(PlusPack.nmap.queue.active); \
|
|
(r) = -1; \
|
|
} \
|
|
} \
|
|
XplSignalLocalSemaphore(PlusPack.nmap.semaphore); \
|
|
}
|
|
|
|
PlusPackGlobals PlusPack;
|
|
|
|
static BOOL
|
|
PlusPackClientAllocCB(void *buffer, void *data)
|
|
{
|
|
register PlusPackClient *c = (PlusPackClient *)buffer;
|
|
|
|
memset(c, 0, sizeof(PlusPackClient));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
static void
|
|
PlusPackClientFree(PlusPackClient *client)
|
|
{
|
|
register PlusPackClient *c = client;
|
|
|
|
if (c->conn) {
|
|
ConnClose(c->conn, 1);
|
|
ConnFree(c->conn);
|
|
c->conn = NULL;
|
|
}
|
|
|
|
MemPrivatePoolReturnEntry(c);
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
FreeClientData(PlusPackClient *client)
|
|
{
|
|
if (client && !(client->flags & PLUSPACK_CLIENT_FLAG_EXITING)) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_EXITING;
|
|
|
|
if (client->conn) {
|
|
ConnClose(client->conn, 1);
|
|
ConnFree(client->conn);
|
|
client->conn = NULL;
|
|
}
|
|
|
|
if (client->vs) {
|
|
MDBDestroyValueStruct(client->vs);
|
|
client->vs = NULL;
|
|
}
|
|
|
|
if (client->envelope.data) {
|
|
MemFree(client->envelope.data);
|
|
client->envelope.data = NULL;
|
|
client->envelope.length = 0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static int
|
|
ProcessConnection(PlusPackClient *client)
|
|
{
|
|
int ccode;
|
|
unsigned char preserve;
|
|
unsigned char *cur;
|
|
unsigned char *ptr;
|
|
unsigned char *eol;
|
|
unsigned char *line;
|
|
MDBValueStruct *vs;
|
|
|
|
preserve = '\0';
|
|
|
|
if (((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) != -1)
|
|
&& (ccode == 6020)
|
|
&& ((ptr = strchr(client->line, ' ')) != NULL)
|
|
&& (client->line[3] == '-')) {
|
|
*ptr++ = '\0';
|
|
|
|
strcpy(client->entry.name, client->line);
|
|
|
|
client->line[3] = '\0';
|
|
client->entry.queue = atol(client->line);
|
|
client->entry.id = atol(client->line + 4);
|
|
|
|
client->envelope.length = atoi(ptr);
|
|
client->envelope.data = MemMalloc(client->envelope.length + 3);
|
|
vs = MDBCreateValueStruct(PlusPack.handle.directory, NULL);
|
|
} else {
|
|
NMAPSendCommand(client->conn, "QDONE\r\n", 7);
|
|
NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
return(-1);
|
|
}
|
|
|
|
if (client->envelope.data && vs) {
|
|
sprintf(client->line, "PlusPack: %s", client->entry.name);
|
|
XplRenameThread(XplGetThreadID(), client->line);
|
|
|
|
ccode = NMAPReadCount(client->conn, client->envelope.data, client->envelope.length);
|
|
} else {
|
|
if (client->envelope.data) {
|
|
MemFree(client->envelope.data);
|
|
}
|
|
|
|
NMAPSendCommand(client->conn, "QDONE\r\n", 7);
|
|
NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
return(-1);
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == 6021)) {
|
|
client->envelope.data[client->envelope.length] = '\0';
|
|
|
|
cur = client->envelope.data;
|
|
} else {
|
|
MemFree(client->envelope.data);
|
|
client->envelope.data = NULL;
|
|
|
|
NMAPSendCommand(client->conn, "QDONE\r\n", 7);
|
|
NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
return(-1);
|
|
}
|
|
|
|
eol = NULL;
|
|
while (*cur) {
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
if (line[-1] == 0x0D) {
|
|
eol = line - 1;
|
|
} else {
|
|
eol = line;
|
|
}
|
|
|
|
preserve = *eol;
|
|
*eol = '\0';
|
|
|
|
line++;
|
|
} else {
|
|
eol = NULL;
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
switch (cur[0]) {
|
|
case QUEUE_CALENDAR_LOCAL: {
|
|
client->recipients.calendar++;
|
|
break;
|
|
}
|
|
|
|
case QUEUE_FROM: {
|
|
unsigned char *auth;
|
|
|
|
auth = strchr(cur + 1, ' ');
|
|
if (auth) {
|
|
*auth = '\0';
|
|
strcpy(client->sender.claim, cur + 1);
|
|
*auth++ = ' ';
|
|
|
|
ptr = strchr(auth, ' ');
|
|
if (ptr) {
|
|
*ptr = '\0';
|
|
strcpy(client->sender.auth, auth);
|
|
*ptr = ' ';
|
|
} else {
|
|
strcpy(client->sender.auth, auth);
|
|
}
|
|
} else {
|
|
strcpy(client->sender.claim, cur + 1);
|
|
|
|
client->sender.auth[0] = '-';
|
|
client->sender.auth[0] = '\0';
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case QUEUE_RECIP_LOCAL:
|
|
case QUEUE_RECIP_MBOX_LOCAL: {
|
|
client->recipients.local++;
|
|
break;
|
|
}
|
|
|
|
case QUEUE_RECIP_REMOTE: {
|
|
client->recipients.remote++;
|
|
break;
|
|
}
|
|
|
|
case QUEUE_FLAGS: {
|
|
client->entry.flags = atol(cur + 1);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_ADDRESS:
|
|
case QUEUE_BOUNCE:
|
|
case QUEUE_DATE:
|
|
case QUEUE_ID:
|
|
case QUEUE_THIRD_PARTY:
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = line;
|
|
}
|
|
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
return(ccode);
|
|
}
|
|
|
|
static void
|
|
ProcessACL(PlusPackClient *client)
|
|
{
|
|
unsigned long used;
|
|
unsigned char *ptr;
|
|
unsigned char *delim;
|
|
|
|
client->dn[0] = '\0';
|
|
client->flags &= ~(PLUSPACK_CLIENT_FLAG_FOUND | PLUSPACK_CLIENT_FLAG_ALLOWED);
|
|
|
|
if ((client->sender.auth[0] != '-') && (client->sender.auth[0] != '\0')) {
|
|
ptr = client->sender.auth;
|
|
} else if (!(PlusPack.flags & PLUSPACK_FLAG_ACL_AUTH_REQUIRED)) {
|
|
ptr = client->sender.claim;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
delim = strchr(ptr, '@');
|
|
if (delim) {
|
|
*delim = '\0';
|
|
}
|
|
|
|
if (MsgFindObject(ptr, client->dn, NULL, NULL, client->vs)) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_FOUND;
|
|
|
|
if (delim) {
|
|
*delim = '@';
|
|
}
|
|
} else if (delim) {
|
|
*delim = '@';
|
|
|
|
delim = strchr(ptr, ' ');
|
|
if (delim) {
|
|
*delim = '\0';
|
|
}
|
|
|
|
if (MsgFindObject(ptr, client->dn, NULL, NULL, client->vs)) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_FOUND;
|
|
}
|
|
|
|
if (delim) {
|
|
*delim = ' ';
|
|
}
|
|
}
|
|
|
|
if (client->dn[0]) {
|
|
MDBFreeValues(client->vs);
|
|
MDBReadDN(client->dn, A_GROUP_MEMBERSHIP, client->vs);
|
|
for (used = 0; used < client->vs->Used; used++) {
|
|
if (XplStrCaseCmp(PlusPack.allowedGroup, client->vs->Value[used]) != 0) {
|
|
continue;
|
|
}
|
|
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_ALLOWED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (client->flags & PLUSPACK_CLIENT_FLAG_FOUND) {
|
|
if (client->flags & PLUSPACK_CLIENT_FLAG_ALLOWED) {
|
|
if (PlusPack.flags & PLUSPACK_FLAG_ACL_SENDNOMEMBERONLY) {
|
|
client->flags &= ~PLUSPACK_CLIENT_FLAG_ALLOWED;
|
|
}
|
|
} else if (PlusPack.flags & PLUSPACK_FLAG_ACL_SENDNOMEMBERONLY) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_ALLOWED;
|
|
}
|
|
}
|
|
|
|
MDBFreeValues(client->vs);
|
|
|
|
return;
|
|
}
|
|
|
|
static int
|
|
ProcessCopy(PlusPackClient *client)
|
|
{
|
|
int count;
|
|
int length;
|
|
unsigned char *cur;
|
|
unsigned char *line;
|
|
unsigned char *envelope;
|
|
|
|
if (!(client->entry.flags & MSG_FLAG_PLUSPACK_COPIED)
|
|
&& (((client->entry.queue == Q_FIVE) && (client->recipients.local))
|
|
|| ((client->entry.queue == Q_DELIVER) && (client->recipients.remote)))) {
|
|
count = client->envelope.length + 39;
|
|
count += (strlen(PlusPack.copy.user) * 2);
|
|
count += strlen(PlusPack.copy.inbox);
|
|
|
|
envelope = (unsigned char *)MemMalloc(count);
|
|
if (envelope) {
|
|
client->entry.flags |= MSG_FLAG_PLUSPACK_COPIED;
|
|
|
|
count = 0;
|
|
length = client->envelope.length;
|
|
cur = client->envelope.data;
|
|
while (*cur) {
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
line++;
|
|
} else {
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
if (cur[0] != QUEUE_FLAGS) {
|
|
cur = line;
|
|
continue;
|
|
}
|
|
|
|
count = cur - client->envelope.data;
|
|
memcpy(envelope, client->envelope.data, count);
|
|
|
|
count += sprintf(envelope + count, QUEUES_FLAGS"%lu\r\n", client->entry.flags);
|
|
|
|
length -= (line - client->envelope.data);
|
|
|
|
memcpy(envelope + count, line, length);
|
|
|
|
count += length;
|
|
break;
|
|
}
|
|
|
|
if (!count) {
|
|
count = sprintf(envelope, QUEUES_FLAGS"%lu\r\n", client->entry.flags);
|
|
memcpy(envelope + count, client->envelope.data, client->envelope.length);
|
|
count += client->envelope.length;
|
|
}
|
|
|
|
MemFree(client->envelope.data);
|
|
client->envelope.data = envelope;
|
|
client->envelope.length = count;
|
|
envelope[count] = '\0';
|
|
|
|
if (client->entry.queue == Q_FIVE) {
|
|
if (client->recipients.local) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_COPIED;
|
|
client->recipients.local++;
|
|
|
|
if (PlusPack.copy.inbox[0]) {
|
|
count = sprintf(envelope + client->envelope.length, QUEUES_RECIP_MBOX_LOCAL"%s %s 0 %s %d\r\n", PlusPack.copy.user, PlusPack.copy.user, PlusPack.copy.inbox, NO_PLUSPACK);
|
|
} else {
|
|
count = sprintf(envelope + client->envelope.length, QUEUES_RECIP_LOCAL"%s %s %d\r\n", PlusPack.copy.user, PlusPack.copy.user, NO_PLUSPACK);
|
|
}
|
|
|
|
client->envelope.length += count;
|
|
}
|
|
} else if (client->recipients.remote) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_COPIED;
|
|
client->recipients.local++;
|
|
|
|
if (PlusPack.copy.outbox[0]) {
|
|
count = sprintf(envelope + client->envelope.length, QUEUES_RECIP_MBOX_LOCAL"%s %s 0 %s %d\r\n", PlusPack.copy.user, PlusPack.copy.user, PlusPack.copy.outbox, NO_PLUSPACK);
|
|
} else {
|
|
count = sprintf(envelope + client->envelope.length, QUEUES_RECIP_LOCAL"%s %s %d\r\n", PlusPack.copy.user, PlusPack.copy.user, NO_PLUSPACK);
|
|
}
|
|
|
|
client->envelope.length += count;
|
|
}
|
|
} else {
|
|
LoggerEvent(PlusPack.handle.directory, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_OUT_OF_MEMORY, LOG_ERROR, 0, __FILE__, NULL, sizeof(MDBValueStruct), __LINE__, NULL, 0);
|
|
|
|
count = 0;
|
|
}
|
|
} else {
|
|
count = 0;
|
|
}
|
|
|
|
return(count);
|
|
}
|
|
|
|
static int
|
|
ProcessMime(PlusPackClient *client)
|
|
{
|
|
int ccode;
|
|
int count;
|
|
unsigned long size;
|
|
unsigned long position;
|
|
unsigned char *ptr;
|
|
unsigned char *type = NULL;
|
|
unsigned char *subtype = NULL;
|
|
unsigned char *charset = NULL;
|
|
unsigned char *encoding = NULL;
|
|
|
|
count = 0;
|
|
|
|
ccode = NMAPSendCommandF(client->conn, "QMIME %s\r\n", client->entry.name);
|
|
while ((ccode != -1) && (ccode != NMAP_OK)) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE);
|
|
switch (ccode) {
|
|
case NMAP_OK: {
|
|
continue;
|
|
}
|
|
|
|
case 2002: {
|
|
ptr = NULL;
|
|
|
|
type = client->line;
|
|
subtype = strchr(client->line, ' ');
|
|
if (subtype) {
|
|
*subtype++ = '\0';
|
|
|
|
charset = strchr(subtype, ' ');
|
|
if (charset) {
|
|
*charset++ = '\0';
|
|
|
|
encoding = strchr(charset, ' ');
|
|
if (encoding) {
|
|
*encoding++ = '\0';
|
|
|
|
ptr = strchr(encoding, ' ');
|
|
if (ptr) {
|
|
*ptr++ = '\0';
|
|
|
|
ptr = strrchr(ptr, '"');
|
|
if (ptr) {
|
|
ptr += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type && subtype && charset && encoding && ptr) {
|
|
if (sscanf(ptr, "%lu %lu", &position, &size) == 2) {
|
|
if (!count) {
|
|
if (XplStrCaseCmp(type, "multipart") == 0) {
|
|
if (XplStrCaseCmp(subtype, "alternative") == 0) {
|
|
count++;
|
|
} else if (XplStrCaseCmp(subtype, "mixed") == 0) {
|
|
count++;
|
|
|
|
client->mime.attachments = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count < 2) {
|
|
if (XplStrCaseCmp(type, "text") == 0) {
|
|
if (XplStrCaseCmp(subtype, "plain") == 0) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_SIGNATURE;
|
|
|
|
client->mime.plain.position = position;
|
|
client->mime.plain.size = size;
|
|
} else if (XplStrCaseCmp(subtype, "html") == 0) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_SIGNATURE_HTML;
|
|
|
|
client->mime.html.position = position;
|
|
client->mime.html.size = size;
|
|
} else {
|
|
client->mime.attachments = TRUE;
|
|
}
|
|
} else if ((XplStrCaseCmp(type, "multipart") != 0)
|
|
&& (XplStrCaseCmp(type, "message") != 0)) {
|
|
client->mime.attachments = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
case 2003:
|
|
case 2004: {
|
|
count--;
|
|
continue;
|
|
}
|
|
|
|
default: {
|
|
ccode = -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE)
|
|
&& (client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE_HTML)) {
|
|
if (client->mime.html.position < client->mime.plain.position) {
|
|
client->mime.signature[0].html = TRUE;
|
|
client->mime.signature[0].position = client->mime.html.position;
|
|
client->mime.signature[0].size = client->mime.html.size;
|
|
client->mime.signature[1].html = FALSE;
|
|
client->mime.signature[1].position = client->mime.plain.position;
|
|
client->mime.signature[1].size = client->mime.plain.size;
|
|
} else {
|
|
client->mime.signature[0].html = FALSE;
|
|
client->mime.signature[0].position = client->mime.plain.position;
|
|
client->mime.signature[0].size = client->mime.plain.size;
|
|
client->mime.signature[1].html = TRUE;
|
|
client->mime.signature[1].position = client->mime.html.position;
|
|
client->mime.signature[1].size = client->mime.html.size;
|
|
}
|
|
} else if (client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE) {
|
|
client->mime.signature[0].html = FALSE;
|
|
client->mime.signature[0].position = client->mime.plain.position;
|
|
client->mime.signature[0].size = client->mime.plain.size;
|
|
client->mime.signature[1].position = 0;
|
|
} else if (client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE_HTML) {
|
|
client->mime.signature[0].html = TRUE;
|
|
client->mime.signature[0].position = client->mime.html.position;
|
|
client->mime.signature[0].size = client->mime.html.size;
|
|
client->mime.signature[1].position = 0;
|
|
}
|
|
|
|
if (((ccode = NMAPSendCommandF(client->conn, "QINFO %s\r\n", client->entry.name)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == 2001)
|
|
&& (sscanf(client->line, "%*s %lu %lu", &client->mime.size, &client->mime.header) == 2)) {
|
|
return(0);
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
static int
|
|
ProcessAttachments(PlusPackClient *client)
|
|
{
|
|
int ccode = 0;
|
|
unsigned char preserve;
|
|
unsigned char *cur;
|
|
unsigned char *eol;
|
|
unsigned char *line;
|
|
|
|
preserve = '\0';
|
|
if ((client->entry.queue == Q_DELIVER) && client->mime.attachments) {
|
|
client->flags &= ~(PLUSPACK_FLAG_SIGNATURE_HTML | PLUSPACK_FLAG_SIGNATURE);
|
|
|
|
eol = NULL;
|
|
cur = client->envelope.data;
|
|
while (*cur) {
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
if (line[-1] == 0x0D) {
|
|
eol = line - 1;
|
|
} else {
|
|
eol = line;
|
|
}
|
|
|
|
preserve = *eol;
|
|
*eol = '\0';
|
|
|
|
line++;
|
|
} else {
|
|
eol = NULL;
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
switch (cur[0]) {
|
|
case QUEUE_CALENDAR_LOCAL:
|
|
case QUEUE_RECIP_LOCAL:
|
|
case QUEUE_RECIP_MBOX_LOCAL:
|
|
case QUEUE_RECIP_REMOTE: {
|
|
/* If the COPIED bit has been set; then the last recipient in the envelope
|
|
is the copied user and we need to preserve it.
|
|
|
|
Otherwise; consume all recipients.
|
|
*/
|
|
if (!(client->flags & PLUSPACK_CLIENT_FLAG_COPIED) || *line) {
|
|
break;
|
|
}
|
|
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_FLAGS: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW "QUEUES_FLAGS"%d\r\n", client->entry.flags | MSG_FLAG_PLUSPACK_PROCESSED);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_ADDRESS:
|
|
case QUEUE_BOUNCE:
|
|
case QUEUE_DATE:
|
|
case QUEUE_FROM:
|
|
case QUEUE_ID:
|
|
case QUEUE_THIRD_PARTY:
|
|
default: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = line;
|
|
}
|
|
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
client->bounce = "You are not allowed to send attatchments.";
|
|
}
|
|
|
|
return(ccode);
|
|
}
|
|
|
|
static int
|
|
ProcessAllowed(PlusPackClient *client)
|
|
{
|
|
int ccode = 0;
|
|
unsigned char preserve;
|
|
unsigned char *cur;
|
|
unsigned char *eol;
|
|
unsigned char *line;
|
|
|
|
preserve = '\0';
|
|
if ((client->entry.queue == Q_DELIVER) && client->recipients.remote && !(client->flags & PLUSPACK_CLIENT_FLAG_ALLOWED)) {
|
|
client->flags &= ~(PLUSPACK_FLAG_SIGNATURE_HTML | PLUSPACK_FLAG_SIGNATURE);
|
|
|
|
if (!client->bounce) {
|
|
eol = NULL;
|
|
cur = client->envelope.data;
|
|
while (*cur) {
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
if (line[-1] == 0x0D) {
|
|
eol = line - 1;
|
|
} else {
|
|
eol = line;
|
|
}
|
|
|
|
preserve = *eol;
|
|
*eol = '\0';
|
|
|
|
line++;
|
|
} else {
|
|
eol = NULL;
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
switch (cur[0]) {
|
|
case QUEUE_CALENDAR_LOCAL:
|
|
case QUEUE_RECIP_LOCAL:
|
|
case QUEUE_RECIP_MBOX_LOCAL: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_RECIP_REMOTE: {
|
|
break;
|
|
}
|
|
|
|
case QUEUE_ADDRESS:
|
|
case QUEUE_BOUNCE:
|
|
case QUEUE_DATE:
|
|
case QUEUE_FROM:
|
|
case QUEUE_ID:
|
|
case QUEUE_THIRD_PARTY:
|
|
case QUEUE_FLAGS:
|
|
default: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = line;
|
|
}
|
|
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
client->bounce = "You are not allowed to send external mail.";
|
|
} else {
|
|
client->bounce = "You are not allowed to send external mail; or attachments.";
|
|
}
|
|
}
|
|
|
|
return(ccode);
|
|
}
|
|
|
|
static int
|
|
ProcessEnvelope(PlusPackClient *client)
|
|
{
|
|
int ccode = 0;
|
|
unsigned char preserve;
|
|
unsigned char *cur;
|
|
unsigned char *eol;
|
|
unsigned char *line;
|
|
|
|
preserve = '\0';
|
|
if (client->flags & PLUSPACK_CLIENT_FLAG_COPIED) {
|
|
eol = NULL;
|
|
cur = client->envelope.data;
|
|
while ((ccode != -1) && *cur) {
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
if (line[-1] == 0x0D) {
|
|
eol = line - 1;
|
|
} else {
|
|
eol = line;
|
|
}
|
|
|
|
preserve = *eol;
|
|
*eol = '\0';
|
|
|
|
line++;
|
|
} else {
|
|
eol = NULL;
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
|
|
cur = line;
|
|
}
|
|
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
}
|
|
|
|
return(ccode);
|
|
}
|
|
|
|
static int
|
|
ProcessSignatures(PlusPackClient *client)
|
|
{
|
|
int ccode;
|
|
int count;
|
|
unsigned char preserve;
|
|
unsigned char *ptr;
|
|
unsigned char *cur;
|
|
unsigned char *eol;
|
|
unsigned char *line;
|
|
|
|
preserve = '\0';
|
|
if ((client->entry.queue == Q_DELIVER) && client->recipients.remote) {
|
|
ccode = NMAPSendCommand(client->conn, "QCREA\r\n", 7);
|
|
} else {
|
|
ccode = ProcessEnvelope(client);
|
|
return(ccode);
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
client->flags |= PLUSPACK_CLIENT_FLAG_SPLIT;
|
|
|
|
if (((ccode = NMAPSendCommandF(client->conn, "QSTOR FLAGS %d\r\n", client->entry.flags | MSG_FLAG_PLUSPACK_PROCESSED)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QSTOR FROM %s %s\r\n", client->sender.claim, client->sender.auth)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QADDQ %s 0 %lu\r\n", client->entry.name, client->mime.header)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QSTOR MESSAGE\r\nX-AutoSignature-Version: Bongo Signature Agent 0.1\r\n.\r\n")) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
if ((client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE)
|
|
&& (client->flags & PLUSPACK_CLIENT_FLAG_SIGNATURE_HTML)) {
|
|
if (((ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header, client->mime.signature[0].position + client->mime.signature[0].size)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
if (client->mime.signature[0].html) {
|
|
ptr = PlusPack.signature.html;
|
|
} else {
|
|
ptr = PlusPack.signature.plain;
|
|
}
|
|
|
|
count = strlen(ptr);
|
|
if ((ccode = NMAPSendCommandF(client->conn, "QSTOR MESSAGE %d\r\n", count)) != -1) {
|
|
ccode = NMAPSendCommand(client->conn, ptr, count);
|
|
}
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommand(client->conn, "QSTOR MESSAGE 2\r\n\r\n", 19)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header + client->mime.signature[0].position + client->mime.signature[0].size, (client->mime.signature[1].position - client->mime.signature[0].position - client->mime.signature[0].size) + client->mime.signature[1].size)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
if (client->mime.signature[1].html) {
|
|
ptr = PlusPack.signature.html;
|
|
} else {
|
|
ptr = PlusPack.signature.plain;
|
|
}
|
|
|
|
count = strlen(ptr);
|
|
if ((ccode = NMAPSendCommandF(client->conn, "QSTOR MESSAGE %d\r\n", count)) != -1) {
|
|
ccode = NMAPSendCommand(client->conn, ptr, count);
|
|
}
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommand(client->conn, "QSTOR MESSAGE 2\r\n\r\n", 19)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header + client->mime.signature[1].position + client->mime.signature[1].size, client->mime.size - client->mime.header - client->mime.signature[1].position - client->mime.signature[1].size);
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
} else if (client->flags & (PLUSPACK_CLIENT_FLAG_SIGNATURE | PLUSPACK_CLIENT_FLAG_SIGNATURE_HTML)) {
|
|
if (((ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header, client->mime.signature[0].position + client->mime.signature[0].size)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
if (client->mime.signature[0].html) {
|
|
ptr = PlusPack.signature.html;
|
|
} else {
|
|
ptr = PlusPack.signature.plain;
|
|
}
|
|
|
|
count = strlen(ptr);
|
|
if ((ccode = NMAPSendCommandF(client->conn, "QSTOR MESSAGE %d\r\n", count)) != -1) {
|
|
ccode = NMAPSendCommand(client->conn, ptr, count);
|
|
}
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)
|
|
&& ((ccode = NMAPSendCommand(client->conn, "QSTOR MESSAGE 2\r\n\r\n", 19)) != -1)
|
|
&& ((ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE)) == NMAP_OK)) {
|
|
ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header + client->mime.signature[0].position + client->mime.signature[0].size, client->mime.size - client->mime.header - client->mime.signature[0].position - client->mime.signature[0].size);
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
} else {
|
|
ccode = NMAPSendCommandF(client->conn, "QADDQ %s %lu %lu\r\n", client->entry.name, client->mime.header, client->mime.size - client->mime.header);
|
|
}
|
|
|
|
if (ccode != -1) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE);
|
|
|
|
eol = NULL;
|
|
cur = client->envelope.data;
|
|
while ((ccode != -1) && *cur) {
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
|
|
line = strchr(cur, 0x0A);
|
|
if (line) {
|
|
if (line[-1] == 0x0D) {
|
|
eol = line - 1;
|
|
} else {
|
|
eol = line;
|
|
}
|
|
|
|
preserve = *eol;
|
|
*eol = '\0';
|
|
|
|
line++;
|
|
} else {
|
|
eol = NULL;
|
|
line = cur + strlen(cur);
|
|
}
|
|
|
|
switch (cur[0]) {
|
|
case QUEUE_CALENDAR_LOCAL:
|
|
case QUEUE_RECIP_LOCAL:
|
|
case QUEUE_RECIP_MBOX_LOCAL: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_RECIP_REMOTE: {
|
|
if ((client->flags & PLUSPACK_CLIENT_FLAG_ALLOWED)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QSTOR RAW %s\r\n", cur)) != -1)) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case QUEUE_FROM:
|
|
case QUEUE_DATE:
|
|
case QUEUE_FLAGS: {
|
|
ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur);
|
|
break;
|
|
}
|
|
|
|
case QUEUE_ADDRESS:
|
|
case QUEUE_BOUNCE:
|
|
case QUEUE_ID:
|
|
case QUEUE_THIRD_PARTY:
|
|
default: {
|
|
if (((ccode = NMAPSendCommandF(client->conn, "QMOD RAW %s\r\n", cur)) != -1)
|
|
&& ((ccode = NMAPSendCommandF(client->conn, "QSTOR RAW %s\r\n", cur)) != -1)) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = line;
|
|
}
|
|
|
|
if (eol) {
|
|
*eol = preserve;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ccode == -1) {
|
|
client->flags &= ~PLUSPACK_CLIENT_FLAG_SPLIT;
|
|
|
|
NMAPSendCommand(client->conn, "QABRT\r\n", 7);
|
|
NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
}
|
|
} else {
|
|
ccode = -1;
|
|
}
|
|
|
|
return(ccode);
|
|
}
|
|
|
|
static void
|
|
HandleConnection(void *param)
|
|
{
|
|
int ccode;
|
|
long threadNumber = (long)param;
|
|
time_t sleep = time(NULL);
|
|
time_t wokeup;
|
|
PlusPackClient *client;
|
|
|
|
if ((client = PlusPackClientAlloc()) == NULL) {
|
|
XplConsolePrintf("bongopluspack: New worker failed to startup; out of memory.\r\n");
|
|
|
|
NMAPSendCommand(client->conn, "QDONE\r\n", 7);
|
|
|
|
XplSafeDecrement(PlusPack.nmap.queue.active);
|
|
|
|
return;
|
|
}
|
|
|
|
do {
|
|
XplRenameThread(XplGetThreadID(), "PlusPack Worker");
|
|
|
|
XplSafeIncrement(PlusPack.nmap.queue.idle);
|
|
|
|
XplWaitOnLocalSemaphore(PlusPack.nmap.queue.todo);
|
|
|
|
XplSafeDecrement(PlusPack.nmap.queue.idle);
|
|
|
|
wokeup = time(NULL);
|
|
|
|
XplWaitOnLocalSemaphore(PlusPack.nmap.semaphore);
|
|
|
|
client->conn = PlusPack.nmap.queue.tail;
|
|
if (client->conn) {
|
|
PlusPack.nmap.queue.tail = client->conn->queue.previous;
|
|
if (PlusPack.nmap.queue.tail) {
|
|
PlusPack.nmap.queue.tail->queue.next = NULL;
|
|
} else {
|
|
PlusPack.nmap.queue.head = NULL;
|
|
}
|
|
}
|
|
|
|
XplSignalLocalSemaphore(PlusPack.nmap.semaphore);
|
|
|
|
if (client->conn) {
|
|
if (((client->vs = MDBCreateValueStruct(PlusPack.handle.directory, NULL)) != NULL)
|
|
&& ConnNegotiate(client->conn, PlusPack.nmap.ssl.context)) {
|
|
ccode = ProcessConnection(client);
|
|
|
|
if ((ccode != -1) && !(client->entry.flags & MSG_FLAG_PLUSPACK_PROCESSED)) {
|
|
if (PlusPack.flags & PLUSPACK_FLAG_ACL_ENABLED) {
|
|
ProcessACL(client);
|
|
} else {
|
|
client->flags |= (PLUSPACK_CLIENT_FLAG_FOUND | PLUSPACK_CLIENT_FLAG_ALLOWED);
|
|
}
|
|
|
|
if (PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) {
|
|
ccode = ProcessCopy(client);
|
|
}
|
|
|
|
if ((ccode != -1) && (PlusPack.flags & (PLUSPACK_FLAG_SIGNATURE_HTML | PLUSPACK_FLAG_SIGNATURE | PLUSPACK_FLAG_NO_ATTACHMENTS))) {
|
|
ccode = ProcessMime(client);
|
|
}
|
|
|
|
if ((ccode != -1) && (PlusPack.flags & PLUSPACK_FLAG_NO_ATTACHMENTS)) {
|
|
ccode = ProcessAttachments(client);
|
|
}
|
|
|
|
if ((ccode != -1) && (PlusPack.flags & PLUSPACK_FLAG_ACL_ENABLED)) {
|
|
ccode = ProcessAllowed(client);
|
|
}
|
|
|
|
if (ccode != -1) {
|
|
if (!client->bounce) {
|
|
if (PlusPack.flags & (PLUSPACK_FLAG_SIGNATURE_HTML | PLUSPACK_FLAG_SIGNATURE)) {
|
|
ccode = ProcessSignatures(client);
|
|
} else {
|
|
ccode = ProcessEnvelope(client);
|
|
}
|
|
} else {
|
|
ccode = NMAPSendCommandF(client->conn, "QRTS %s %s %d %d %s\r\n", client->sender.claim, client->sender.claim, DSN_HEADER | DSN_FAILURE, DELIVER_BLOCKED, client->bounce);
|
|
}
|
|
}
|
|
|
|
if (client->flags & PLUSPACK_CLIENT_FLAG_SPLIT) {
|
|
if ((ccode = NMAPSendCommand(client->conn, "QRUN\r\n", 6)) != -1) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ccode != -1)
|
|
&& ((ccode = NMAPSendCommand(client->conn, "QDONE\r\n", 7)) != -1)) {
|
|
ccode = NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
}
|
|
} else {
|
|
if (!client->vs) {
|
|
LoggerEvent(PlusPack.handle.directory, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_OUT_OF_MEMORY, LOG_ERROR, 0, __FILE__, NULL, sizeof(MDBValueStruct), __LINE__, NULL, 0);
|
|
}
|
|
|
|
NMAPSendCommand(client->conn, "QDONE\r\n", 7);
|
|
NMAPReadAnswer(client->conn, client->line, CONN_BUFSIZE, FALSE);
|
|
}
|
|
}
|
|
|
|
if (client->conn) {
|
|
ConnFlush(client->conn);
|
|
}
|
|
|
|
FreeClientData(client);
|
|
|
|
/* Live or die? */
|
|
if (threadNumber == XplSafeRead(PlusPack.nmap.queue.active)) {
|
|
if ((wokeup - sleep) > PlusPack.nmap.sleepTime) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
sleep = time(NULL);
|
|
|
|
PlusPackClientAllocCB(client, NULL);
|
|
} while (PlusPack.state == PLUSPACK_STATE_RUNNING);
|
|
|
|
FreeClientData(client);
|
|
|
|
PlusPackClientFree(client);
|
|
|
|
XplSafeDecrement(PlusPack.nmap.queue.active);
|
|
|
|
XplExitThread(TSR_THREAD, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
PlusPackQueueServer5(void *ignored)
|
|
{
|
|
int ccode;
|
|
XplThreadID id;
|
|
Connection *conn;
|
|
|
|
XplSafeIncrement(PlusPack.server.active);
|
|
|
|
XplRenameThread(XplGetThreadID(), "PlusPack Queue 6 Server");
|
|
|
|
while (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
if (ConnAccept(PlusPack.nmap.conn.queue6, &conn) != -1) {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
conn->ssl.enable = FALSE;
|
|
|
|
QUEUE_WORK_TO_DO(conn, id, ccode);
|
|
if (!ccode) {
|
|
XplSignalLocalSemaphore(PlusPack.nmap.queue.todo);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ConnWrite(conn, "QDONE\r\n", 7);
|
|
ConnClose(conn, 0);
|
|
|
|
ConnFree(conn);
|
|
conn = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
switch (errno) {
|
|
case ECONNABORTED:
|
|
#ifdef EPROTO
|
|
case EPROTO:
|
|
#endif
|
|
case EINTR: {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
LoggerEvent(PlusPack.handle.logging, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_ACCEPT_FAILURE, LOG_ERROR, 0, "Server", NULL, errno, 0, NULL, 0);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
default: {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
XplConsolePrintf("bongopluspack: Exiting after an accept() failure; error %d\r\n", errno);
|
|
|
|
LoggerEvent(PlusPack.handle.logging, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_ACCEPT_FAILURE, LOG_ERROR, 0, "Server", NULL, errno, 0, NULL, 0);
|
|
|
|
PlusPack.state = PLUSPACK_STATE_STOPPING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Shutting down */
|
|
PlusPack.state = PLUSPACK_STATE_UNLOADING;
|
|
|
|
XplConsolePrintf("bongopluspack: Remote recipient handler shutting down.\r\n");
|
|
|
|
XplSafeDecrement(PlusPack.server.active);
|
|
XplSetThreadGroupID(id);
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
PlusPackQueueServer6(void *ignored)
|
|
{
|
|
int i;
|
|
int ccode;
|
|
XplThreadID id;
|
|
Connection *conn;
|
|
|
|
XplSafeIncrement(PlusPack.server.active);
|
|
|
|
XplRenameThread(XplGetThreadID(), "PlusPack Queue 5 Server");
|
|
|
|
while (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
if (ConnAccept(PlusPack.nmap.conn.queue5, &conn) != -1) {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
conn->ssl.enable = FALSE;
|
|
|
|
QUEUE_WORK_TO_DO(conn, id, ccode);
|
|
if (!ccode) {
|
|
XplSignalLocalSemaphore(PlusPack.nmap.queue.todo);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ConnWrite(conn, "QDONE\r\n", 7);
|
|
ConnClose(conn, 0);
|
|
|
|
ConnFree(conn);
|
|
conn = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
switch (errno) {
|
|
case ECONNABORTED:
|
|
#ifdef EPROTO
|
|
case EPROTO:
|
|
#endif
|
|
case EINTR: {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
LoggerEvent(PlusPack.handle.logging, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_ACCEPT_FAILURE, LOG_ERROR, 0, "Server", NULL, errno, 0, NULL, 0);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
default: {
|
|
if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
XplConsolePrintf("bongopluspack: Exiting after an accept() failure; error %d\r\n", errno);
|
|
|
|
LoggerEvent(PlusPack.handle.logging, LOGGER_SUBSYSTEM_GENERAL, LOGGER_EVENT_ACCEPT_FAILURE, LOG_ERROR, 0, "Server", NULL, errno, 0, NULL, 0);
|
|
|
|
PlusPack.state = PLUSPACK_STATE_STOPPING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Shutting down */
|
|
PlusPack.state = PLUSPACK_STATE_UNLOADING;
|
|
|
|
XplConsolePrintf("bongopluspack: Shutting down.\r\n");
|
|
|
|
id = XplSetThreadGroupID(PlusPack.id.group);
|
|
|
|
if (PlusPack.nmap.conn.queue5) {
|
|
ConnClose(PlusPack.nmap.conn.queue5, 1);
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
}
|
|
|
|
if (PlusPack.nmap.conn.queue6) {
|
|
ConnClose(PlusPack.nmap.conn.queue6, 1);
|
|
PlusPack.nmap.conn.queue6 = NULL;
|
|
}
|
|
|
|
if (PlusPack.nmap.ssl.enable) {
|
|
PlusPack.nmap.ssl.enable = FALSE;
|
|
|
|
if (PlusPack.nmap.ssl.conn) {
|
|
ConnClose(PlusPack.nmap.ssl.conn, 1);
|
|
PlusPack.nmap.ssl.conn = NULL;
|
|
}
|
|
|
|
if (PlusPack.nmap.ssl.context) {
|
|
ConnSSLContextFree(PlusPack.nmap.ssl.context);
|
|
PlusPack.nmap.ssl.context = NULL;
|
|
}
|
|
}
|
|
|
|
ConnCloseAll(1);
|
|
|
|
for (i = 0; (XplSafeRead(PlusPack.server.active) > 1) && (i < 60); i++) {
|
|
XplDelay(1000);
|
|
}
|
|
|
|
XplConsolePrintf("bongopluspack: Shutting down %d queue threads\r\n", XplSafeRead(PlusPack.nmap.queue.active));
|
|
|
|
XplWaitOnLocalSemaphore(PlusPack.nmap.semaphore);
|
|
|
|
ccode = XplSafeRead(PlusPack.nmap.queue.idle);
|
|
while (ccode--) {
|
|
XplSignalLocalSemaphore(PlusPack.nmap.queue.todo);
|
|
}
|
|
|
|
XplSignalLocalSemaphore(PlusPack.nmap.semaphore);
|
|
|
|
for (i = 0; XplSafeRead(PlusPack.nmap.queue.active) && (i < 60); i++) {
|
|
XplDelay(1000);
|
|
}
|
|
|
|
if (XplSafeRead(PlusPack.server.active) > 1) {
|
|
XplConsolePrintf("bongopluspack: %d server threads outstanding; attempting forceful unload.\r\n", XplSafeRead(PlusPack.server.active) - 1);
|
|
}
|
|
|
|
if (XplSafeRead(PlusPack.nmap.queue.active)) {
|
|
XplConsolePrintf("bongopluspack: %d threads outstanding; attempting forceful unload.\r\n", XplSafeRead(PlusPack.nmap.queue.active));
|
|
}
|
|
|
|
LoggerClose(PlusPack.handle.logging);
|
|
PlusPack.handle.logging = NULL;
|
|
|
|
XplCloseLocalSemaphore(PlusPack.nmap.queue.todo);
|
|
XplCloseLocalSemaphore(PlusPack.nmap.semaphore);
|
|
|
|
MsgShutdown();
|
|
|
|
CONN_TRACE_SHUTDOWN();
|
|
ConnShutdown();
|
|
|
|
if (PlusPack.signature.plain) {
|
|
MemFree(PlusPack.signature.plain);
|
|
}
|
|
|
|
if (PlusPack.signature.html) {
|
|
MemFree(PlusPack.signature.html);
|
|
}
|
|
|
|
if (PlusPack.allowedGroup) {
|
|
MemFree(PlusPack.allowedGroup);
|
|
}
|
|
|
|
MemPrivatePoolFree(PlusPack.nmap.pool);
|
|
|
|
MemoryManagerClose(PLUSPACK_AGENT);
|
|
|
|
XplConsolePrintf("bongopluspack: Shutdown complete\r\n");
|
|
|
|
XplSignalLocalSemaphore(PlusPack.sem.main);
|
|
XplWaitOnLocalSemaphore(PlusPack.sem.shutdown);
|
|
|
|
XplCloseLocalSemaphore(PlusPack.sem.shutdown);
|
|
XplCloseLocalSemaphore(PlusPack.sem.main);
|
|
|
|
XplSetThreadGroupID(id);
|
|
|
|
return;
|
|
}
|
|
|
|
static BOOL
|
|
ReadConfiguration(void)
|
|
{
|
|
unsigned char *ptr;
|
|
MDBValueStruct *vs;
|
|
|
|
vs = MDBCreateValueStruct(PlusPack.handle.directory, MsgGetServerDN(NULL));
|
|
if (vs) {
|
|
if (MDBRead(MDB_CURRENT_CONTEXT, MSGSRV_A_OFFICIAL_NAME, vs)) {
|
|
strcpy(PlusPack.officialName, vs->Value[0]);
|
|
MDBFreeValues(vs);
|
|
} else {
|
|
PlusPack.officialName[0] = '\0';
|
|
}
|
|
|
|
if (MDBRead(PLUSPACK_AGENT, MSGSRV_A_CONFIGURATION, vs)) {
|
|
PlusPack.flags = atol(vs->Value[0]);
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
if (MDBRead(PLUSPACK_AGENT, MSGSRV_A_LIST_SIGNATURE, vs)) {
|
|
if (vs->Value[0][0]
|
|
&& ((PlusPack.signature.plain = MemStrdup(vs->Value[0])) != NULL)) {
|
|
PlusPack.flags |= PLUSPACK_FLAG_SIGNATURE;
|
|
} else {
|
|
PlusPack.flags &= ~PLUSPACK_FLAG_SIGNATURE;
|
|
}
|
|
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
if (MDBRead(PLUSPACK_AGENT, MSGSRV_A_LIST_SIGNATURE_HTML, vs)) {
|
|
if (vs->Value[0][0]
|
|
&& ((PlusPack.signature.html = MemStrdup(vs->Value[0])) != NULL)) {
|
|
PlusPack.flags |= PLUSPACK_FLAG_SIGNATURE_HTML;
|
|
} else {
|
|
PlusPack.flags &= ~PLUSPACK_FLAG_SIGNATURE_HTML;
|
|
}
|
|
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
if (MDBReadDN(PLUSPACK_AGENT, PLUSPACK_A_COPY_USER, vs)) {
|
|
if (vs->Value[0][0]
|
|
&& (strlen(vs->Value[0]) < sizeof(PlusPack.copy.user))) {
|
|
if (!(ptr = strrchr(vs->Value[0], '\\'))) {
|
|
strcpy(PlusPack.copy.user, vs->Value[0]);
|
|
} else {
|
|
strcpy(PlusPack.copy.user, ptr + 1);
|
|
}
|
|
|
|
PlusPack.flags |= PLUSPACK_FLAG_BIGBROTHER_ENABLED;
|
|
} else {
|
|
PlusPack.flags &= ~PLUSPACK_FLAG_BIGBROTHER_ENABLED;
|
|
}
|
|
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
PlusPack.copy.inbox[0] = '\0';
|
|
PlusPack.copy.outbox[0] = '\0';
|
|
if (MDBRead(PLUSPACK_AGENT, PLUSPACK_A_COPY_MBOX, vs)) {
|
|
if (vs->Value[0][0]
|
|
&& (strlen(vs->Value[0]) < sizeof(PlusPack.copy.inbox))) {
|
|
strcpy(PlusPack.copy.inbox, vs->Value[0]);
|
|
}
|
|
|
|
if ((vs->Used == 2)
|
|
&& vs->Value[1][0]
|
|
&& (strlen(vs->Value[1]) < sizeof(PlusPack.copy.outbox))) {
|
|
strcpy(PlusPack.copy.outbox, vs->Value[1]);
|
|
} else {
|
|
strcpy(PlusPack.copy.outbox, PlusPack.copy.inbox);
|
|
}
|
|
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
if (MDBReadDN(PLUSPACK_AGENT, PLUSPACK_A_ACL_GROUP, vs)) {
|
|
if (vs->Value[0][0]) {
|
|
PlusPack.allowedGroup = vs->Value[0];
|
|
vs->Used = 0;
|
|
|
|
PlusPack.flags |= PLUSPACK_FLAG_ACL_ENABLED;
|
|
} else {
|
|
PlusPack.flags &= ~PLUSPACK_FLAG_ACL_ENABLED;
|
|
}
|
|
|
|
MDBFreeValues(vs);
|
|
}
|
|
|
|
MDBDestroyValueStruct(vs);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
#if defined(NETWARE) || defined(LIBC) || defined(WIN32)
|
|
static int
|
|
_NonAppCheckUnload(void)
|
|
{
|
|
static BOOL checked = FALSE;
|
|
XplThreadID id;
|
|
|
|
if (!checked) {
|
|
checked = TRUE;
|
|
PlusPack.state = PLUSPACK_STATE_UNLOADING;
|
|
|
|
XplWaitOnLocalSemaphore(PlusPack.sem.shutdown);
|
|
|
|
id = XplSetThreadGroupID(PlusPack.id.group);
|
|
ConnClose(PlusPack.nmap.conn.queue5, 1);
|
|
XplSetThreadGroupID(id);
|
|
|
|
id = XplSetThreadGroupID(PlusPack.id.group);
|
|
ConnClose(PlusPack.nmap.conn.queue6, 1);
|
|
XplSetThreadGroupID(id);
|
|
|
|
XplWaitOnLocalSemaphore(PlusPack.sem.main);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
SignalHandler(int sigtype)
|
|
{
|
|
switch(sigtype) {
|
|
case SIGHUP: {
|
|
if (PlusPack.state < PLUSPACK_STATE_UNLOADING) {
|
|
PlusPack.state = PLUSPACK_STATE_UNLOADING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SIGINT:
|
|
case SIGTERM: {
|
|
if (PlusPack.state == PLUSPACK_STATE_STOPPING) {
|
|
XplUnloadApp(getpid());
|
|
} else if (PlusPack.state < PLUSPACK_STATE_STOPPING) {
|
|
PlusPack.state = PLUSPACK_STATE_STOPPING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static int
|
|
QueueSocketInit(void)
|
|
{
|
|
if (PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) {
|
|
PlusPack.nmap.conn.queue5 = ConnAlloc(FALSE);
|
|
}
|
|
|
|
PlusPack.nmap.conn.queue6 = ConnAlloc(FALSE);
|
|
if (PlusPack.nmap.conn.queue6 && (!(PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) || PlusPack.nmap.conn.queue5)) {
|
|
memset(&(PlusPack.nmap.conn.queue6->socketAddress), 0, sizeof(PlusPack.nmap.conn.queue6->socketAddress));
|
|
PlusPack.nmap.conn.queue6->socketAddress.sin_family = AF_INET;
|
|
PlusPack.nmap.conn.queue6->socketAddress.sin_addr.s_addr = MsgGetAgentBindIPAddress();
|
|
|
|
if (PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) {
|
|
memset(&(PlusPack.nmap.conn.queue5->socketAddress), 0, sizeof(PlusPack.nmap.conn.queue5->socketAddress));
|
|
PlusPack.nmap.conn.queue5->socketAddress.sin_family = AF_INET;
|
|
PlusPack.nmap.conn.queue5->socketAddress.sin_addr.s_addr = MsgGetAgentBindIPAddress();
|
|
}
|
|
|
|
/* Get root privs back for the bind. It's ok if this fails -
|
|
the user might not need to be root to bind to the port */
|
|
XplSetEffectiveUserId(0);
|
|
|
|
if (PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) {
|
|
PlusPack.nmap.conn.queue5->socket = ConnServerSocket(PlusPack.nmap.conn.queue5, 2048);
|
|
}
|
|
|
|
PlusPack.nmap.conn.queue6->socket = ConnServerSocket(PlusPack.nmap.conn.queue6, 2048);
|
|
|
|
if (XplSetEffectiveUser(MsgGetUnprivilegedUser()) < 0) {
|
|
XplConsolePrintf("bongopluspack: Could not drop to unprivileged user '%s'\r\n", MsgGetUnprivilegedUser());
|
|
if (PlusPack.nmap.conn.queue5) {
|
|
ConnFree(PlusPack.nmap.conn.queue5);
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
}
|
|
|
|
ConnFree(PlusPack.nmap.conn.queue6);
|
|
PlusPack.nmap.conn.queue6 = NULL;
|
|
return(-1);
|
|
}
|
|
|
|
if ((PlusPack.nmap.conn.queue5->socket == -1) || (PlusPack.nmap.conn.queue6->socket == -1)) {
|
|
XplConsolePrintf("bongopluspack: Could not bind to dynamic port\r\n");
|
|
if (PlusPack.nmap.conn.queue5) {
|
|
ConnFree(PlusPack.nmap.conn.queue5);
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
}
|
|
|
|
ConnFree(PlusPack.nmap.conn.queue6);
|
|
PlusPack.nmap.conn.queue6 = NULL;
|
|
return(-1);
|
|
}
|
|
|
|
if ((QueueRegister(PLUSPACK_AGENT, Q_FIVE, PlusPack.nmap.conn.queue5->socketAddress.sin_port) != REGISTRATION_COMPLETED)
|
|
|| (QueueRegister(PLUSPACK_AGENT, Q_DELIVER, PlusPack.nmap.conn.queue6->socketAddress.sin_port) != REGISTRATION_COMPLETED)) {
|
|
XplConsolePrintf("bongopluspack: Could not register with bongonmap\r\n");
|
|
if (PlusPack.nmap.conn.queue5) {
|
|
ConnFree(PlusPack.nmap.conn.queue5);
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
}
|
|
|
|
ConnFree(PlusPack.nmap.conn.queue6);
|
|
PlusPack.nmap.conn.queue6 = NULL;
|
|
return(-1);
|
|
}
|
|
} else {
|
|
if (PlusPack.nmap.conn.queue5) {
|
|
ConnFree(PlusPack.nmap.conn.queue5);
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
}
|
|
|
|
XplConsolePrintf("bongopluspack: Could not allocate connection.\r\n");
|
|
return(-1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
XplServiceCode(SignalHandler)
|
|
|
|
int
|
|
XplServiceMain(int argc, char *argv[])
|
|
{
|
|
int ccode;
|
|
XplThreadID id;
|
|
|
|
if (XplSetEffectiveUser(MsgGetUnprivilegedUser()) < 0) {
|
|
XplConsolePrintf("bongopluspack: Could not drop to unprivileged user '%s', exiting.\n", MsgGetUnprivilegedUser());
|
|
return(1);
|
|
}
|
|
XplInit();
|
|
|
|
XplSignalHandler(SignalHandler);
|
|
|
|
PlusPack.id.main = XplGetThreadID();
|
|
PlusPack.id.group = XplGetThreadGroupID();
|
|
|
|
PlusPack.state = PLUSPACK_STATE_INITIALIZING;
|
|
|
|
PlusPack.nmap.conn.queue5 = NULL;
|
|
PlusPack.nmap.conn.queue6 = NULL;
|
|
|
|
PlusPack.nmap.pool = NULL;
|
|
PlusPack.nmap.sleepTime = (5 * 60);
|
|
PlusPack.nmap.ssl.conn = NULL;
|
|
PlusPack.nmap.ssl.enable = FALSE;
|
|
PlusPack.nmap.ssl.context = NULL;
|
|
PlusPack.nmap.ssl.config.options = 0;
|
|
|
|
PlusPack.handle.directory = NULL;
|
|
PlusPack.handle.logging = NULL;
|
|
|
|
strcpy(PlusPack.nmap.address, "127.0.0.1");
|
|
|
|
XplSafeWrite(PlusPack.server.active, 0);
|
|
|
|
XplSafeWrite(PlusPack.nmap.queue.idle, 0);
|
|
XplSafeWrite(PlusPack.nmap.queue.active, 0);
|
|
XplSafeWrite(PlusPack.nmap.queue.maximum, 100000);
|
|
|
|
if (MemoryManagerOpen(PLUSPACK_AGENT) == TRUE) {
|
|
PlusPack.nmap.pool = MemPrivatePoolAlloc("PlusPack Connections", sizeof(PlusPackClient), 0, 3072, TRUE, FALSE, PlusPackClientAllocCB, NULL, NULL);
|
|
if (PlusPack.nmap.pool != NULL) {
|
|
XplOpenLocalSemaphore(PlusPack.sem.main, 0);
|
|
XplOpenLocalSemaphore(PlusPack.sem.shutdown, 1);
|
|
XplOpenLocalSemaphore(PlusPack.nmap.semaphore, 1);
|
|
XplOpenLocalSemaphore(PlusPack.nmap.queue.todo, 1);
|
|
} else {
|
|
MemoryManagerClose(PLUSPACK_AGENT);
|
|
|
|
XplConsolePrintf("bongopluspack: Unable to create connection pool; shutting down.\r\n");
|
|
return(-1);
|
|
}
|
|
} else {
|
|
XplConsolePrintf("bongopluspack: Unable to initialize memory manager; shutting down.\r\n");
|
|
return(-1);
|
|
}
|
|
|
|
ConnStartup(CONNECTION_TIMEOUT, TRUE);
|
|
|
|
MDBInit();
|
|
PlusPack.handle.directory = (MDBHandle)MsgInit();
|
|
if (PlusPack.handle.directory == NULL) {
|
|
XplBell();
|
|
XplConsolePrintf("bongopluspack: Invalid directory credentials; exiting!\r\n");
|
|
XplBell();
|
|
|
|
MemoryManagerClose(PLUSPACK_AGENT);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
We need to delay the startup of the plus-pack agent to allow SMTP to register with NMAP first.
|
|
|
|
fixme - when enhanced nmap registration is available; remove this delay!
|
|
*/
|
|
#if 0
|
|
XplDelay(20 * 1000);
|
|
#endif
|
|
|
|
NMAPInitialize();
|
|
|
|
SetCurrentNameSpace(NWOS2_NAME_SPACE);
|
|
SetTargetNameSpace(NWOS2_NAME_SPACE);
|
|
|
|
PlusPack.handle.logging = LoggerOpen("bongopluspack");
|
|
if (!PlusPack.handle.logging) {
|
|
XplConsolePrintf("bongopluspack: Unable to initialize logging; disabled.\r\n");
|
|
}
|
|
|
|
ReadConfiguration();
|
|
|
|
CONN_TRACE_INIT((char *)MsgGetWorkDir(NULL), "pluspack");
|
|
// CONN_TRACE_SET_FLAGS(CONN_TRACE_ALL); /* uncomment this line and pass '--enable-conntrace' to autogen to get the agent to trace all connections */
|
|
|
|
if (PlusPack.flags) {
|
|
if (QueueSocketInit() < 0) {
|
|
XplConsolePrintf("bongopluspack: Exiting.\r\n");
|
|
|
|
MemoryManagerClose(PLUSPACK_AGENT);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (XplSetRealUser(MsgGetUnprivilegedUser()) < 0) {
|
|
XplConsolePrintf("bongopluspack: Could not drop to unprivileged user '%s', exiting.\r\n", MsgGetUnprivilegedUser());
|
|
|
|
MemoryManagerClose(PLUSPACK_AGENT);
|
|
|
|
return 1;
|
|
}
|
|
|
|
PlusPack.nmap.ssl.enable = FALSE;
|
|
PlusPack.nmap.ssl.config.certificate.file = MsgGetTLSCertPath(NULL);
|
|
PlusPack.nmap.ssl.config.key.type = GNUTLS_X509_FMT_PEM;
|
|
PlusPack.nmap.ssl.config.key.file = MsgGetTLSKeyPath(NULL);
|
|
|
|
PlusPack.nmap.ssl.context = ConnSSLContextAlloc(&(PlusPack.nmap.ssl.config));
|
|
if (PlusPack.nmap.ssl.context) {
|
|
PlusPack.nmap.ssl.enable = TRUE;
|
|
}
|
|
|
|
NMAPSetEncryption(PlusPack.nmap.ssl.context);
|
|
|
|
PlusPack.state = PLUSPACK_STATE_RUNNING;
|
|
|
|
if (PlusPack.flags & PLUSPACK_FLAG_BIGBROTHER_ENABLED) {
|
|
XplBeginThread(&id, PlusPackQueueServer5, 8192, NULL, ccode);
|
|
} else {
|
|
ccode = 0;
|
|
}
|
|
|
|
if (!ccode) {
|
|
XplStartMainThread(PRODUCT_SHORT_NAME, &id, PlusPackQueueServer6, 8192, NULL, ccode);
|
|
} else {
|
|
XplConsolePrintf("bongopluspack: Unable to startup an NMAP queue server thread.\r\n");
|
|
}
|
|
} else {
|
|
XplConsolePrintf("bongopluspack: Not configured; unloading.\r\n");
|
|
}
|
|
|
|
XplUnloadApp(XplGetThreadID());
|
|
return(0);
|
|
}
|