/*****************************************************************************/ /* report.c Send a report to configurable email client, OPCOM target and log. VERSION HISTORY --------------- 27-MAY-2017 MGD initial */ /*****************************************************************************/ /* standard C header files */ #include #include #include #include #include #include #include /* VMS related header files */ #include #include #include #include #include #include #include "report.h" #include "util.h" #include "acmeport/vms.h" #define FI_LI "REPORT", __LINE__ /*****************************************************************************/ /* Report this via configurable OPCOM, email address(es), and into the log. The first '\n' delimitted line is treated as a subject in mail and a "header" line in OPCOM. Remaining lines become the body. */ void ReportThis (char *text) { int status, target; char *cptr, *toptr, *sptr; /*********/ /* begin */ /*********/ if (cptr = UtilTrnLnm ("WCME_OPCOM", "LNM$SYSTEM", 0)) target = ReportOpcomTargetOf(cptr); else target = ReportOpcomTargetOf("CENTRAL"); if (cptr = UtilTrnLnm ("WCME_MAIL", "LNM$SYSTEM", 0)) toptr = strdup(cptr); else toptr = NULL; if (target) ReportOpcom (target, text); if (toptr) { cptr = sptr = strdup(text); while (*cptr && *cptr != '\n') *cptr++; if (*cptr) *cptr++ = '\0'; else cptr = sptr; ReportMail (MAIL_PERSONAL, toptr, sptr, cptr); free (sptr); free (toptr); } /* finally write it to the log file () */ vmsdbg (text); } /*****************************************************************************/ /* Use the VMS callable mail interface to create and send a VMS mail message. 'To' can be a list of comma-separated addresses. 'Subject' is a null-terminated string. 'Body' is a null-terminated string of '\n'-separated lines of plain text. Just truncates anything longer than 255 characters (body excluded, body records included)! */ int ReportMail ( char *PersonalName, char *To, char *Subject, char *Body ) { int status; unsigned long SendContext = 0; char *cptr, *sptr; struct { short int buf_len; short int item; void *buf_addr; unsigned short *ret_len; } BodyPartItem [] = { { 0, MAIL$_SEND_RECORD, 0, 0 }, { 0, MAIL$_NOSIGNAL, 0, 0 }, {0,0,0,0} }, PersonalNameItem [] = { { 0, MAIL$_SEND_PERS_NAME, PersonalName, 0 }, { 0, MAIL$_NOSIGNAL, 0, 0 }, {0,0,0,0} }, SendUserNameItem [] = { { 0, MAIL$_SEND_USERNAME, 0, 0 }, { 0, MAIL$_NOSIGNAL, 0, 0 }, {0,0,0,0} }, SubjectItem [] = { { 0, MAIL$_SEND_SUBJECT, Subject, 0 }, { 0, MAIL$_NOSIGNAL, 0, 0 }, {0,0,0,0} }, NoSignalItem [] = { { 0, MAIL$_NOSIGNAL, 0, 0 }, {0,0,0,0} }, NullItem = {0,0,0,0}; /*********/ /* begin */ /*********/ if (PersonalName != NULL && PersonalName[0]) { PersonalNameItem[0].buf_len = strlen(PersonalName); if (PersonalNameItem[0].buf_len > 255) PersonalNameItem[0].buf_len = 255; status = mail$send_begin (&SendContext, &PersonalNameItem, &NullItem); } else status = mail$send_begin (&SendContext, &NoSignalItem, &NullItem); if ((status & 1) == 0) EXIT_FI_LI(status); /* a single, or multiple comma-separated addresses */ for (cptr = To; *cptr && isspace(*cptr); cptr++); if (!*cptr) cptr = DEFAULT_MAIL; while (*cptr) { if (!*cptr) break; sptr = cptr; while (*cptr && *cptr != ',') cptr++; if (*cptr) *cptr++ = '\0'; SendUserNameItem[0].buf_addr = sptr; SendUserNameItem[0].buf_len = strlen(sptr); if (SendUserNameItem[0].buf_len > 255) SendUserNameItem[0].buf_len = 255; status = mail$send_add_address (&SendContext, &SendUserNameItem, &NullItem); if ((status & 1) == 0) EXIT_FI_LI(status); } SubjectItem[0].buf_len = strlen(Subject); if (SubjectItem[0].buf_len > 255) SubjectItem[0].buf_len = 255; status = mail$send_add_attribute (&SendContext, &SubjectItem, &NullItem); if ((status & 1) == 0) EXIT_FI_LI(status); cptr = Body; while (*cptr) { BodyPartItem[0].buf_addr = cptr; while (*cptr && *cptr != '\n') cptr++; BodyPartItem[0].buf_len = cptr - (char*)BodyPartItem[0].buf_addr; if (BodyPartItem[0].buf_len > 255) BodyPartItem[0].buf_len = 255; if (*cptr) cptr++; status = mail$send_add_bodypart (&SendContext, &BodyPartItem, &NullItem); if ((status & 1) == 0) EXIT_FI_LI(status); } status = mail$send_message (&SendContext, &NoSignalItem, &NoSignalItem); if ((status & 1) == 0) EXIT_FI_LI(status); mail$send_end (&SendContext, &NullItem, &NullItem); return (SS$_NORMAL); } /****************************************************************************/ /* $FAO formatted print statement to OPCOM. A fixed-size, internal buffer of 986 bytes maximum is used and the result output as an OPCOM message. */ int ReportOpcom ( int OpcomTarget, char *text ) { static $DESCRIPTOR (OpcomDsc, ""); static $DESCRIPTOR (OpcomMsgDsc, ""); int length, status; char *cptr, *sptr, *zptr; struct { unsigned long TargetType; unsigned long RequestId; char MsgText [986+1]; } OpcomMsg; /*********/ /* begin */ /*********/ zptr = (sptr = OpcomMsg.MsgText) + sizeof(OpcomMsg.MsgText)-1; for (cptr = text; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; length = sptr - OpcomMsg.MsgText; OpcomMsgDsc.dsc$a_pointer = (char*)&OpcomMsg.MsgText; OpcomMsg.TargetType = OPC$_RQ_RQST + ((OpcomTarget & 0xffffff) << 8); OpcomMsg.RequestId = 0; OpcomDsc.dsc$a_pointer = (char*)&OpcomMsg; OpcomDsc.dsc$w_length = length + 8; status = sys$sndopr (&OpcomDsc, 0); if ((status & 1) == 0) EXIT_FI_LI(status); return (status); } /*****************************************************************************/ /* Return an integer value representing the OPCOM target string. Zero indicates an error. */ int ReportOpcomTargetOf (char *cptr) { int OpcomTarget; /*********/ /* begin */ /*********/ OpcomTarget = 0; while (*cptr && isspace(*cptr)) cptr++; if (!*cptr) return (DEFAULT_OPCOM); while (*cptr) { while (*cptr == '(' || *cptr == ',' || *cptr == ')') cptr++; if (!*cptr) break; if (!strncasecmp (cptr, "ALL", 3)) OpcomTarget = 0xffffffff; else if (!strncasecmp (cptr, "NONE", 4)) OpcomTarget = 0; else if (!strncasecmp (cptr, "CENTRAL", 7)) OpcomTarget |= OPC$M_OPR_CENTRAL; else if (!strncasecmp (cptr, "PRINTER", 7)) OpcomTarget |= OPC$M_OPR_PRINTER; else if (!strncasecmp (cptr, "TAPES", 5)) OpcomTarget |= OPC$M_OPR_TAPES; else if (!strncasecmp (cptr, "DISKS", 5)) OpcomTarget |= OPC$M_OPR_DISKS; else if (!strncasecmp (cptr, "DEVICES", 7)) OpcomTarget |= OPC$M_OPR_DEVICES; else if (!strncasecmp (cptr, "CARDS", 5)) OpcomTarget |= OPC$M_OPR_CARDS; else if (!strncasecmp (cptr, "NETWORK", 7)) OpcomTarget |= OPC$M_OPR_NETWORK; else if (!strncasecmp (cptr, "CLUSTER", 7)) OpcomTarget |= OPC$M_OPR_CLUSTER; else if (!strncasecmp (cptr, "SECURITY", 8)) OpcomTarget |= OPC$M_OPR_SECURITY; else if (!strncasecmp (cptr, "REPLY", 5)) OpcomTarget |= OPC$M_OPR_REPLY; else if (!strncasecmp (cptr, "SOFTWARE", 8)) OpcomTarget |= OPC$M_OPR_SOFTWARE; else if (!strncasecmp (cptr, "LICENSE", 7)) OpcomTarget |= OPC$M_OPR_LICENSE; else if (!strncasecmp (cptr, "OPER2", 5)) OpcomTarget |= OPC$M_OPR_USER2; else if (!strncasecmp (cptr, "OPER3", 5)) OpcomTarget |= OPC$M_OPR_USER3; else if (!strncasecmp (cptr, "OPER4", 5)) OpcomTarget |= OPC$M_OPR_USER4; else if (!strncasecmp (cptr, "OPER5", 5)) OpcomTarget |= OPC$M_OPR_USER5; else if (!strncasecmp (cptr, "OPER6", 5)) OpcomTarget |= OPC$M_OPR_USER6; else if (!strncasecmp (cptr, "OPER7", 5)) OpcomTarget |= OPC$M_OPR_USER7; else if (!strncasecmp (cptr, "OPER8", 5)) OpcomTarget |= OPC$M_OPR_USER8; else if (!strncasecmp (cptr, "OPER9", 5)) OpcomTarget |= OPC$M_OPR_USER9; else if (!strncasecmp (cptr, "OPER10", 6)) OpcomTarget |= OPC$M_OPR_USER10; else if (!strncasecmp (cptr, "OPER11", 6)) OpcomTarget |= OPC$M_OPR_USER11; else if (!strncasecmp (cptr, "OPER12", 6)) OpcomTarget |= OPC$M_OPR_USER12; else /* must be here after OPER1n for the obvious reason */ if (!strncasecmp (cptr, "OPER1", 5)) OpcomTarget |= OPC$M_OPR_USER1; else return (0); while (isalnum(*cptr)) cptr++; } return (OpcomTarget); } /*****************************************************************************/