home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / srev13g.zip / POSTMAIL.80 < prev    next >
Text File  |  1999-02-18  |  28KB  |  815 lines

  1. /* a sample of a SRE-http "post-filter" -- 13 May 1997
  2. This will mail a message to selected users, depending on the value
  3. of the request selector, or the client's IP address.
  4. For general notes on how  POSTFILT is called, see the bottom of this file.
  5.  
  6.     ----------------------- A Mail Notification Facility ----------------
  7.  
  8. This will automatically send "e-mail alerts" to specified recipients given specified events.
  9. It calls a local version of the SREF_MAILIT procedure.
  10.  
  11. It requires that a valid SMTP Gateway be available (the SMTP Gateway
  12. is set by running SRE-http's configurator and modifying the SMTP_GATEWAY variable)
  13. Note that if you may be able to use OS/2's SENDMAIL program to use the server as
  14. an SMTP gateway (see the TCP/IP command reference documentation).
  15.  
  16. To use this routine, you will need to set up an "event" list.  The event list
  17. should contain the following information:
  18.  a)   What type of event to examine (client or request selector)
  19.  b)   The value that triggers a "match" (i.e.; a client's address, or a request for a particular file)
  20.  c)   The list of e-mail addresses to send "e-mail alerts" to
  21.  d)   An optional message to include in these alerts.
  22.  e)   An optional subject line
  23.  
  24. This routine uses the EVENTS.field.n  stem variable to store this event list.
  25.  
  26.   field should take one of 4 values
  27.      a)TYPE   : Either CLIENT or REQUEST (REQUEST is the "request selector")
  28.      b)VALUE : An IP (name or numeric) address, or a target request selector.  
  29.               Either may contain * characters;
  30.               (either as domain wildcards or as a wildcard)
  31.      c)RECIPIENTS: A space delimited list of e-mail  addresses
  32.      d)MESSAGE : An optional message.  It may contain CRLFs, and be quite long.
  33.      e)SUBJECT: An optional 1 line message to use as the SUBJECT.
  34.  
  35.    n is an integer value (that should run from 1.. "# of events")
  36.  
  37. You also must set EVENTS.0 equal to the "# of  events"
  38.  
  39. The algorithim works by:
  40.   From m=1.. to EVENTS.0
  41.       If EVENTS.TYPE.m=CLIENT, then see if client's numeric IP address
  42.           matches EVENTS.VALUE.m (with * acceptable as a wildcard)
  43.       If EVENTS.TYPE.m=REQUEST, see if the client's request selector matches EVENTS.VALUE.m,
  44.           (with * signalling that abbreviation matching should be used).
  45.           NOTE: The SEL variable contains the original request selector, before modifications
  46.                 by SRE-http.  The match is against the entire request selector,
  47.                 not just the Action!  Thus, a SEL of FOO.HTM?this_one
  48.                 will NOT match a target of FOO.HTM (but will match FOO.HTM*)
  49.                 In comparision, exact matches (say,
  50.                 in the access_file) compare the action to the target -- so
  51.                 any ?xxx is ignored.
  52.  
  53.  
  54.   If either occurs
  55.       Create a note containing time,date, server name, client's name, SRE-http status
  56.       message, and  EVENTS.MESSAGE.m
  57.            Note that EVENTS.MESSAGE.m is optional.
  58.       If EVENTS.SUBJECT.j is missing, a generic subject line is used.
  59.       Sent this note to each e-mail addresss listed in EVENT.RECIPIENTS.m
  60.  
  61. If there is not SMTP_GATEWAY specified, or EVENTS.0=0, then nothing 
  62. is done.
  63.  
  64. Note that there may be multiple matches; so that several different e-mail alerts (to
  65. different sets of e-mail addresses, some of which may contain common 
  66. addresses) may be generated by each call to this routine.
  67.  
  68. Example  -- note that the numbering goes from 1 (first event) to 3 (third event):
  69.  
  70. EVENTS.0=3
  71.  
  72. EVENTS.TYPE.1="CLIENT"
  73. EVENTS.VALUE.1="*.*.*.*"
  74. EVENTS.RECIPIENTS.1="bob@hisorg.net  jill@staff.agency.gov "
  75.      Note that EVENTS.MESSAGE.1 is not set
  76.  
  77. EVENTS.TYPE.2="REQUEST"
  78. EVENTS.VALUE.2="PROJECTS/PROJ1.HTM"
  79. EVENTS.RECIPIENTS.2="ANDREW@myorg.org"
  80. EVENTS.MESSAGE.2="A request for PROJ1 was recieved "
  81. events.subject.2=' PROJ1 Request '
  82.  
  83. EVENTS.TYPE.3="REQUEST"
  84. EVENTS.VALUE.2="\PUT_FILE*"
  85. EVENTS.RECIPIENTS.3="WEBMASTER@MYORG.ORG"
  86. EVENTS.MESSAGE.3="A file upload has been recieved! "||crlf||" You may want to check it?"
  87.   Note the use of CRLF to add a line feed to the message.
  88.  
  89. Note when EVENTS.TYPE.m=REQUEST:
  90.   all / are converted to \ (in both the SEL and EV*ENTS.VALUE.n), and
  91.   leading and trailing \ are stripped
  92.  
  93. HINT: if you are using OS/2's SENDMAIL as an SMTP gateway, you might want to
  94. read the short appendix at the bottom of this file.
  95.  
  96.  
  97.  
  98.             --------------------------------------------------
  99. */
  100.  
  101.  
  102.  
  103.   
  104. postmail:
  105. CRLF = '0d0a'x
  106. signal on syntax name error2
  107. signal on error name error2
  108.  
  109. /*  ==============  INSERT  EVENTS list here   ================  */
  110.  
  111. EVENTS.0=0
  112.  
  113. /* optional: set verbose=1 to echo status stuff, 2 more stuff, 0 for quiet operation */
  114. verbose=1
  115.  
  116. /* optional: name of sender. If left blank, or =0, a generic name is used */
  117. sender_name=' '
  118.  
  119.  
  120. /* ============ DO NOT CHANGE BELOW HERE  ===================== */
  121. /* args sent here:
  122. post_filter_message,source0,request0,seloriginal,tempfile,
  123. servername,HOST_NICKNAME,used_file,thereferer,tcache
  124. */
  125.  
  126.  
  127. parse arg amessage,source,request,sel,tempfile,servername,host_nickname,used_file,thereferer
  128. parse var source serveraddr serverport transaction_number clientaddr clientport
  129.  
  130. GATEWAY=' '
  131. AFF='SREF_'||SERVERPORT||'_SMTP_GATEWAY'
  132. IF HOST_NICKNAME<>' ' THEN do
  133.    AFF2=AFF2||'.'||HOST_NICKNAME
  134.    GATEWAY=VALUE(AFF2,,'OS2ENVIRONMENT')
  135. end
  136. IF GATEWAY=' ' THEN
  137.   GATEWAY=VALUE(AFF,,'OS2ENVIRONMENT')
  138.  
  139. if symbol('VERBOSE')<>'VAR' then verbose=0
  140.  
  141. if symbol('sender_name')<>'VAR' then sender_name=' '
  142. if sender_name=0 then sender_name=' '
  143.  
  144. if gateway=0 then do                    /* if no gateway specified, do nothing */
  145. /*  call say_stuff*/     /* enable this to get simple pmprintf output */
  146.   call pmprintf_sref(' POSTMAIL: No gateway specified ')
  147.   signal off error ; signal off syntax
  148.   return ' '
  149. end
  150. if events.0=0 then do
  151. /*  call say_stuff*/     /* enable this to get simple pmprintf output */
  152. end
  153.  
  154. sname=servername
  155. cname=clientaddr
  156. alphapos=verify(cNAME,'1234567890.')
  157. if alphapos=0 then  do        /* is numeric ip */
  158.           astat=sockgethostbyaddr(clientaddr,'stuff.!')
  159.           cname=upper(stuff.!name)
  160.           if abbrev(cname,'STUFF.!')=1 then cname=clientaddr
  161. end
  162.  
  163. atime=time()
  164. adate=date()
  165. CRLF = '0d0a'x
  166.  
  167. /* loop through events list .. */
  168. didit=0
  169. do jj=1 to events.0
  170.     if symbol('EVENTS.TYPE.'||jj)<>'VAR' then do
  171.         if verbose>0 then call pmprintf_sref(" POSTMAIL warning: EVENTS.TYPE."jj" not specified. ")
  172.         iterate
  173.     end
  174.     if symbol('EVENTS.VALUE.'||jj)<>'VAR' then do
  175.         if verbose>0 then call pmprintf_sref(" POSTMAIL warning: EVENTS.VALUE."jj" not specified. ")
  176.         iterate
  177.     end
  178.     ok=0
  179.     if events.TYPE.jj="CLIENT" then do 
  180.         ool=verify(events.value.jj,'1234567890*.')
  181.         if ool=0 then
  182.               ok=goodip(events.VALUE.jj,clientaddr)
  183.          else
  184.              ok=goodip(events.VALUE.jj,cname)
  185.    end
  186.    if events.type.jj='REQUEST' then do
  187.        if events.type.jj='REQUEST' then do
  188.           ok=goodsel(upper(events.value.jj),upper(sel))
  189.        end
  190.     end
  191.     if ok=0 then iterate
  192.  
  193.     if didit=0 & verbose>0 then  call pmprintf_sref(" Using gateway at " gateway)
  194.     didit=1
  195.  
  196.  
  197. /* if here, a match occurred */
  198.    address_list=events.recipients.jj
  199.  
  200.    if symbol('events.subject.jj')='VAR' then  
  201.           asubject='Subject: '||events.subject.jj
  202.    else
  203.           asubject='Subject: Notification of WEB transaction  '
  204.  
  205.    themessage="Date: " || adate || ' ' ||atime
  206.    if sender_name=' ' then
  207.       themessage=themessage||crlf||'From: WebServer@'||sname
  208.    else
  209.       themessage=themessage||crlf||'From: 'sender_name
  210.  
  211.    themessage=themessage||crlf||asubject
  212.    themessage=themessage||crlf||'To: '||address_list||crlf
  213.  
  214.    themessage=themessage||crlf||'An e-mail alert from the Web Server at '||sname
  215.    themessage=themessage||crlf||"    Date of occurrence: " || adate || ' ' ||atime
  216.    themessage=themessage||crlf||'     Request by client: '|| cname
  217.    themessage=themessage||crlf||'      Request selector: '|| sel
  218.    themessage=themessage||crlf||' Server status message: '|| amessage
  219.  
  220.    if symbol('events.message.jj')='VAR' then  /* check for a mess up */
  221.       themessage=themessage||crlf||"Notes:"||crlf||events.message.jj||crlf
  222.    else
  223.       themessage=themessage||crlf
  224.    foo=a_mailit(address_list,themessage, gateway,sender_name,verbose)
  225.    if verbose>0 then call pmprintf_sref(" Event " jj ", MAILIT status: "foo)
  226.  
  227. end                     /* try next event */
  228.  
  229. signal off error ; signal off syntax
  230. return ' '
  231.  
  232. /* -----------------------------------------------------------------------*/
  233. /* see if match (or abbreviation match) the sel                          */
  234. /* -----------------------------------------------------------------------*/
  235. goodsel: procedure
  236. parse  arg asel,thesel
  237. asel=translate(asel) ; thesel=translate(thesel)
  238. asel=translate(asel,'\','/') ; asel=strip(asel,,'\')
  239. thesel=translate(thesel,'\','/') ; thesel=strip(thesel,,'\')
  240.  
  241. if asel=thesel then return 1   /* exact match */
  242. return a_wildcard(thesel,asel)
  243.  
  244.  
  245.  
  246. /* -----------------------------------------------------------------------*/
  247. /* see if matches one of a set of good ips (1 if yes)*/
  248. /* -----------------------------------------------------------------------*/
  249. goodip: procedure 
  250.  
  251. parse upper arg anips,cip0
  252. parse var anips ip.1 '.' ip.2 '.' ip.3 '.' ip.4
  253. parse var cip0 cip.1 '.' cip.2 '.' cip.3 '.' cip.4
  254. match=1
  255. do mm2=1 to 4
  256.       if ip.mm2="*" then iterate
  257.       if ip.mm2=cip.mm2 then iterate
  258.       match=0       /*if here, not a match */
  259.       leave
  260. end
  261.  
  262. return match
  263.  
  264.  
  265. /* A simple transaction recorder (used if no SMTP_GATEWAY specified */
  266. say_stuff:
  267. call pmprintf_sref("  - - - - - ")
  268. call pmprintf_sref(time() ' ' date())
  269. call pmprintf_sref("  Message= "  amessage)
  270. call pmprintf_sref(" Source=  " source)
  271. call pmprintf_sref( " Request= "  request)
  272. call pmprintf_sref( " Sel = "  sel)
  273. return 
  274.  
  275.  
  276.  
  277. /********************************/
  278. /* see if needle matches haystack (* wildcards permitted) */
  279. a_wildcard:procedure  /* needle,haystack */
  280. parse arg tn ,tc 
  281. tn=strip(tn); tc=strip(tc)
  282. if tn=tc then   return 1              /* exact match */
  283. /* check for wildcard */
  284. astc=pos('*',tc)
  285. if astc=0 then  return 0          /* not a wildcard candidate */
  286.  
  287. if astc=1 then do
  288.    tc1=""
  289.    tn1=tc1
  290.    len1=0
  291. end
  292. else do
  293.    tc1=substr(tc,1,astc-1)
  294.    len1=length(tc1)
  295.    tn1=left(tn,len1)
  296. end
  297. if astc=length(tc) then do
  298.    tn2=""
  299.    tc2=""
  300.    len2=0
  301. end
  302. else do
  303.    tc2=substr(tc,astc+1)
  304.    len2=length(tc2)
  305.    tn2=right(tn,len2)
  306. end
  307. if tn1<>tc1 | tn2<>tc2 then     /* not a wildcard match */
  308.   return  0 
  309.  
  310. return 1                /* have a wildcard match */
  311.  
  312.  
  313. /******/
  314. /* here on error */
  315. error2:
  316. signal off syntax ; signal off error
  317. call pmprintf_sref(' Error in POSTMAIL at line ' sigl)
  318. return 0
  319.  
  320.  
  321. /*******************************************************************
  322.  *******************************************************************
  323.   *******************************************************************/
  324.  
  325. /*
  326.          ---------------- General notes  ------------------------
  327.  
  328. SRE-http  call this procedure when the POST_FILTER variable is set to YES.
  329.  
  330. 6 arguments are passed here:
  331.     amessage
  332.     source
  333.     request
  334.     sel0
  335.     tempfile
  336.     params
  337.  
  338. Amessage 
  339.     is generated by SRE-http, and indicates what SRE-http did with this request.
  340.  
  341. Source,request,and sel0 are generated by GoServe, and contain:
  342.  
  343.   Source 
  344.        serveraddr serverport transaction_number clientaddr clientport
  345.   Request
  346.     verb uri protocol 
  347.   Sel0
  348.     action '?' awords  (?awords may not be present
  349.  
  350. Tempfile is set in SRE-http
  351.   Tempfile
  352.     A temporary file name. It may have been used to construct the response, so you probably should
  353.     delete it first (use SYSFILEDELETE(TEMPFILE) ).
  354.  
  355. Params
  356.    Are optional parameters sent by SRE-http.  Currently, it contains the name of the
  357.    SMTP gateway (set in the SMTP_GATEWAY variable of SRE-http).
  358.  
  359. Example:
  360.      message               HTML File sent:/INDEX.HTM
  361.      Source                151.121.65.143 80 3 219.134.78.12 1026
  362.      request                GET /sampask2.htm HTTP/1.0
  363.      sel0                   sampask2.htm
  364.      tempfile               D:/GOHTTP/$10.80
  365.      params                mail.myprovider.net
  366.  
  367.  
  368. Note on Amessage:
  369.   The folllowing lists the "messages" that SRE-http may send.  Note that the ||varname
  370.   means the value of Varname is appended to the message.  Also note that when varname=SEL,
  371.   the SEL may be different then SEL0 (say, if a ~ replacement occurred).
  372.  
  373.     Pre-filter used
  374.     Cached file sent: ||sel0
  375.     Bad HTTP Protocol
  376.     Unauthorized access
  377.     No client name found, access denied
  378.     Logon denied to non-inhouse user
  379.     Pre-filter used
  380.     Alias invoked permanent redirect
  381.     Alias invoked temporary redirect
  382.     Transfered non-data directory file
  383.     Access to file denied:  ||sel
  384.     Ping request
  385.     CONTROL Statistics request
  386.     Host request
  387.     Control Moveaudit
  388.     Control Reset all
  389.     Variable display
  390.     !Special request denied: ||sel
  391.     Message box access
  392.     Message box access denied
  393.     Message box viewing
  394.     Special request processing unknown:||sel
  395.     HEAD request: Document not found:  ||sel0
  396.     Head request
  397.     Document not found
  398.     Server is busy
  399.     Non-HTML File sent:||file
  400.     HTML File sent:||file
  401.     HTML File sent (with ssi):||file
  402.     Mappable image request:'||foo
  403.     GET request:||action
  404.     Server busy
  405.     POST error: too much data
  406.     POST error: could not read data
  407.     POST request:||sel
  408.     POST problem:||sel
  409.     CGI-BIN access||sel
  410.  
  411. **************************************************************************/
  412.  
  413. /* This is MAILIT: an SRE-http procedure */
  414. /* ============================================================================ 
  415. MAILIT: A  REXX procedure to mail a note to several recipients.
  416. .
  417. .  Called as:  status=mailit(address_list,message_string,smtp_gateway,optional_sender_address)
  418. .
  419. . address_list: A space delimited list of addresses
  420. . message_string: A message string, that may contain CRLFs (and may be rather long)
  421. . smtp_gateway: The address of your SMTP server 
  422. . optional_senders_address: The sender's address (optional)
  423. .        If sender's address is not given, it will be generated using the servername() function.
  424. .
  425. . Example:
  426. . status=mailit("BOB@HIS.NET" , "This is my message ", "MAIL.MY.ORG" )
  427. .    or
  428. . status= mailit("BOB@HIS.NET JILL@HER.COM " , "This is my message ", ,
  429. .             "MAIL.MY.ORG", "HARRY@MY.ORG")
  430. .
  431. .NOTES:
  432. . SMTP gateway addresses.
  433. .   If you are using an INTERNET provider, use the POP or SMTP gateway address.
  434. .
  435. .   If no such address is available, you can try running the OS/2 SENDMAIL program, and
  436. .   use your hostname as the SMTP gateway address.
  437. .   For example, assuming that SENDMAIL.UML is in c:\mptn\etc,
  438. .   before starting GoServe you should   start sendmail with:
  439. .       [C:]START SENDMAIL -bd -q30m -Cc:\mptn\etc\sendmail.uml
  440. .   Alternatively, you can use AUTOSTART sendmail using the TCPCFG program.
  441. .
  442. . Note on recipient addresses:
  443. .    The message will be sent to each address.  Since the addresses are
  444. .    sent and then the message, this allows for fairly rapid mailing to multiple
  445. .    individuals.
  446. .
  447. . Acknowledgment:
  448. .     This is a modification of a routine written by Dave Briccetti (see acknowledgment at
  449. .     bottom of file)
  450. .     It was modified by Daniel Hellerstein for use in SRE-http. 4/96
  451. .
  452. .
  453. ============================================================================ */
  454.  
  455. a_mailit:
  456. parse arg whotos , themessage  , smtpaddress , sender_address,verbose
  457.  
  458. smtpaddress=strip(smtpaddress)
  459. sender_address=strip(sender_address)
  460.  
  461. /* set some constants */
  462. CRLF                    = '0d0a'x
  463. TRUE                    = 1
  464. FALSE                   = 0
  465. REPLYTYPE_OK            = '2'   /* SMTP reply code first byte */
  466. REPLY_START_MAIL_INPUT  = '354' /* SMTP reply code */
  467.  
  468. if sender_address="" then do
  469.    sendinghost=servername()
  470.    sendinguser="WebServer"
  471.    sender_address=sendinguser||'@'||sendinghost
  472. end
  473.  
  474. MailServer  = smtpaddress  /* Mail server, leave blank if you are connected through a LAN */
  475.  
  476. if \RxFuncQuery("SockLoadFuncs") then nop
  477. else do
  478.        call RxFuncAdd "SockLoadFuncs","rxSock","SockLoadFuncs"
  479.        call SockLoadFuncs
  480. end
  481.  
  482.  
  483. if EstablishProtocol() = FALSE then
  484.     return 0
  485.  
  486. /* The protocol initiated, we'll now send the message to each
  487.    recipient */
  488.  
  489. call SendMsgToEachRecipient
  490.  
  491.  
  492. /* QUIT ends the protocol */
  493.     
  494. CmdReply = TransactSmtpCommand(socket, 'QUIT', 1)
  495.  
  496.  
  497. /* Close the socket */
  498.     
  499. call SockSoClose socket
  500.  
  501. return isgood
  502.  
  503.  
  504. /* ========================================================================= */
  505. SetConstants:
  506. /* ========================================================================= */
  507.  
  508. return
  509.  
  510.  
  511. /* ========================================================================= */
  512. EstablishProtocol:
  513. /* ========================================================================= */
  514.  
  515. socket = ConnectToMailServer(MailServer)    
  516. if socket <= 0 then 
  517. do
  518.     if verbose>0 then 
  519.           call pmprintf_sref( 'Could not connect to mail server')
  520.     return FALSE
  521. end
  522.  
  523. CmdReply = GetCmdReply(socket)
  524.  
  525. if left(CmdReply, 1) \= REPLYTYPE_OK then 
  526. do
  527.     if verbose>0 then 
  528.           call pmprintf_sref( 'Could not establish protocol')
  529.     return FALSE
  530. end
  531.  
  532. /* Send the extended hello, in case this SMTP server supports
  533.    SMTP extensions */
  534.         
  535. CmdReply = TransactSmtpCommand(socket, 'EHLO', 1)
  536. SizeExtensionSupported = 0
  537.         
  538. if left(CmdReply, 1) = REPLYTYPE_OK then do
  539.     /* That worked, so enable extended SMTP processing.  If
  540.        the response to the EHLO indicates support for SIZE,
  541.        enable our use of that feature */
  542.               
  543.     SmtpExtensionsSupported = TRUE
  544.     if pos('250 SIZE', CmdReply) > 0 | pos('250-SIZE', CmdReply) > 0 then
  545.         SizeExtensionSupported = 1
  546. end
  547. else do
  548.     /* The server didn't recognize the EHLO so we'll go with
  549.        the regular HELO */
  550.               
  551.     SmtpExtensionsSupported = FALSE
  552.     SizeExtensionSupported  = FALSE
  553.     CmdReply = TransactSmtpCommand(socket, 'HELO', 1)
  554. end
  555.  
  556. if left(CmdReply, 1) = REPLYTYPE_OK then 
  557.     return TRUE
  558. else
  559.     return FALSE
  560.  
  561.  
  562. /* ========================================================================= */
  563. SendMsgBody: 
  564. /* ========================================================================= */
  565.  
  566. /* DATA tells the server that the body of the message is coming.  It
  567.    should reply with a code meaning "go ahead." */
  568.  
  569. CmdReply = TransactSmtpCommand(socket, 'DATA', 1)
  570. if substr(CmdReply, 1, 3) = REPLY_START_MAIL_INPUT then 
  571. do
  572.     /* Send the data, followed by a '.' on a line by itself to 
  573.        indicate the end of the message */
  574.     CmdReply = TransactSmtpCommand(socket, MsgFileContents || CRLF || '.', 0)
  575. end
  576.  
  577. return
  578.  
  579.  
  580. /* ========================================================================= */
  581. SendMsgToEachRecipient:
  582. /* ========================================================================= */
  583.  
  584. /*
  585. MsgFileContents = charin(MessageFile, 1, chars(MessageFile))
  586. call stream MessageFile, 'c', 'close'
  587. */
  588.  
  589. msgfilecontents=themessage
  590. MsgFileContents = strip(MsgFileContents, 't', '1a'x) 
  591.   /* Strip EOF */
  592.  
  593.         
  594. /* MAIL FROM identifies the sender.  The SIZE= extension
  595.    provides the size of the message, to allow the 
  596.    server to quickly refuse messages bigger than it wants. */
  597.            
  598. MailFromCmd = 'MAIL FROM:' ||sender_address
  599. isgood=1
  600.  
  601. if SizeExtensionSupported then
  602.     MailFromCmd = MailFromCmd ' SIZE=' || length(MsgFileContents)
  603.     
  604. CmdReply = TransactSmtpCommand(socket, MailFromCmd, 1)
  605.  
  606. if left(CmdReply, 1) = REPLYTYPE_OK then do
  607.   whotos=translate(whotos,' ','000d0a1a09'x)
  608.   do while whotos<> ""
  609.      parse var whotos whoto whotos
  610.  
  611.      RecipientEmailAddress = strip(whoto)
  612.      if RecipientEmailAddress \= '' then    /* RCPT identifies the intended recipient of the message */
  613.          CmdReply = TransactSmtpCommand(socket,,
  614.                          "RCPT TO:" || RecipientEmailAddress, 1)
  615. /*say " cmdreply " cmdreply*/
  616.   end /* do */
  617.  
  618.   call SendMsgBody
  619. end
  620. else do
  621.   isgood=0
  622. end
  623. return
  624.  
  625.  
  626. /* ========================================================================= */
  627. ConnectToMailServer: procedure
  628. /* ========================================================================= */
  629.  
  630. parse arg MailServer
  631. socket = 0
  632.  
  633. /* Open a socket to the mail server.  (The Sock* functions are
  634.    documented in the REXX Socket book in the Information folder
  635.    in the OS/2 System folder */
  636.  
  637. call SockInit
  638. if SockGetHostByName(MailServer, 'host.!') = 0 then do
  639.     if verbose>0 then 
  640.          call pmprintf_sref( 'Could not get host by name' errno' ' h_errno)
  641. end
  642. else do
  643.     socket = SockSocket('AF_INET','SOCK_STREAM',0)
  644.     address.!family = 'AF_INET'
  645.     address.!port = 25          /* the standard SMTP port */
  646.     address.!addr = host.!addr
  647.     if SockConnect(socket, 'address.!') = -1 then  do
  648.       if verbose>0 then
  649.             call pmprintf_sref( 'Could not connect socket' errno' ' h_errno)
  650.     end
  651. end
  652. return socket
  653.  
  654.  
  655. /* ========================================================================= */
  656. GetCmdReply: procedure
  657. /* ========================================================================= */
  658.  
  659. parse arg socket
  660.  
  661. CRLF = '0d0a'x
  662.  
  663. /* Receive the response to the SMTP command into a variable.  Use
  664.    more than one socket read if necessary to collect the whole 
  665.    response. */
  666.    
  667. if SockRecv(socket, 'CmdReply', 200) < 0 then do
  668.     if verbose>0 then 
  669.           call pmprintf_sref('Error reading from socket' errno' ' h_errno)
  670.     exit 0
  671. end
  672.  
  673. ReadCount = 1
  674. MaxParts = 10
  675.  
  676. do while ReadCount < MaxParts & right(CmdReply, 2) \= CRLF  
  677.     if SockRecv(socket, 'CmdReplyExtra', 200) < 0 then do
  678.         if verbose>0 then 
  679.            call pmprintf_sref('Error reading from socket')
  680.         exit 0
  681.     end
  682.     CmdReply = CmdReply || CmdReplyExtra
  683.     ReadCount = ReadCount + 1
  684. end
  685.  
  686. return CmdReply
  687.  
  688.  
  689. /* ========================================================================= */
  690. TransactSmtpCommand: 
  691. /* ========================================================================= */
  692.  
  693. parse arg socket, Cmd, SayCmd
  694.  
  695. /* Send a command to the SMTP server, echoing it to the display
  696.    if requested */
  697.  
  698. if SayCmd then 
  699.     if verbose>0 then 
  700.            call pmprintf_sref(" Command is "  Cmd)
  701. rc = SockSend(socket, Cmd || CRLF)
  702. op=GetCmdReply(socket)
  703. return op
  704.  
  705.  
  706. /* ------------- Acknowledgement  ------------------------------
  707. Most of this e-mail routine was obtained from:
  708.  
  709. Send Email Message to a Mailing List Via SMTP, Using the REXX Socket Interface
  710. Written by a novice REXX programmer
  711.      Dave Briccetti, November 1995
  712.      daveb@davebsoft.com, http://www.davebsoft.com
  713.  
  714.   May be used for any purpose
  715.   Thanks to REXX expert <a href=http://www.quercus-sys.com>Charles Daney</a>
  716.   and internet expert David Singer for looking over the code
  717. ----------------------------------------------------------    */
  718.  
  719.  
  720.  
  721. /***************************************  
  722. Problems with using IBM SENDMAIL for OS/2 version 2.02/2.0
  723. ----------------------------------------------------------
  724.  
  725. OS/2's SENDMAIL facility, although a bit outdated, is still a powerful
  726. SMTP server for OS/2; it can also be used as an ESMTP (Enhanced SMTP) server.
  727.  
  728. However, there are several problems one may encounter when using SENDMAIL as a 
  729. server. In particular:
  730.  
  731.   1) Delay when answering to a EHLO command from client.
  732.   2) Cannot act as a true relay server.
  733.  
  734. Let's examine these problems in greater detail.
  735.  
  736. Delay when answering to a EHLO command from client.
  737. --------------------------------------------------
  738.  
  739. When client (for example sref_mailit function from SRE-http) wants to
  740. send a message the first thing (after the connection is established) it
  741. must do is to send an HELO command, or an EHLO command, to the server.
  742. The HELO command is used to talk with usual SMTP servers, while the EHLO command
  743. is used with ESMTP servers. 
  744.  
  745. When an HELO command is send, the server responds with a one line string.
  746. An EHLO command (to an ESMTP server) yields a three (or more) line response.
  747. This multiple line response is usually not a problem, but when client sends EHLO to
  748. OS/2 SENDMAIL, only the first string is returned immediately. The remaining
  749. strings  are returned after some delay.  This delay can "confuse" the 
  750. client.
  751.  
  752. There are two workarounds for this problem:
  753.  
  754.   1) Do not use EHLO command with SENDMAIL at all and use only HELO command
  755.   2) Add a short delay, after sending EHLO command, before reading the response
  756.      from the server
  757.  
  758. The first workaround is not an elegant thing - you'll lost a lot of ESMTP
  759. extensions (of course, if you don't need those extensions if you use only
  760. standard SMTP commands).
  761.  
  762. Cannot act as a true relay server.
  763. ----------------------------------
  764.  
  765. When client sends the "." (the "." means "end of message") after a message body
  766. to the server, the server put the accepted message into the mail queue and sends
  767. "Message accepted to delivery" string to client. After receiving this message
  768. the client can send the QUIT command and end the session.
  769.  
  770. SENDMAIL has an interpretation of this syntax that can cause a problem.
  771. After receiving "." SENDMAIL tries to resolve the host address of the message
  772. recipient. For example, if we sends message to some@mailhub.com, SENDMAIL
  773. will try to resolve the mailhub.com into standard IP-address before placing the
  774. message into mail queue. In contrast, other SMTP servers always sends 
  775. "Message accepted..." before putting message into queue -- this frees the client 
  776. to disconnect. Since SENDMAIL doesn't do this (it waits until AFTER address
  777. resolution), problems can arise.  For example, if there is no DNS record for the
  778. recipient's address (for example, if mailhub.com doesn't exist), the client will
  779. never be "allowed" to disconnect.
  780.  
  781. Is there a workaround of this problem? Yes! Use two SENDMAIL's program. One
  782. SENDMAIL acting as server will only collect messages from clients and put them
  783. into mail queue but, won't try to send messages. The second SENDMAIL won't
  784. collect messages from clients but periodically starts to scan mail queue and
  785. send messages to recipients. 
  786.  
  787. How can you organize this? 
  788.  
  789. Usually, the SENDMAIL working as a full SMTP server starts from TCPSTART.CMD
  790. (\tcpip\bin directory) via command (for example):
  791.  
  792. DETACH sendmail -bd -q30s -CC:\MPTN\ETC\sendmail.cf
  793.  
  794. in this case SENDMAIL will collect messages from clients (-bd keys), and every
  795. 30 seconds scans mail queue to send messages using configuration from file
  796. C:\MPTN\ETC\sendmail.cf
  797.  
  798. What we will need to do? Just delete the "-q30s" parameter! Now SENDMAIL will
  799. only collect messages from clients without resolving hosts of message's
  800. recipients.
  801.  
  802. Now we need to start SENDMAIL every one minute for scan queue and send queued
  803. messages... It can be done via any shedulers like AT or CRON. You will simple
  804. invoke command "sendmail -q -CC:\MPTN\ETC\SENDMAIL.CF" every one minute. For
  805. example (using AT command from EWS AIXLIKE utilities set):
  806.  
  807. echo sendmail -q -CC:\MPTN\ETC\SENDMAIL.CF | at now + 1 minute
  808.  
  809. Of course, you can use any other sheduler - there are a lot of them.
  810.  
  811. Written on 18 Feb 1999 by Timur Kazimirov (timur@r1.sax.inkom.ru), with some
  812. editing by Daniel Hellerstein.
  813.  
  814. */
  815.