OpenVMS Source Code Demos
SFF_DEMO_C
//================================================================================================
// title : SFF_DEMO_c_101.c
// author : Neil Rieck ( https://neilrieck.net )
// created: 2014/11/19
// build : $cc sff_demo_c
// $link sff_demo_c , -
// sys$input/opt
// sys$share:tcpip$smtp_mailshr.exe/share
// notes :
// 1) tcpip_send_from_file() only works with "TCPIP Services for OpenVMS"
// 2) contents of my static test file "sff_demo.txt" ------------------------------------
// MAIL FROM:<catbert@dilbert.com> <--- no w/s after the colon
// RCPT TO:<neil.rieck@bell.ca> <--- no w/s after the colon
// DATA
// Date: Wed, 19 Nov 2014 14:48:14 -0400 <<--- should use the current UTC
// Message-Id: <96080414481486@dilbert.com> <<--- change to avoid some spam tests
// From: catbert@dilbert.com (Funny Stuff)
// To: neil.rieck@bell.ca
// Subject: Test of SFF mechanism
// <<--- blank line is recommended
// This is the message text. Whatever. <<--- body
// ----------------------------------------------------------------------------------
// 3) tcpip_send_from_file() requires that your data begins immediately after the colon in fields
// "MAIL FROM:" and "RCPT TO:". No spaces or tabs. This is an oddity of tcpip_send_from_file
// because you can use white-space when connecting directly to port 25
// 4) "Message-Id:" is not mandatory but some anti-SPAM detectors require it. It must be unique
// because:
// 4a. some pop3 servers will throw away duplicate mail based upon "Message-Id:"
// 4b. some smtp clients will remember that you deleted a message with "Message-Id:" then
// will auto-delete new mail containing the same "Message-Id:" (Office Outlook does this)
// 5) "Date" is not mandatory but some anti-SPAM detectors require it
// 5a. This is nice to have since SMTP messages can be delayed by up to 4 hours
// 5b. some anti-SPAM detectors consider old stamps (which go to the bottom of a smtp message
// window) as suspicious.
// 5c. some anti-SPAM detectors consider future stamps (which go to the top of a smtp message
// window) as suspicious.
// history:
// ver who when what
// --- --- -------- ------------------------------------------------------------------------------
// 100 NSR 20141119 1. original effort (only works with a static file)
// 101 NSR 20141120 1. added code to create a unique file, timestamp, and message-id
//================================================================================================
//
// external references
//
#include <stdlib.h> //
#include <stdio.h> //
#include <time.h> //
#include <errno.h> //
#include <locale.h> //
#define __NEW_STARLET 1 // enable new (strict) starlet (OpenVMS Alpha 7.0)
#include <starlet.h> // vms specific - system library
#include <ssdef.h> // vms specific - system services constants
#include <sjcdef.h> // vms specific - system job control
#include <jbcmsgdef.h> // vms specific - job control message
#include <iosbdef.h> // vms specific - i/o status block
#include <iledef.h> // vms specific - Item List Entry 3 structure
//
// prototypes
//
long tcpip$smtp_send_from_file(char*, char*, long); // found in "sys$share:tcpip$smtp_mailshr.exe"
void get_datetime_str(char*); //
void get_datetime_smtp(char*); //
//
// variables
//
char fs1[99];
char fs2[99];
char temp[99];
char dtstamp[40];
long debug;
long rc;
FILE *file1 = 0;
extern int errno; // needed for "fprintf(stderr"
//
//==============================================================================
// main
//==============================================================================
void main(int argc, char *argv[]) {
printf("-i-pgm: %s\n",argv[0]); //
get_datetime_smtp(dtstamp); // get current date-time for SMTP
get_datetime_str(temp); // get current date-time for fname
sprintf(fs1,"%s%s%s","smtp-scratch-",temp,".txt"); // build fname string
//
printf("-i-creating file: %s\n",fs1);
file1 = fopen(fs1,"w", "rfm=var","rat=cr", "mrs=132"); // rec-fmt: variable rec-att: cr
if (file1==NULL) { //
perror("-e-The following error occurred"); // this function tacks on human-readable text
fprintf(stderr,"-e-error: %d opening %s\n",errno,fs1); // this function provides the error number
exit (2); // vms-e-
}else{ //
printf("-i-writing to file: %s\n",fs1);
fprintf(file1,"MAIL FROM:<catbert@dilbert.com>\n" );
fprintf(file1,"RCPT TO:<neil.rieck@bell.ca>\n" );
fprintf(file1,"DATA\n" );
fprintf(file1,"Date: %s\n", dtstamp ); //
fprintf(file1,"Message-Id: <%s@dilbert.com>\n",temp );
fprintf(file1,"From: catbert@dilbert.com (Funny Stuff)\n" );
fprintf(file1,"To: neil.rieck@bell.ca\n" );
fprintf(file1,"Subject: Test of SFF mechanism\n" );
fprintf(file1,"\n" ); // new rules say we need a blank line
fprintf(file1,"Test of SFF mechanism.\n\n" );
printf("-i-closing file: %s\n",fs1);
fclose(file1); // flush and close
} //
printf("-i-invoking: tcpip$smtp_send_from_file\n");
fs2[0] = '\0'; // init
debug = 0; //
rc = tcpip$smtp_send_from_file(fs1,fs2,debug); //
printf("status: %ld\n",rc); // display return code
printf("-i-deleting file: %s\n",fs1); //
rc = remove(fs1); //
if (rc!=0) { //
perror("-e-The following error occurred"); // this function tacks on human-readable text
fprintf(stderr,"-e-error: %d deleting %s\n",errno,fs1); // this function provides the error number
exit (2); // vms-e-
}
printf("-i-exiting: %s\n",argv[0]); //
exit(1); // vms-s-
}
//==============================================================================
// get_time_str
// note: date + time are concatinated to produce a unique file name
//==============================================================================
void get_datetime_str(char *buffer) {
struct timeb timebuffer; // for ftime()
struct tm *time_fields; // for localtime()
char millisecs[5]; //
char my_date_time[30]; //
//
ftime( &timebuffer ); // record current system time
sprintf(millisecs, "%03hu", timebuffer.millitm); // extract milliseconds as three chars
time_fields = localtime( &timebuffer.time ); // breakout other time fields
strftime( my_date_time, // yields: ccyymmddhhmmss
sizeof(my_date_time), //
"%Y%m%d%H%M%S", //
time_fields ); //
sprintf( buffer, // yields: ccyymmddhhmmssxxx
"%s%s", //
my_date_time, // ccyymmddhhmmss
millisecs); // xxx
}
//==============================================================================
// get_time_smtp
// note: produces a date-time stamp suitable for use with SMTP
//==============================================================================
void get_datetime_smtp(char *buffer) {
struct timeb timebuffer; // for ftime()
struct tm *time_fields; // for localtime()
char my_date_time[30]; //
long temp_mins, temp_hours; //
//
// here we want to return an SMTP date string like this:
// Wed, 19 Nov 2014 14:48:14 -0500
// see: RFC-5322, ISO-8601
//
ftime( &timebuffer ); // record current system time (snapshot)
setlocale(LC_ALL, "C"); //
time_fields = localtime( &timebuffer.time ); // breakout other time fields
//
// notes:
// 1) in 2014-11-xx "HP C V7.3-010 on OpenVMS Alpha V8.4" still does not support "%z" but does support "%Z"
// 2) divide by 36 only returns the correct result for so-called whole time zones. It does not return the
// correct result for half-shifted timezones like NST (Newfoundland Standard Time). See: ISO-8601
//
strftime( my_date_time, //
sizeof(my_date_time), //
"%a, %d %b %Y %H:%M:%S", // day dnum mon ccyy hh:mm:ss
time_fields ); //
#if 1 // this is the preferred universal solution
temp_mins = (time_fields->tm_gmtoff/60); // secs->mins (could be negative)
temp_hours = (temp_mins / 60); // mins->hours (could be negative)
temp_mins = abs(temp_mins % 60); // remainder (positive)
strftime( temp, //
sizeof(temp), //
"%a, %d %b %Y %H:%M:%S", // day dnum mon ccyy hh:mm:ss
time_fields ); //
sprintf(buffer, "%s %+03d%02d", temp, temp_hours, temp_mins); // tack offset onto date-time
#else // this common hack is sometimes wrong
//
// notes: time_fields->tm_gmtoff); yields: -18000 for EST
// time_fields->tm_gmtoff/36); yields: -500 for EST (yields wrong answer for NST/NDT)
//
sprintf(buffer, "%s %+05d", my_date_time, time_fields->tm_gmtoff/36); // tack offset onto date-time
#endif //
}