PMDF Programmer's Reference Manual
PMDF-PRM-6.0


Previous | Contents

1.12.2 Dequeuing messages

Each of the two programs shown in Examples 1-5 and 1-6 constitutes a PMDF-to-batch-SMTP channel which reads messages from a message queue, converting each message to a batch SMTP format stored in a file on disk. If the conversion is successful, then the message is dequeued and deferred otherwise. Sample output is given in Example 1-7 .

Note that these example programs always attempt to specify an envelope id in the batch SMTP message they output. This is done for illustration purposes only. In general, the code should check to see if the envelope id obtained with PMDF_get_envelope_id is of zero length. Only if it has non-zero length should it then be outputting an envelope id.


Note:

It is important to remember to define the PMDF_CHANNEL logical (OpenVMS) or environment variable (UNIX and NT) to be the name of the channel (in lower case) to be serviced by this program. Also, if experimenting from your own account, do not leave this logical or environment variable defined while not experimenting --- PMDF may see it when you send mail and submit that mail as though it was enqueued by the channel given by PMDF_CHANNEL. (This is a debugging feature.)

The following items of note are identified with callouts in each of the two programs:

  1. In the event of an error, the current message being processed is deferred and the program exits.
  2. get_message is a routine which will return true (1) if PMDF_get_message successfully accesses a message or false (0) otherwise. If PMDF_get_message returns any error other than PMDF__EOF, then the check routine, , is invoked.
  3. read_line is a routine which will return true (1) if PMDF_get_line successfully reads a line from a message or false (0) otherwise. If PMDF_read_line returns any error other than PMDF__EOF, then the check routine, , is invoked.
  4. open_outbound is a routine which opens an output file to which to write the batch SMTP command. Output from PMDF_get_unique_string is used in generating the file name.
  5. notify is a routine which, builds an RFC 1891 NOTIFY= parameter based upon the NOTARY flags for an envelope To: recipient.
  6. PMDF_initialize is invoked with the ischannel argument true.
  7. PMDF_dequeue_initialize creates and initializes a message dequeue context.
  8. Using the get_message routine, the program loops over all messages to be processed.
  9. Using PMDF_get_recipient, the program loops over the envelope To: address list in the currently accessed message.
  10. The NOTARY flags for the current envelope To: recipient are obtained with PMDF_get_recipient_flags.
  11. The disposition of the envelope To: recipient address is passed back to PMDF.
  12. Using the read_line routine, the program loops over the message header and body, copying each line to the batch SMTP file.
  13. Processing was successful; the processed message is dequeued.
  14. All done processing messages; dispose of the message dequeue context.

Example 1-5 Message dequeuing (Pascal)


(* api_example3.pas -- Dequeue a message and output it in batch SMTP format *) 
 
[inherit ('pmdf_exe:apidef')] program api_example3 (output); 
 
  type 
    uword     = [word] 0..65535; 
    string    = packed array [1..ALFA_SIZE] of char; 
    bigstring = packed array [1..BIGALFA_SIZE] of char; 
    vstring   = varying [64] of char; 
 
  var 
    dq_context                               : PMDF_dq; 
    empty                                    : varying [1] of char; 
    env_id, from_adr, host, orig_adr, to_adr : string; 
    env_id_len, from_adr_len, host_len, 
      orig_adr_len, to_adr_len, txt_len      : uword; 
    nflags, stat                             : integer; 
    outbound_open                            : boolean; 
    outfile                                  : text; 
    txt                                      : bigstring; 
 
procedure check (stat : integer); (1)
 
  var reason : varying [20] of char; 
 
  begin (* check *) 
    if not odd (stat) then begin 
      writev (reason, 'Error ', stat:0); 
      if dq_context <> nil then PMDF_defer_message (dq_context, true, reason); 
      if outbound_open then 
        close (file_variable := outfile, disposition := delete); 
      halt; 
    end; (* if *) 
  end; (* check *) 
 
function get_message : boolean; (2)
 
  var msg_file : string; msg_file_len : uword; 
 
  begin (* get_message *) 
    stat := PMDF_get_message (dq_context, msg_file, msg_file_len, 
                              from_adr, from_adr_len); 
    get_message := odd (stat); 
    if (not odd (stat)) and (stat <> PMDF__EOF) then check (stat); 
  end; (* get_message *) 
 
function read_line : boolean; (3)
 
  begin (* read_line *) 
    stat := PMDF_read_line (dq_context, txt, txt_len); 
    read_line := odd (stat); 
    if (not odd (stat)) and (stat <> PMDF__EOF) then check (stat); 
  end; (* read_line *) 
 
procedure open_outbound; (4)
 
  var 
    str     : string; 
    str_len : uword; 
 
  begin (* open_outbound *) 
    check (PMDF_get_unique_string (str, str_len)); 
    open (file_variable := outfile, 
          file_name := 'ZZ' + substr (str, 1, str_len) + '.00', 
          history := NEW, record_length := 1024); 
    stat := status (outfile); 
    if stat >= 0 then begin 
      rewrite (outfile); 
      outbound_open := true; 
    end else begin 
      writeln ('Pascal file error ', stat:0, '; aborting'); 
      check (0); 
    end; (* if *) 
  end; (* open_outbound *) 
 
function notify (nflags : integer) : vstring; (5)
 
  var str : vstring; 
 
  procedure add (bit : integer; toadd : varying [len] of char); 
    begin (* add *) 
      if 0 <> uand (nflags, bit) then begin 
        if length (str) = 0 then str := ' NOTIFY=' else str := str + ','; 
        str := str + toadd; 
      end; (* if *) 
    end; (* add *) 
 
  begin (* notify *) 
    str := ''; 
    add (PMDF_RECEIPT_NEVER,     'NEVER'); 
    add (PMDF_RECEIPT_FAILURES,  'FAILURE'); 
    add (PMDF_RECEIPT_DELAYS,    'DELAY'); 
    add (PMDF_RECEIPT_SUCCESSES, 'SUCCESS'); 
    notify := str; 
  end; (* notify *) 
 
begin (* api_example3 *) 
  empty         := ''; 
  dq_context    := nil; 
  outbound_open := false; 
  check (PMDF_initialize (true)); (6)
  check (PMDF_get_host_name (host, host_len)); 
  check (PMDF_dequeue_initialize (dq_context)); (7)
  while get_message do begin (8)
    check (PMDF_get_envelope_id (dq_context, env_id, env_id_len)); 
    open_outbound; 
    writeln (outfile, 'EHLO ', substr (host, 1, host_len)); 
    writeln (outfile, 'MAIL FROM:<', substr (from_adr, 1, from_adr_len), '>', 
             ' ENVID=', substr (env_id, 1, env_id_len)); 
    while odd (PMDF_get_recipient (dq_context, to_adr, to_adr_len, (9)
                                   orig_adr, orig_adr_len)) do begin 
      check (PMDF_get_recipient_flags (dq_context, nflags)); (10)
      writeln (outfile, 'RCPT TO:<', substr (to_adr, 1, to_adr_len), '>', 
               ' ORCPT=', substr (orig_adr, 1, orig_adr_len), 
               notify (nflags)); 
      check (PMDF_recipient_disposition (dq_context, nflags, (11)
                                PMDF_DISP_DELIVERED, 
                                substr (to_adr, 1, to_adr_len), 
                                substr (orig_adr, 1, orig_adr_len), empty)); 
    end; (* while *) 
    writeln (outfile, 'DATA'); 
    while read_line do begin (12)
      if txt_len > 0 then if txt[1] = '.' then write (outfile, '.'); 
      writeln (outfile, substr (txt, 1, txt_len)); 
    end; (* while *) 
    writeln (outfile, '.'); 
    writeln (outfile, 'QUIT'); 
    close (outfile); outbound_open := false; 
    check (PMDF_dequeue_message_end (dq_context, false, empty)); (13)
  end; (* while *) 
  check (PMDF_dequeue_end (dq_context)); (14)
  check (PMDF_done); 
end. (* api_example3 *) 

Example 1-6 Message dequeuing (C)


/* api_example4.c -- Dequeue a message and output it in batch SMTP format */ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#ifdef __VMS 
#include "pmdf_com:apidef.h" 
#else 
#include "/pmdf/include/apidef.h" 
#endif 
 
typedef char string[ALFA_SIZE+1]; 
 
string filename, from_adr, txt; 
int outbound_open, txt_len; 
PMDF_dq *dq_context = 0; 
FILE *outfile; 
 
void check (int stat) (1)
{ 
  char reason[20]; 
  if (!(1 & stat)) { 
    sprintf (reason, "Reason %d", stat); 
    if (dq_context) PMDFdeferMessage (&dq_context, 1, reason, strlen (reason)); 
    if (outbound_open) { 
      fclose (outfile); 
      remove (filename); 
    } 
    if (!stat) exit (0); 
    else exit (stat); 
  } 
} 
 
int get_message (void) (2)
{ 
    string msg_file; 
    int from_adr_len, msg_file_len, stat; 
 
    from_adr_len = msg_file_len = ALFA_SIZE; 
    stat = PMDFgetMessage (&dq_context, msg_file, &msg_file_len, 
                           from_adr, &from_adr_len); 
    if (!(1 & stat) && stat != PMDF__EOF) check (stat); 
    return (1 & stat); 
} 
 
int read_line (void) (3)
{ 
    int stat; 
 
    txt_len = BIGALFA_SIZE; 
    stat = PMDFreadLine (&dq_context, txt, &txt_len); 
    if ( !(1 & stat) && stat != PMDF__EOF) check (stat); 
    return (1 & stat); 
} 
 
void open_outbound (void) (4)
{ 
  char str[18+5+1]; 
  int str_len = 18; 
 
  check (PMDFgetUniqueString (str, &str_len)); 
  sprintf (filename, "ZZ%s.00", str); 
  outfile = fopen (filename, "w"); 
  if (!outfile) { 
    fprintf (stderr, "Error opening output file; aborting\n", filename); 
    check (0); 
  } 
  outbound_open = 1; 
} 
 
void add (int nflags, int bit, char *src, char *dst) 
{ 
  if (!(nflags & bit)) return; 
  if (*dst) strcat (dst, ","); 
  strcat (dst, src); 
} 
 
void make_notify (int nflags, char *buf) (5)
{ 
  *buf = '\0'; 
  add (nflags, PMDF_RECEIPT_NEVER,     "NEVER",   buf); 
  add (nflags, PMDF_RECEIPT_FAILURES,  "FAILURE", buf); 
  add (nflags, PMDF_RECEIPT_DELAYS,    "DELAY",   buf); 
  add (nflags, PMDF_RECEIPT_SUCCESSES, "SUCCESS", buf); 
} 
 
main () 
{ 
  string env_id, host, orig_adr, to_adr; 
  int env_id_len, nflags, host_len, orig_adr_len, to_adr_len; 
  char notify[64]; 
 
  outbound_open = 0; 
  check (PMDFinitialize (1)); (6)
  host_len = ALFA_SIZE; 
  check (PMDFgetHostName (host, &host_len)); 
  check (PMDFdequeueInitialize (&dq_context)); (7)
  while (get_message ()) { (8)
    env_id_len = ALFA_SIZE; 
    check (PMDFgetEnvelopeId (&dq_context, env_id, &env_id_len)); 
    open_outbound (); 
    fprintf (outfile, "EHLO %s\n", host); 
    fprintf (outfile, "MAIL FROM:<%s> ENVID=%s\n", from_adr, env_id); 
    to_adr_len = orig_adr_len = ALFA_SIZE; 
    while (1 & PMDFgetRecipient (&dq_context, to_adr, &to_adr_len, (9)
                                 orig_adr, &orig_adr_len)) 
    { 
      check (PMDFgetRecipientFlags (&dq_context, &nflags)); (10)
      make_notify (nflags, notify); 
      fprintf (outfile, "RCPT TO:<%s> ORCPT=%s", to_adr, orig_adr); 
      if (notify[0]) fprintf (outfile, " NOTIFY=%s\n", notify); 
      else fprintf (outfile, "\n"); 
      check (PMDFrecipientDisposition (&dq_context, nflags, (11)
                                       PMDF_DISP_DELIVERED, to_adr, 
                                       to_adr_len, orig_adr, orig_adr_len, 
                                       NULL, 0)); 
      to_adr_len = orig_adr_len = ALFA_SIZE; 
    } 
    fprintf (outfile, "DATA\n"); 
    while (read_line ()) { (12)
      if (txt_len > 0) if (txt[0] == '.') fprintf (outfile, "."); 
      fprintf (outfile, "%s\n", txt); 
    } 
    fprintf (outfile, ".\nQUIT\n"); 
    fclose (outfile); outbound_open = 0; 
    check (PMDFdequeueMessageEnd (&dq_context, 0, NULL, 0)); (13)
  } 
  check (PMDFdequeueEnd (&dq_context)); (14)
  check (PMDFdone ()); 
} 

Example 1-7 Output of Examples1-5and1-6


EHLO INNOSOFT.COM ENVID=01ISXU84PB929AMHQL@INNOSOFT.COM 
MAIL FROM:<fresnel@innosoft.com> 
RCPT TO:<mrochek@hmcvax.claremont.edu> 
  ORCPT=rfc822;m.freed@claremont.edu NOTIFY=FAILURES,DELAY 
DATA 
Received: from INNOSOFT.COM by INNOSOFT.COM (PMDF #1339 ) id 
 <01GP3A97QW9CAATXKZ@INNOSOFT.COM>; Tue, 22 Sep 1997 16:04:31 PDT 
Date: 22 Sep 1997 16:04:31 -0700 (PDT) 
From: "Fresnel the tabby cat" <fresnel@innosoft.com> 
Subject: Testing 
To: "Mrochek the weiner dog" <m.freed@claremont.edu> 
Message-id: <01GP3A97R5WIAATXKZ@INNOSOFT.COM> 
MIME-version: 1.0 
Content-type: TEXT/PLAIN; CHARSET=US-ASCII 
Content-transfer-encoding: 7BIT 
 
This is a test of the emergency broadcasting system. 
Please do not be alarmed.  Please do not hold your breath. 
 
Bye 
. 
QUIT 


Previous | Next | Contents