You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1479 lines
37 KiB
1479 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1987-1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
alformat.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines to format alert messages sent out by the
|
|
Alerter service.
|
|
|
|
Author:
|
|
|
|
Ported from LAN Man 2.0
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
Contains NT-specific code.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
|
|
08-July-1991 (ritaw)
|
|
Ported to NT. Converted to NT style.
|
|
|
|
--*/
|
|
|
|
#include "alformat.h" // Constant definitions
|
|
#include <windows.h> // GetDateFormat/GetTimeFormat
|
|
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// Global variables //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
|
|
CHAR MessageBuffer[MAX_ALERTER_MESSAGE_SIZE];
|
|
|
|
//-------------------------------------------------------------------//
|
|
// //
|
|
// Local function prototypes //
|
|
// //
|
|
//-------------------------------------------------------------------//
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlMakeMessageHeader(
|
|
IN LPTSTR From,
|
|
IN LPTSTR To,
|
|
IN DWORD MessageSubjectId,
|
|
IN DWORD AlertNotificationTime,
|
|
IN BOOL IsAdminAlert
|
|
);
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlAppendMessage(
|
|
IN DWORD MessageId,
|
|
OUT LPSTR MessageBuffer,
|
|
IN LPSTR *SubstituteStrings,
|
|
IN DWORD NumberOfSubstituteStrings
|
|
);
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlMakeMessageBody(
|
|
IN DWORD MessageId,
|
|
IN LPTSTR MergeStrings,
|
|
IN DWORD NumberOfMergeStrings
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
AlMakePrintMessage(
|
|
IN DWORD PrintMessageID,
|
|
IN LPTSTR DocumentName,
|
|
IN LPTSTR PrinterName,
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR StatusString
|
|
);
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlSendMessage(
|
|
IN LPTSTR MessageAlias
|
|
);
|
|
|
|
VOID
|
|
AlMakeTimeString(
|
|
DWORD * Time,
|
|
PCHAR String,
|
|
int StringLength
|
|
);
|
|
|
|
STATIC
|
|
BOOL
|
|
IsDuplicateReceiver(
|
|
LPTSTR Name
|
|
);
|
|
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlMakeMessageHeader(
|
|
IN LPTSTR From,
|
|
IN LPTSTR To,
|
|
IN DWORD MessageSubjectId,
|
|
IN DWORD AlertNotificationTime,
|
|
IN BOOL IsAdminAlert
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates the header of an alert message, and puts it in the
|
|
MessageBuffer. A message header takes the following form:
|
|
|
|
From: SPOOLER at \\PRT41130
|
|
To: DAISY
|
|
Subj: ** PRINTING NOTIFICATION **
|
|
Date: 06-23-91 01:16am
|
|
|
|
Arguments:
|
|
|
|
From - Supplies the component that raised the alert.
|
|
|
|
To - Supplies the message alias name of the recipient.
|
|
|
|
MessageSubjectId - Supplies an id which indicates the subject of the
|
|
alert.
|
|
|
|
AlertNotificationTime - Supplies the time of the alert notification.
|
|
|
|
IsAdminAlert - Supplies a flag which if TRUE indicates that the To line
|
|
should be created for multiple recipients.
|
|
|
|
Return Value:
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - if Unicode to ANSI conversion buffer cannot
|
|
be allocated.
|
|
|
|
NERR_Success - if successful.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Array of subtitution strings for an alert message
|
|
//
|
|
LPSTR SubstituteStrings[2];
|
|
|
|
//
|
|
// Tab read in from the message file
|
|
//
|
|
static CHAR TabMessage[80] = "";
|
|
|
|
LPSTR AnsiTo;
|
|
DWORD ToLineLength; // Number of chars on the To line
|
|
WORD MessageLength; // Returned by DosGetMessage
|
|
|
|
LPSTR AnsiAlertNames;
|
|
|
|
LPSTR FormatPointer1;
|
|
LPSTR FormatPointer2;
|
|
CHAR SaveChar;
|
|
|
|
CHAR szAlertTime[MAX_DATE_TIME_LEN];
|
|
|
|
LPSTR PlaceHolder = "X";
|
|
LPSTR PointerToPlaceHolder = NULL;
|
|
|
|
|
|
//
|
|
// Read in the message tab, if necessary
|
|
//
|
|
if (*TabMessage == AL_NULL_CHAR) {
|
|
|
|
if (DosGetMessage(
|
|
NULL, // String substitution table
|
|
0, // Number of entries in table above
|
|
(LPBYTE) TabMessage, // Buffer receiving message
|
|
sizeof(TabMessage), // Size of buffer receiving message
|
|
APE2_ALERTER_TAB, // Message number to retrieve
|
|
MESSAGE_FILENAME, // Name of message file
|
|
&MessageLength // Number of bytes returned
|
|
)) {
|
|
|
|
*TabMessage = AL_NULL_CHAR;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Creating a new alert message
|
|
//
|
|
MessageBuffer[0] = AL_NULL_CHAR;
|
|
|
|
//
|
|
// "From: <From> at \\<AlLocalComputerName>"
|
|
//
|
|
// Alerts received by the Alerter service all come from the local server.
|
|
//
|
|
SubstituteStrings[0] = NetpAllocStrFromWStr(From);
|
|
|
|
if (SubstituteStrings[0] == NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
|
|
if (AlLocalComputerNameA != NULL) {
|
|
SubstituteStrings[1] = AlLocalComputerNameA;
|
|
}
|
|
else {
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
return ERROR_GEN_FAILURE;
|
|
}
|
|
|
|
//
|
|
// Put the from line into the message buffer
|
|
//
|
|
AlAppendMessage(
|
|
APE2_ALERTER_FROM,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
2 // Number of strings to substitute into message
|
|
);
|
|
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
|
|
//
|
|
// "To: X"
|
|
//
|
|
// The 'X' is a place holder for the To message so that DosGetMessage
|
|
// can perform the substitution. We are not putting the real string
|
|
// because the message can either be sent to one recipient (non-admin
|
|
// alerts or to many recipient (admin alert).
|
|
//
|
|
SubstituteStrings[0] = PlaceHolder;
|
|
|
|
AlAppendMessage(
|
|
APE2_ALERTER_TO,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
1 // Number of strings to substitute into message
|
|
);
|
|
|
|
//
|
|
// Search for the place holder character and replace with zero terminator
|
|
//
|
|
PointerToPlaceHolder = strrchr(MessageBuffer, *PlaceHolder);
|
|
|
|
//
|
|
// If PointerToPlaceHolder == NULL, we have a big problem, but rather than
|
|
// choke, we'll just continue. The resulting message will be
|
|
// mis-formated (the place holder will still be there and the To name(s)
|
|
// will be on the next line) but it will still be sent.
|
|
//
|
|
|
|
if (PointerToPlaceHolder != NULL) {
|
|
*PointerToPlaceHolder = AL_NULL_CHAR;
|
|
}
|
|
|
|
if (To != NULL) {
|
|
AnsiTo = NetpAllocStrFromWStr(To);
|
|
if (AnsiTo == NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
else {
|
|
AnsiTo = NULL;
|
|
}
|
|
|
|
if (IsAdminAlert) {
|
|
|
|
//
|
|
// Do not send the message to the same person twice, since it is
|
|
// possible that the person is on the alert names list, as well as
|
|
// specified by To.
|
|
//
|
|
|
|
if (To != NULL && ! IsDuplicateReceiver(To)) {
|
|
|
|
//
|
|
// Print admin alerts, like printer is offline or out of paper,
|
|
// will be sent to the person who's printing as well as admins
|
|
// on the alertnames list.
|
|
//
|
|
|
|
strcat(MessageBuffer, AnsiTo);
|
|
strcat(MessageBuffer, " ");
|
|
ToLineLength = strlen(TabMessage) + strlen(AnsiTo) + sizeof(CHAR);
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// All admin alerts will have a NULL To field, except print admin
|
|
// alerts, e.g. ran out of paper while printing.
|
|
//
|
|
|
|
ToLineLength = strlen(TabMessage);
|
|
}
|
|
|
|
if (AlertNamesA != NULL) {
|
|
|
|
//
|
|
// AlertNamesA is space-separated.
|
|
//
|
|
|
|
AnsiAlertNames = AlertNamesA;
|
|
|
|
//
|
|
// Wrap the names to the next line if width of all alert names exceeds
|
|
// screen display width.
|
|
//
|
|
while ((strlen(AnsiAlertNames) + ToLineLength) > MESSAGE_WIDTH) {
|
|
|
|
FormatPointer1 = AnsiAlertNames + 1 +
|
|
(MESSAGE_WIDTH - ToLineLength);
|
|
SaveChar = *FormatPointer1;
|
|
*FormatPointer1 = AL_NULL_CHAR;
|
|
FormatPointer2 = strrchr(AnsiAlertNames, AL_SPACE_CHAR);
|
|
*FormatPointer2 = AL_NULL_CHAR;
|
|
strcat(MessageBuffer, AnsiAlertNames);
|
|
*FormatPointer2++ = AL_SPACE_CHAR;
|
|
*FormatPointer1 = SaveChar;
|
|
strcat(MessageBuffer, AL_EOL_STRING);
|
|
strcat(MessageBuffer, TabMessage);
|
|
AnsiAlertNames = FormatPointer2;
|
|
ToLineLength = strlen(TabMessage);
|
|
}
|
|
|
|
strcat(MessageBuffer, AnsiAlertNames);
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Non-admin alert
|
|
//
|
|
|
|
if (To != NULL) {
|
|
strcat(MessageBuffer, AnsiTo);
|
|
}
|
|
}
|
|
|
|
if (AnsiTo != NULL) {
|
|
NetApiBufferFree(AnsiTo);
|
|
}
|
|
|
|
strcat(MessageBuffer, AL_EOL_STRING);
|
|
|
|
//
|
|
// Append subject line to MessageBuffer
|
|
//
|
|
// "Subj: <Message string of MessageSubjectId>"
|
|
//
|
|
AlAppendMessage(
|
|
MessageSubjectId,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
0 // No substitution strings
|
|
);
|
|
|
|
AlMakeTimeString(
|
|
&AlertNotificationTime,
|
|
szAlertTime,
|
|
sizeof(szAlertTime)
|
|
);
|
|
|
|
SubstituteStrings[0] = szAlertTime;
|
|
|
|
//
|
|
// "Date: <mm/dd/yy hh:mm>"
|
|
//
|
|
AlAppendMessage(
|
|
APE2_ALERTER_DATE,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
1
|
|
);
|
|
|
|
strcat(MessageBuffer, AL_EOL_STRING);
|
|
|
|
return NERR_Success;
|
|
}
|
|
|
|
|
|
VOID
|
|
AlAdminFormatAndSend(
|
|
IN PSTD_ALERT Alert
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes an admin alert notification, formats it into an alert
|
|
message, and sends it to the admins with message aliases that are listed
|
|
on the alert names entry in the configuration.
|
|
|
|
An admin alert notification (arrived via the mailslot) has the following
|
|
form:
|
|
|
|
Timestamp of the alert event
|
|
"ADMIN"
|
|
"SERVER"
|
|
|
|
Message id of message
|
|
Number of merge strings which will be substituted into message
|
|
Merge strings, each separated by a zero terminator.
|
|
|
|
Arguments:
|
|
|
|
Alert - Supplies a pointer to the alert notification structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
LPTSTR AdminToAlert;
|
|
PADMIN_OTHER_INFO AdminInfo = (PADMIN_OTHER_INFO) ALERT_OTHER_INFO(Alert);
|
|
|
|
|
|
AdminToAlert = AlertNamesW;
|
|
|
|
|
|
IF_DEBUG(FORMAT) {
|
|
NetpKdPrint(("[Alerter] Got admin alert\n"));
|
|
}
|
|
|
|
while (AdminToAlert != NULL && *AdminToAlert != TCHAR_EOS) {
|
|
|
|
|
|
//
|
|
// Format the message for this alert name
|
|
//
|
|
status = AlMakeMessageHeader(
|
|
Alert->alrt_servicename,
|
|
NULL, // The To field is always NULL
|
|
APE2_ALERTER_ADMN_SUBJ,
|
|
Alert->alrt_timestamp,
|
|
TRUE // Admin alert
|
|
);
|
|
|
|
if (status != NERR_Success) {
|
|
NetpKdPrint((
|
|
"[Alerter] Alert not sent. Error making message header %lu\n",
|
|
status
|
|
));
|
|
return;
|
|
}
|
|
|
|
AlMakeMessageBody(
|
|
AdminInfo->alrtad_errcode,
|
|
(LPTSTR) ALERT_VAR_DATA(AdminInfo),
|
|
AdminInfo->alrtad_numstrings
|
|
);
|
|
|
|
|
|
//
|
|
// Send the message
|
|
//
|
|
(void) AlSendMessage(AdminToAlert);
|
|
|
|
AdminToAlert += (STRLEN(AdminToAlert) + 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlMakeMessageBody(
|
|
IN DWORD MessageId,
|
|
IN LPTSTR MergeStrings,
|
|
IN DWORD NumberOfMergeStrings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates the body of an alert message and append it to the
|
|
header already in MessageBuffer.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Supplies a message id of the core message to be sent.
|
|
|
|
MergeStrings - Supplies a pointer to strings that would make up the message
|
|
to be sent. The strings are separated by zero terminators.
|
|
|
|
NumberOfMergeStrings - Supplies the number of strings pointed to by
|
|
MergeStrings.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NET_API_STATUS status = NERR_Success;
|
|
DWORD i;
|
|
|
|
LPSTR AdminMessage;
|
|
LPSTR MergeTable[9];
|
|
CHAR String[34];
|
|
LPSTR SubstituteStrings[2];
|
|
|
|
LPSTR CRPointer;
|
|
LPSTR EndPointer;
|
|
|
|
|
|
//
|
|
// Message utility can only handle substitution of up to 9 strings.
|
|
//
|
|
if (NumberOfMergeStrings > 9) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the buffer which receives the message from the
|
|
// message file.
|
|
//
|
|
if ((AdminMessage = (LPSTR) LocalAlloc(
|
|
LMEM_ZEROINIT,
|
|
MAX_ALERTER_MESSAGE_SIZE
|
|
)) == NULL) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (MessageId == NO_MESSAGE) {
|
|
|
|
//
|
|
// Merge strings are the literal message (don't format). Print one
|
|
// per line.
|
|
//
|
|
for (i = 0; i < NumberOfMergeStrings; i++) {
|
|
|
|
SubstituteStrings[0] = NetpAllocStrFromWStr(MergeStrings);
|
|
if (SubstituteStrings[0] == NULL) {
|
|
(void) LocalFree(AdminMessage);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
strcat(MessageBuffer, SubstituteStrings[0]);
|
|
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
strcat(MessageBuffer, AL_EOL_STRING);
|
|
MergeStrings = STRCHR(MergeStrings, TCHAR_EOS);
|
|
MergeStrings++;
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Set up the MergeStrings table for the call to AlAppendMessage
|
|
//
|
|
for (i = 0; i < NumberOfMergeStrings; i++) {
|
|
|
|
IF_DEBUG(FORMAT) {
|
|
NetpKdPrint(("Merge string #%lu: " FORMAT_LPTSTR "\n", i, MergeStrings));
|
|
}
|
|
|
|
MergeTable[i] = NetpAllocStrFromWStr(MergeStrings);
|
|
if (MergeTable[i] == NULL) {
|
|
DWORD j;
|
|
|
|
(void) LocalFree(AdminMessage);
|
|
for (j = 0; j < i; j++) {
|
|
(void) LocalFree(MergeTable[j]);
|
|
}
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
MergeStrings = STRCHR(MergeStrings, TCHAR_EOS);
|
|
MergeStrings++;
|
|
}
|
|
|
|
|
|
status = AlAppendMessage(
|
|
MessageId,
|
|
AdminMessage,
|
|
MergeTable,
|
|
NumberOfMergeStrings
|
|
);
|
|
|
|
//
|
|
// Free memory allocated for Unicode to ANSI conversion
|
|
//
|
|
for (i = 0; i < NumberOfMergeStrings; i++) {
|
|
(void) LocalFree(MergeTable[i]);
|
|
}
|
|
|
|
if (status != NERR_Success) {
|
|
|
|
//
|
|
// Could not find message of MessageId in message file. An error
|
|
// message will be sent.
|
|
//
|
|
_itoa(MessageId, String, 10);
|
|
SubstituteStrings[0] = String;
|
|
AlAppendMessage(
|
|
APE2_ALERTER_ERROR_MSG,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
1
|
|
);
|
|
|
|
status = NERR_Success;
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Got the message
|
|
//
|
|
|
|
//
|
|
// Process the message from DosGetMessage to replace the CR and
|
|
// LF with equivalent display characters.
|
|
//
|
|
CRPointer = strchr(AdminMessage, AL_CR_CHAR);
|
|
EndPointer = CRPointer;
|
|
|
|
while (CRPointer) {
|
|
|
|
*CRPointer = '\040';
|
|
CRPointer++;
|
|
|
|
//
|
|
// Check for end of message
|
|
//
|
|
if (*CRPointer != AL_NULL_CHAR) {
|
|
|
|
//
|
|
// Use display end-of-line character
|
|
//
|
|
*CRPointer = AL_EOL_CHAR;
|
|
}
|
|
|
|
EndPointer = CRPointer;
|
|
CRPointer = strchr(CRPointer, AL_CR_CHAR);
|
|
}
|
|
|
|
//
|
|
// Wipe out rest of garbage in the message
|
|
//
|
|
if (EndPointer) {
|
|
*EndPointer = AL_EOL_CHAR;
|
|
*(EndPointer + 1) = AL_NULL_CHAR;
|
|
}
|
|
|
|
strcat(MessageBuffer, AdminMessage);
|
|
}
|
|
}
|
|
(void) LocalFree(AdminMessage);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AlUserFormatAndSend(
|
|
IN PSTD_ALERT Alert
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a user alert notification, formats it into an alert
|
|
message, and sends it to the user. If there is an error sending to the
|
|
user message alias, the message is send to the computer name.
|
|
|
|
A user alert notification (arrived via the mailslot) has the following
|
|
form:
|
|
|
|
Timestamp of the alert event
|
|
"USER"
|
|
"SERVER"
|
|
|
|
Message id of message
|
|
Number of merge strings which will be substituted into message
|
|
Merge strings, each separated by a zero terminator.
|
|
|
|
Username
|
|
\\ComputerNameOfUser
|
|
|
|
Arguments:
|
|
|
|
Alert - Supplies a pointer to the alert notification structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
PUSER_OTHER_INFO UserInfo = (PUSER_OTHER_INFO) ALERT_OTHER_INFO(Alert);
|
|
|
|
DWORD i;
|
|
|
|
LPTSTR MergeStrings;
|
|
LPTSTR Username;
|
|
LPTSTR ComputerNameOfUser;
|
|
LPTSTR To = NULL;
|
|
|
|
|
|
IF_DEBUG(FORMAT) {
|
|
NetpKdPrint(("[Alerter] Got user alert\n"));
|
|
}
|
|
|
|
MergeStrings = (LPTSTR) ALERT_VAR_DATA(UserInfo);
|
|
|
|
//
|
|
// Name of user to be notified of the alert is found after the merge
|
|
// strings.
|
|
//
|
|
for (Username = MergeStrings, i = 0; i < UserInfo->alrtus_numstrings; i++) {
|
|
Username += STRLEN(Username) + 1;
|
|
}
|
|
|
|
//
|
|
// Computer name of user is in the alert structure after the user name.
|
|
//
|
|
ComputerNameOfUser = Username + STRLEN(Username) + 1;
|
|
|
|
//
|
|
// If both username and computer name are not specified, cannot send the
|
|
// message
|
|
//
|
|
if (*Username == TCHAR_EOS && *ComputerNameOfUser == TCHAR_EOS) {
|
|
NetpKdPrint((
|
|
"[Alerter] Alert not sent. Username or computername not specified.\n"
|
|
));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Setup the To pointer to point to the message alias that canonicalize
|
|
// properly. If there's a problem with the username, we will send the
|
|
// message to the computer name.
|
|
//
|
|
|
|
if (AlCanonicalizeMessageAlias(Username) == NERR_Success) {
|
|
To = Username;
|
|
}
|
|
|
|
//
|
|
// Computer name may or may not be preceeded by backslashes
|
|
//
|
|
if (*ComputerNameOfUser == TCHAR_BACKSLASH &&
|
|
*(ComputerNameOfUser + 1) == TCHAR_BACKSLASH) {
|
|
ComputerNameOfUser += 2;
|
|
}
|
|
|
|
if (AlCanonicalizeMessageAlias(ComputerNameOfUser) == NERR_Success &&
|
|
To == NULL) {
|
|
To = ComputerNameOfUser;
|
|
}
|
|
|
|
//
|
|
// Both username and computer name are not acceptable.
|
|
//
|
|
if (To == NULL) {
|
|
NetpKdPrint((
|
|
"[Alerter] Alert not sent. Username & computername are not acceptable.\n"
|
|
));
|
|
return;
|
|
}
|
|
|
|
status = AlMakeMessageHeader(
|
|
Alert->alrt_servicename,
|
|
To,
|
|
APE2_ALERTER_USER_SUBJ,
|
|
Alert->alrt_timestamp,
|
|
FALSE // Not an admin alert
|
|
);
|
|
|
|
if (status != NERR_Success) {
|
|
NetpKdPrint((
|
|
"[Alerter] Alert not sent. Error making message header %lu\n",
|
|
status
|
|
));
|
|
return;
|
|
}
|
|
|
|
AlMakeMessageBody(
|
|
UserInfo->alrtus_errcode,
|
|
MergeStrings,
|
|
UserInfo->alrtus_numstrings
|
|
);
|
|
|
|
//
|
|
// Send the message
|
|
//
|
|
if (AlSendMessage(To) == NERR_Success) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If To points to the Username and the send was not successful, try
|
|
// sending to the computer name of user.
|
|
//
|
|
if (To == Username) {
|
|
(void) AlSendMessage(ComputerNameOfUser);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AlPrintFormatAndSend(
|
|
IN PSTD_ALERT Alert
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a print alert notification, formats it into an alert
|
|
message, and sends it to the computer name which the print job submitter
|
|
is on. If the print alert is for certain type of printing error, like
|
|
the printer is offline, the admins on the alert names list gets the alert
|
|
message as well.
|
|
|
|
Arguments:
|
|
|
|
Alert - Supplies a pointer to the alert notification structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PPRINT_OTHER_INFO PrintInfo = (PPRINT_OTHER_INFO) ALERT_OTHER_INFO(Alert);
|
|
|
|
LPTSTR ComputerName = NULL;
|
|
LPTSTR Username = NULL;
|
|
LPTSTR DocumentName = NULL;
|
|
LPTSTR PrinterName = NULL;
|
|
LPTSTR ServerName = NULL;
|
|
LPTSTR StatusString = NULL;
|
|
|
|
DWORD PrintMessageID = APE2_ALERTER_PRINTING_SUCCESS;
|
|
|
|
BOOL AdminAlso;
|
|
|
|
LPTSTR AdminToAlert;
|
|
|
|
|
|
IF_DEBUG(FORMAT) {
|
|
NetpKdPrint(("[Alerter] Got print alert\n"));
|
|
}
|
|
|
|
ComputerName = (LPTSTR) ALERT_VAR_DATA(PrintInfo);
|
|
Username = ComputerName + STRLEN(ComputerName) + 1;
|
|
DocumentName = Username + STRLEN(Username) + 1;
|
|
PrinterName = DocumentName + STRLEN(DocumentName) + 1;
|
|
ServerName = PrinterName + STRLEN(PrinterName) + 1;
|
|
StatusString = ServerName + STRLEN(ServerName) + 1;
|
|
|
|
if ( ((PrintInfo->alrtpr_status & PRJOB_QSTATUS) == PRJOB_QS_PRINTING)
|
|
&& (PrintInfo->alrtpr_status & PRJOB_COMPLETE) ) {
|
|
PrintMessageID = APE2_ALERTER_PRINTING_SUCCESS;
|
|
}
|
|
else {
|
|
if ( *StatusString == '\0' ) {
|
|
PrintMessageID = APE2_ALERTER_PRINTING_FAILURE;
|
|
}
|
|
else {
|
|
PrintMessageID = APE2_ALERTER_PRINTING_FAILURE2;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If error, notify admins on the alert names list also, besides the print
|
|
// job submitter.
|
|
//
|
|
AdminAlso = (PrintInfo->alrtpr_status &
|
|
(PRJOB_DESTOFFLINE | PRJOB_INTERV | PRJOB_ERROR));
|
|
|
|
//
|
|
// Computer name may or may not be preceeded by backslashes
|
|
//
|
|
if (*ComputerName == TCHAR_BACKSLASH &&
|
|
*(ComputerName + 1) == TCHAR_BACKSLASH) {
|
|
ComputerName += 2;
|
|
}
|
|
|
|
(VOID) AlCanonicalizeMessageAlias(ComputerName);
|
|
|
|
//
|
|
// Format message for the print job submitter
|
|
//
|
|
MessageBuffer[0] = AL_NULL_CHAR;
|
|
AlMakePrintMessage( PrintMessageID,
|
|
DocumentName,
|
|
PrinterName,
|
|
ServerName,
|
|
StatusString );
|
|
|
|
//
|
|
// If the print job submitter is one of admins specified on the alert
|
|
// names list, don't send the message to the submitter yet. All the
|
|
// admins on alert names list will receive the message during admin
|
|
// processing below.
|
|
//
|
|
if ((AdminAlso && !IsDuplicateReceiver(ComputerName) ) ||
|
|
! AdminAlso) {
|
|
|
|
if ( AlSendMessage(ComputerName) != NERR_Success ) {
|
|
(void) AlSendMessage(Username);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are done if this is not an admin related alert.
|
|
//
|
|
if (! AdminAlso) {
|
|
return;
|
|
}
|
|
|
|
AdminToAlert = AlertNamesW;
|
|
|
|
//
|
|
// Send alert message to every admin on the alert names list.
|
|
//
|
|
while (AdminToAlert != NULL && *AdminToAlert != TCHAR_EOS) {
|
|
|
|
MessageBuffer[0] = AL_NULL_CHAR;
|
|
AlMakePrintMessage( PrintMessageID,
|
|
DocumentName,
|
|
PrinterName,
|
|
ServerName,
|
|
StatusString );
|
|
|
|
//
|
|
// Send message to the admin.
|
|
//
|
|
(void) AlSendMessage(AdminToAlert);
|
|
|
|
AdminToAlert += (STRLEN(AdminToAlert) + 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
AlMakePrintMessage(
|
|
IN DWORD PrintMessageID,
|
|
IN LPTSTR DocumentName,
|
|
IN LPTSTR PrinterName,
|
|
IN LPTSTR ServerName,
|
|
IN LPTSTR StatusString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
PrintMessageID - ID of message string to use
|
|
|
|
DocumentName, PrinterName, ServerName, StatusString(Optional) - insert strings passed by spooler.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LPSTR SubstituteStrings[4];
|
|
|
|
|
|
SubstituteStrings[0] = NetpAllocStrFromWStr(DocumentName);
|
|
if (SubstituteStrings[0] == NULL) {
|
|
return;
|
|
}
|
|
SubstituteStrings[1] = NetpAllocStrFromWStr(PrinterName);
|
|
if (SubstituteStrings[1] == NULL) {
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
return;
|
|
}
|
|
SubstituteStrings[2] = NetpAllocStrFromWStr(ServerName);
|
|
if (SubstituteStrings[2] == NULL) {
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
NetApiBufferFree(SubstituteStrings[1]);
|
|
return;
|
|
}
|
|
SubstituteStrings[3] = NULL;
|
|
if ( *StatusString != '\0' ) {
|
|
SubstituteStrings[3] = NetpAllocStrFromWStr(StatusString);
|
|
if (SubstituteStrings[3] == NULL) {
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
NetApiBufferFree(SubstituteStrings[1]);
|
|
NetApiBufferFree(SubstituteStrings[2]);
|
|
return;
|
|
}
|
|
}
|
|
AlAppendMessage(
|
|
PrintMessageID,
|
|
MessageBuffer,
|
|
SubstituteStrings,
|
|
*StatusString == '\0' ? 3 : 4
|
|
);
|
|
|
|
NetApiBufferFree(SubstituteStrings[0]);
|
|
NetApiBufferFree(SubstituteStrings[1]);
|
|
NetApiBufferFree(SubstituteStrings[2]);
|
|
if ( SubstituteStrings[3] )
|
|
NetApiBufferFree(SubstituteStrings[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlSendMessage(
|
|
IN LPTSTR MessageAlias
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends the message in MessageBuffer to the specified
|
|
message alias. If an error occurs while sending the message, it will
|
|
be logged to the error log file.
|
|
|
|
Arguments:
|
|
|
|
MessageAlias - Supplies the message alias of recipient of the message.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
static NET_API_STATUS PreviousStatus = NERR_Success;
|
|
NET_API_STATUS Status;
|
|
|
|
LPWSTR MessageW;
|
|
DWORD MessageSize;
|
|
|
|
MessageW = NetpAllocWStrFromStr(MessageBuffer);
|
|
if (MessageW == NULL) {
|
|
NetpKdPrint(("[Alerter] AlSendMessage: NetpAllocWStrFromStr failed\n"));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// fixes alterts to DOS clients and garbage in NT to NT altert message
|
|
MessageSize = wcslen( MessageW ) * sizeof(WCHAR) ;
|
|
//
|
|
// Send a directed message to the specified message alias
|
|
//
|
|
|
|
IF_DEBUG(FORMAT) {
|
|
NetpKdPrint(("\n\nMessage To " FORMAT_LPTSTR "\n\n", MessageAlias));
|
|
NetpDbgHexDump((LPBYTE) MessageW, MessageSize);
|
|
}
|
|
|
|
if ((Status = NetMessageBufferSend(
|
|
NULL,
|
|
MessageAlias,
|
|
AlLocalComputerNameW,
|
|
(LPBYTE) MessageW,
|
|
MessageSize
|
|
)) != NERR_Success) {
|
|
|
|
NetpKdPrint(("[Alerter] Error sending message to "
|
|
FORMAT_LPTSTR " %lu\n", MessageAlias, Status));
|
|
|
|
if (Status != NERR_NameNotFound &&
|
|
Status != NERR_BadReceive &&
|
|
Status != NERR_UnknownServer &&
|
|
Status != PreviousStatus) {
|
|
|
|
AlHandleError(AlErrorSendMessage, Status, MessageAlias);
|
|
PreviousStatus = Status;
|
|
}
|
|
|
|
}
|
|
|
|
NetApiBufferFree(MessageW);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
NET_API_STATUS
|
|
AlAppendMessage(
|
|
IN DWORD MessageId,
|
|
OUT LPSTR MessageBuffer,
|
|
IN LPSTR *SubstituteStrings,
|
|
IN DWORD NumberOfSubstituteStrings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gets the message, as specified by the message id, from a
|
|
predetermined message file. It then appends the message to the
|
|
MessageBuffer.
|
|
|
|
Arguments:
|
|
|
|
MessageId - Supplies the message id of message to get from message file.
|
|
|
|
MessageBuffer - Supplies a pointer to the buffer which the message is
|
|
appended to.
|
|
|
|
SubstituteStrings - Supplies an array of strings to substitute into the
|
|
message.
|
|
|
|
NumberOfSubstituteStrings - Supplies the number of strings in array of
|
|
SunstituteStrings
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
WORD MessageLength = 0;
|
|
NET_API_STATUS status;
|
|
|
|
LPBYTE RetrievedMessage;
|
|
LPBYTE ResultMessage = NULL;
|
|
|
|
|
|
//
|
|
// Allocate memory for the buffer which receives the message from the
|
|
// message file.
|
|
//
|
|
if ((RetrievedMessage = (LPBYTE) LocalAlloc(
|
|
0,
|
|
MAX_ALERTER_MESSAGE_SIZE+1
|
|
)) == NULL) {
|
|
return GetLastError();
|
|
}
|
|
|
|
|
|
if ((status = (NET_API_STATUS) DosGetMessage(
|
|
SubstituteStrings,
|
|
(WORD) NumberOfSubstituteStrings,
|
|
RetrievedMessage,
|
|
MAX_ALERTER_MESSAGE_SIZE,
|
|
(WORD) MessageId,
|
|
MESSAGE_FILENAME,
|
|
&MessageLength
|
|
)) != 0) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
RetrievedMessage[MessageLength] = AL_NULL_CHAR;
|
|
|
|
//
|
|
// Set the result message to the beginning of message
|
|
// if there are no spaces in the message.
|
|
//
|
|
if (ResultMessage == NULL) {
|
|
ResultMessage = RetrievedMessage;
|
|
}
|
|
|
|
strcat(MessageBuffer, ResultMessage);
|
|
|
|
CleanUp:
|
|
|
|
LocalFree(RetrievedMessage);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
STATIC
|
|
BOOL
|
|
IsDuplicateReceiver(
|
|
LPTSTR Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function compares the specified name with the names on the alert
|
|
names list and returns TRUE if there is a match; FALSE otherwise.
|
|
|
|
Arguments:
|
|
|
|
Name - Supplies a name to compare with the alert names list.
|
|
|
|
Return Value:
|
|
|
|
TRUE if match any name; FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
LPTSTR AdminToAlert = AlertNamesW;
|
|
|
|
|
|
while (AdminToAlert != NULL && *AdminToAlert != TCHAR_EOS) {
|
|
|
|
if (STRICMP(Name, AdminToAlert) == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
AdminToAlert = STRCHR(AdminToAlert, TCHAR_EOS);
|
|
AdminToAlert++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
AlFormatErrorMessage(
|
|
IN NET_API_STATUS Status,
|
|
IN LPTSTR MessageAlias,
|
|
OUT LPTSTR ErrorMessage,
|
|
IN DWORD ErrorMessageBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function formats 3 strings and place them, NULL separated, into
|
|
the supplied ErrorMessage buffer. The strings appear in the following
|
|
order:
|
|
Status
|
|
MessageAlias
|
|
Message which was not send
|
|
|
|
Arguments:
|
|
|
|
Status - Supplies the status code of the error.
|
|
|
|
MessageAlias - Supplies the message alias of the intended recipient.
|
|
|
|
ErrorMessage - Returns the formatted error message in this buffer.
|
|
|
|
ErrorMessageBufferSize - Supplies the size of the error message buffer
|
|
in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LPTSTR MessageBufferPointer;
|
|
LPTSTR MBPtr;
|
|
LPTSTR MBPtr2;
|
|
|
|
DWORD SizeOfString;
|
|
|
|
LPTSTR MessageBufferW;
|
|
|
|
CHAR MessageBufferTmp[MAX_ALERTER_MESSAGE_SIZE];
|
|
|
|
|
|
RtlZeroMemory(ErrorMessage, ErrorMessageBufferSize);
|
|
|
|
//
|
|
// Don't muck with the actual message buffer itself because it
|
|
// may still be in use.
|
|
//
|
|
strcpy(MessageBufferTmp, MessageBuffer);
|
|
|
|
//
|
|
// Put status in error message buffer
|
|
//
|
|
ultow(Status, ErrorMessage, 10);
|
|
|
|
MBPtr = &ErrorMessage[STRLEN(ErrorMessage) + 1];
|
|
|
|
//
|
|
// Put message alias in error message buffer
|
|
//
|
|
STRCPY(MBPtr, MessageAlias);
|
|
MBPtr += (STRLEN(MessageAlias) + 1);
|
|
|
|
//
|
|
// Put the message that failed to send in error message buffer
|
|
//
|
|
|
|
MessageBufferW = NetpAllocWStrFromStr(MessageBufferTmp);
|
|
if (MessageBufferW == NULL) {
|
|
return;
|
|
}
|
|
|
|
MessageBufferPointer = MessageBufferW;
|
|
|
|
while (MBPtr2 = STRCHR(MessageBufferPointer, AL_EOL_WCHAR)) {
|
|
|
|
*MBPtr2++ = TCHAR_EOS;
|
|
SizeOfString = (DWORD) ((LPBYTE)MBPtr2 - (LPBYTE)MessageBufferPointer) + sizeof(TCHAR);
|
|
|
|
//
|
|
// Check for error message buffer overflow
|
|
//
|
|
if ((LPBYTE)MBPtr - (LPBYTE)ErrorMessage + SizeOfString >=
|
|
ErrorMessageBufferSize) {
|
|
break;
|
|
}
|
|
|
|
STRCPY(MBPtr, MessageBufferPointer);
|
|
STRCAT(MBPtr, AL_CRLF_STRING);
|
|
MBPtr += SizeOfString / sizeof(TCHAR);
|
|
|
|
MessageBufferPointer = MBPtr2;
|
|
}
|
|
|
|
if (((LPBYTE)MBPtr - (LPBYTE)ErrorMessage +
|
|
STRLEN(MessageBufferPointer) * sizeof(TCHAR)) >
|
|
ErrorMessageBufferSize) {
|
|
|
|
//
|
|
// Put as much info into the error message buffer as possible
|
|
//
|
|
STRNCPY(MBPtr,
|
|
MessageBufferPointer,
|
|
ErrorMessageBufferSize/sizeof(TCHAR) - (int)(MBPtr - ErrorMessage));
|
|
ErrorMessage[(ErrorMessageBufferSize/sizeof(TCHAR))-1] = TCHAR_EOS;
|
|
|
|
} else {
|
|
STRCPY(MBPtr, MessageBufferPointer);
|
|
}
|
|
|
|
NetApiBufferFree(MessageBufferW);
|
|
}
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
AlCanonicalizeMessageAlias(
|
|
LPTSTR MessageAlias
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function canonicalizes the message alias by calling
|
|
I_NetNameCanonicalize.
|
|
|
|
Arguments:
|
|
|
|
MessageAlias - Supplies the message alias of an intended recipient for
|
|
the alert message.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS Status;
|
|
|
|
|
|
//
|
|
// Canonicalize message alias which will receive message
|
|
//
|
|
Status = I_NetNameCanonicalize(
|
|
NULL,
|
|
MessageAlias,
|
|
MessageAlias,
|
|
(STRLEN(MessageAlias) + 1) * sizeof(TCHAR),
|
|
NAMETYPE_USER,
|
|
0
|
|
);
|
|
|
|
if (Status != NERR_Success) {
|
|
|
|
NetpKdPrint(("[Alerter] Error canonicalizing message alias " FORMAT_LPTSTR " %lu\n",
|
|
MessageAlias, Status));
|
|
AlHandleError(AlErrorSendMessage, Status, MessageAlias);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
AlMakeTimeString(
|
|
DWORD * Time,
|
|
PCHAR String,
|
|
int StringLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts the UTC time expressed in seconds since 1/1/70
|
|
to an ASCII String.
|
|
|
|
Arguments:
|
|
|
|
Time - Pointer to the number of seconds since 1970 (UTC).
|
|
|
|
String - Pointer to the buffer to place the ASCII representation.
|
|
|
|
StringLength - The length of String in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
time_t LocalTime;
|
|
DWORD dwTimeTemp;
|
|
struct tm TmTemp;
|
|
SYSTEMTIME st;
|
|
int cchT=0, cchD;
|
|
|
|
NetpGmtTimeToLocalTime(*Time, &dwTimeTemp);
|
|
|
|
//
|
|
// Cast the DWORD returned by NetpGmtTimeToLocalTime up to
|
|
// a time_t. On 32-bit, this is a no-op. On 64-bit, this
|
|
// ensures the high DWORD of LocalTime is zeroed out.
|
|
//
|
|
LocalTime = (time_t) dwTimeTemp;
|
|
|
|
net_gmtime(&LocalTime, &TmTemp);
|
|
|
|
st.wYear = (WORD)(TmTemp.tm_year + 1900);
|
|
st.wMonth = (WORD)(TmTemp.tm_mon + 1);
|
|
st.wDay = (WORD)(TmTemp.tm_mday);
|
|
st.wHour = (WORD)(TmTemp.tm_hour);
|
|
st.wMinute = (WORD)(TmTemp.tm_min);
|
|
st.wSecond = (WORD)(TmTemp.tm_sec);
|
|
st.wMilliseconds = 0;
|
|
|
|
cchD = GetDateFormatA(GetThreadLocale(),
|
|
0,
|
|
&st,
|
|
NULL,
|
|
String,
|
|
StringLength);
|
|
|
|
if (cchD != 0)
|
|
{
|
|
*(String + cchD - 1) = ' '; /* replace NULLC with blank */
|
|
|
|
cchT = GetTimeFormatA(GetThreadLocale(),
|
|
TIME_NOSECONDS,
|
|
&st,
|
|
NULL,
|
|
String + cchD,
|
|
StringLength - cchD);
|
|
|
|
if (cchT == 0)
|
|
{
|
|
//
|
|
// If this gets hit, MAX_DATE_TIME_LEN (in netapi\inc\timelib.h)
|
|
// needs to be increased
|
|
//
|
|
ASSERT(FALSE);
|
|
*(String + cchD - 1) = '\0';
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|