Figure 8: Program IFS3MAIL1

      * This program demonstrates creating/sending an e-mail message
      * for each order in the "shipped orders" files.
      *
      * If compiling this for the first time, create a binding
      * directory for e-mail by typing:
      *   CRTBNDDIR BNDDIR(mylib/EMAIL)
      *   ADDBNDDIRE BNDDIR(mylib/EMAIL) OBJ((QTCP/QTMMSNDM *SRVPGM))
      *
      * To Compile:
      *   CRTBNDRPG IFS3MAIL1 SRCFILE(mylib/QRPGLESRC) DBGVIEW(*LIST)
      *
     H DFTACTGRP(*NO) OPTION(*SRCSTMT: *NODEBUGIO: *NOSHOWCPY)
     H BNDDIR('QC2LE': 'EMAIL')

     FSHPORDERS IF   E             DISK    BLOCK(*YES)
     FSHPDETAIL IF   E           K DISK

      /copy ifsio_h
      /copy iconv_h
      /copy sendmail_h
      /copy errno_h

     D CreateMsg       PR
     D   NameTo                     256A   varying const
     D   AddrTo                     256A   varying const
     D   NameFrom                   256A   varying const
     D   AddrFrom                   256A   varying const
     D   FirstName                   50A   varying const
     D   OrderNo                     10A   const
     D   OrderDate                     D   const
     D   MsgFile                    256A   varying
     D SendMsg         PR
     D   FileName                   256A   varying const
     D   AddrTo                     256A   varying const
     D   AddrFrom                   256A   varying const
     D do_iconv        PR           256A   varying
     D    Trans                            likeds(iconv_t) const
     D    Text                      256A   varying value
     D MailDate        PR            31A
     D ReportError     PR

     D SENDER_EMAIL    C                   'custserv@example.com'
     D filename        s            256A   varying

      /free

         // ************************************
         //  Read through the "Shipped Orders"
         //  file.  For each shipped order, do
         //  the following:
         //
         //    a) Create a text file containing
         //       an e-mail message.
         //
         //    b) Send that e-mail.
         // ************************************ 
         
         read SHPORDERS;

         dow not %eof(SHPORDERS);

            CreateMsg( %trimr(FirstName) + ' ' + %trimr(LastName)
                     : %trimr(EmailAddr)
                     : 'Acme Customer Service'
                     : SENDER_EMAIL
                     : %trimr(FirstName)
                     : OrderNo
                     : OrderDate
                     : FileName );

            SendMsg( FileName
                   : %trimr(EmailAddr)
                   : SENDER_EMAIL );

            read SHPORDERS;

         enddo;  
		
A
         

         *inlr = *on;

      /end-free

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * CreateMsg():  Create a text file that's formatted as
      *               an e-mail message.
      *
      *     NameTo = (input) Recipient's name
      *     AddrTo = (input) Recipient's e-mail address
      *   NameFrom = (input) Sender's name
      *   AddrFrom = (input) Sender's e-mail address
      *  FirstName = (input) Recipient's first name
      *    OrderNo = (input) Order number that has shipped
      *  OrderDate = (input) Date that order was placed
      *    MsgFile = (output) Filename in the IFS where the
      *                       message was saved.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P CreateMsg       B
     D CreateMsg       PI
     D   NameTo                     256A   varying const
     D   AddrTo                     256A   varying const
     D   NameFrom                   256A   varying const
     D   AddrFrom                   256A   varying const
     D   FirstName                   50A   varying const
     D   OrderNo                     10A   const
     D   OrderDate                     D   const
     D   MsgFile                    256A   varying

     D get_errno       PR              *   ExtProc('__errno')
     D ptrToErrno      s               *
     D errno           s             10I 0 based(ptrToErrno)

     D CRLF            C                   x'0d25'
     D fd              s             10I 0
     D hdr             s           2048A   varying
     D msg             s           2048A   varying
     D FileNo          s             10I 0 inz(0)

      /free

        //  When the O_EXCL flag is passed, open() will fail
        //  and set errno to EEXIST if the file already exists.
        //
        //  Here, we use that to create a unique filename.

        dou (fd <> -1);

           FileNo += 1;
           MsgFile = '/tmp/ship_notify_'+ %editc(FileNo:'X') +'.txt';
           fd = open( MsgFile
                    : O_CREAT + O_EXCL + O_WRONLY + O_CCSID
                       + O_TEXTDATA + O_TEXT_CREAT
                    : M_RDWR
                    : 367
                    : 0 );

           if (fd = -1);
              ptrToErrno = get_errno();
              if (errno <> EEXIST);
                 ReportError();
              endif;
           endif;

        enddo;
		
B
        

        //
        // *** Write e-mail header to the text file ***
        //

        hdr = 'To: '   + NameTo   + ' <' + AddrTo   + '>' + CRLF
            + 'From: ' + NameFrom + ' <' + AddrFrom + '>' + CRLF
            + 'Date: ' + MailDate() + CRLF
            + 'Subject: Order ' + %trimr(OrderNo) + ' shipped!' + CRLF
            + CRLF;

        callp write(fd: %addr(hdr)+2: %len(hdr));

        //
        // *** Write top of e-mail message to the text file ***
        //

        msg = 'Dear ' + FirstName +',' + CRLF
            + CRLF
            + 'The following order that you placed on '
            + %char(OrderDate:*ISO) + ' has been shipped!' + CRLF
            + CRLF
            + 'A summary of order #' + %trimr(OrderNo) + ' follows:'
            + CRLF
            + CRLF
            + 'ItemNo        Description        Quantity    Price' 
            + CRLF
            + '------ ------------------------- -------- --------' 
            + CRLF;

        callp write(fd: %addr(msg)+2: %len(msg));

        //
        // *** Add order details to the e-mail message ***
        //

        setll OrderNo SHPDETAIL;
        reade OrderNo SHPDETAIL;

        dow not %eof(SHPDETAIL);
           msg = ItemNo + ' '
               + ItemDesc + '  '
               + %editc(QtyShp:'L') + ' '
               + %editc(Price:'L')
               + CRLF;
           callp write(fd: %addr(msg)+2: %len(msg));
           reade OrderNo SHPDETAIL;
        enddo;

        callp close(fd);

      /end-free
     P                 E

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * SendMsg():  Send E-mail Message
      *
      *    Filename = (input) name of file containing the message
      *                       that is to be sent.
      *      AddrTo = (input) E-mail address of recipient
      *    AddrFrom = (input) E-mail address of sender
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P SendMsg         B
     D SendMsg         PI
     D   FileName                   256A   varying const
     D   AddrTo                     256A   varying const
     D   AddrFrom                   256A   varying const

     D NullError       DS
     D  BytesProv                    10I 0 inz(0)
     D  BytesAvail                   10I 0 inz(0)

     D ascii_from      s                   like(AddrFrom)
     D ascii_to        s                   like(AddrTo)

     D conv            ds                  likeds(iconv_t)
     D conv_from       ds                  likeds(QtqCode_t)
     D                                     inz(*likeds)
     D conv_to         ds                  likeds(QtqCode_t)
     D                                     inz(*likeds)

     D recip           ds                  likeds(ADDTO0100)
     D                                     dim(1)

      /free

         //
         //  The QtmmSendMail API requires that the From and To
         //  addresses be in CCSID 500.
         //
         //  The iconv() API can be used to convert from one
         //  CCSID to another.  (0 = Current Job's CCSID)
         //

         conv_from.CCSID = 0;
         conv_to.CCSID = 500;

         conv = QtqIconvOpen( conv_to : conv_from );
         if (conv.return_value = -1);
            ReportError();
         endif;

         ascii_from = do_iconv(conv: AddrFrom);
         ascii_to = do_iconv(conv: AddrTo);

         iconv_close(conv);

     
    // Recipients are specified as a data structure.  Note
         // that this is an array, because you can have more than
         // one recipient if you like.
         //
         // DistType can be ADDR_NORMAL, ADDR_CC or ADDR_BCC

         recip(1).NextOffset = %size(ADDTO0100);
         recip(1).AddrFormat = 'ADDR0100';
         recip(1).DistType   = ADDR_NORMAL;
         recip(1).Reserved   = 0;
         recip(1).SmtpAddr   = ascii_to;
         recip(1).AddrLen    = %len(ascii_to);

         //
         // The QtmmSendMail API deletes the text file
         // when it is done sending it.
         //

         QtmmSendMail( FileName
                     : %len(FileName)
                     : ascii_from
                     : %len(ascii_from)
                     : recip
                     : %elem(recip)
                     : NullError );
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * do_iconv(): Shortcut wrapper for the iconv() API.
      *
      *     Trans = (input) Translator returned by iconv()
      *      Text = (input) Text to translate
      *
      *  Returns the translated text
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P do_iconv        B
     D do_iconv        PI           256A   varying
     D    Trans                            likeds(iconv_t) const
     D    Text                      256A   varying value

     D p_input         s               *
     D p_output        s               *
     D Output          s           1024A   varying
     D InLeft          s             10U 0
     D OutLeft         s             10U 0

      /free

           InLeft = %len(Text);
           OutLeft = InLeft;
           %len(Output) = OutLeft;
           p_input = %addr(text) + 2;
           p_output = %addr(output) + 2;

           if (iconv(Trans: p_input: InLeft: p_output: OutLeft) = -1);
              ReportError();
           endif;

           return Output;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  MailDate():  Returns the current date, formatted for use
      *               in an e-mail message.
      *
      *     For example:  'Sat, 23 Oct 2004 14:42:06 -0500'
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

     P MailDate        B
     D MailDate        PI            31A

     D CEELOCT         PR                  opdesc
     D   Lilian                      10I 0
     D   Seconds                      8F
     D   Gregorian                   23A
     D   fc                          12A   options(*omit)

     D CEEUTCO         PR                  opdesc
     D   Hours                       10I 0
     D   Minutes                     10I 0
     D   Seconds                      8F

     D CEEDATM         PR                  opdesc
     D   input_secs                   8F   const
     D   date_format                 80A   const options(*varsize)
     D   char_date                   80A   options(*varsize)
     D   feedback                    12A   options(*omit)

     D rfc2822         c                   'Www, DD Mmm YYYY HH:MI:SS'
     D junk1           s              8F
     D junk2           s             10I 0
     D junk3           s             23A
     D hours           s             10I 0
     D mins            s             10I 0
     D tz_hours        s              2P 0
     D tz_mins         s              2P 0
     D tz              s              5A   varying
     D CurTime         s              8F
     D Temp            s             25A

      /free

         //
         //  Calculate the Timezone in format '+0000', for example,
         //    CST should show up as '-0600'
         //

         CEEUTCO(hours: mins: junk1);
         tz_hours = %abs(hours);
         tz_mins = mins;

         if (hours < 0);
            tz = '-';
         else;
            tz = '+';
         endif;

         tz += %editc(tz_hours:'X') + %editc(tz_mins:'X');

         //
         //  Get the current time and convert it to the format
         //    specified for e-mail in RFC 2822
         //

         CEELOCT(junk2: CurTime: junk3: *omit);
         CEEDATM(CurTime: rfc2822: Temp: *omit);

         return Temp + ' ' + tz;

      /end-free
     P                 E