NB. Simple MAPI Interface for Windows.
NB.
NB. Does not request dialog boxes.  Does not support non-IPMs.
NB.   Does not support credentialed messaging systems.
NB.
NB. You log on to establish a session, do mail transactions, and log off.
NB. Sample sequence to process messages with qualifying subject lines might be:
NB.
NB. sess =. logonmail ''  NB. Establish session.  On some systems the argument (a profile name) is required
NB. subjects =. sess collectmail 192  NB. Get subjects only, don't mark as read
NB. desiredmsgs =. 0 {"1 (#~ qualifying_verb) subjects  NB. Get IDs of messages to read
NB. texts =. sess readmail desiredmsgs ,"0 _ <2048  NB. Get full text, no attachments
NB. sess deletemail desiredmsgs  NB. Delete messages after processing
NB. logoffmail sess  NB. end session
NB.
NB. sendmail is used to send outbound mail, with To, Cc, and Bcc recipients optional.
NB.  Attachments are optional.
NB. A session is required.
NB. An example, with only a To recipient:
NB. sess sendmail (1 ; < ,: 'Henry Rich';'SMTP:glasss@mindspring.com') ; 'wow' ; 'Great Work!'
NB.
NB. Henry H. Rich (glasss@mindspring.com), March 1999
NB. Alex Kornilovski <kornal@idirect.com>, March 1999
NB.
NB. Changes: July 2001 (sendmail) add support for original filename in attachments

require 'dll'
coclass 'mapi'

NB. Utility verbs
NB. Extract the return code from a DLL: if DLL error, use it, else the return is the first element
dllretcode =: >@{.
NB. y. is character string, result is memory address of a copy of the string, null-terminated.
allostring =: ( (] [ [ memw (, 0&,@>:@#)~)    mema@>:@# )
NB. But if the string is null, use 0 instead of making an allocation
allononnullstring =: 0: ` allostring @. (*@#)
NB. y. is result from allononnullstring; it is freed (if nonzero)
deallostring =: (''"_)`((''"_)@memf) @. (0&~:) "0

NB.*logonmail v-- Establish mail session
NB. Log on a mail session.  Use shared session if there is one.  y. is name of profile to use
NB.  (default '', which means use default profile).  In Windows 95, the profile is set by
NB.   clicking on Control Panel|Mail.
NB. Result is session handle, 0 if no session
logonmail =: 3 : 0
NB. MAPILogon alters the current directory!  So save it.
initdir =. {.&>/ 0 2 { 'kernel32 GetCurrentDirectoryA i i *c' cd 1024;1024#' '
logonrc =. 'Mapi32 MAPILogon i i i i i i *i' cd 0;(s =. allononnullstring y.);0;0;0;(,_1)
NB. Restore Current Directory, provided we saved one
'kernel32 SetCurrentDirectoryA i *c'&cd@<^:(*@#) initdir
deallostring s
if. 0 = dllretcode logonrc do.
  {. 6 {:: logonrc  NB. Convert response to scalar for use as memory address
else.
  0  NB. If error, return the error code
end.
)

NB.*logoffmail v-- Terminate mail session
NB. Log off a mail session.  y. is the session id.  Return the DLL retcode (0 if success).
logoffmail =: 3 : 0 "0
dllretcode 'Mapi32 MAPILogoff i i i i i' cd y.;0;0;0
)

NB.*sendmail v-- Send email
NB. x. is session id returned from logonmail
NB. y. is recipient_list ; subject_text (string) ; message_text (string) ; (optional) attachments
NB.  recipient_list is list of recipient_type , < list of name (string) ; address (string)
NB.  where recipient_type is 0 (originator), 1 (to), 2 (cc) , or 3 (bcc)
NB.  attachments is (possibly a list of) boxed lists representing attachment files
NB.    each list is filename;original filename (original filename may be omitted)
NB. You may use your address book to translate the name, and leave the address empty.
NB. You may NOT leave the name empty, even though the spec says you may - pick a harmless
NB. nonnull.  If you use an Internet address, be sure to prefix it with 'SMTP:'
NB. Example: sess sendmail (1 ; < ,: 'name';'SMTP:addr') ; 'subject' ; 'text' ;< (1 1 $<'c:att1.txt'),(1 1 $<'c:att2.txt')
sendmail =: 4 : 0 "0 1
NB. y. is (possibly list of) dwords, result is byte string for them
longwords =. 2&(3!:4)

NB. Allocate the recipients
nrecip =. _2 { 1 , $ recipsallolist =. ; recipsallo =. allononnullstring@> &.> (1) {"1 reciplist =. 0 {:: y.
recipallo =. allononnullstring longwords , ; (0 {"1 reciplist) (0: , [ , ] , 0 0"_)"_ 1 &.> recipsallo

NB. Allocate the attachments
if. natt =. _2 { 0 1 , $ att=. ,@<^:(2:=(3!:0)) 3 {:: y. , (<a:)  do.  NB. get attachment list (default null)
     NB. the ,@<^:(2:=(3!:0)) is to support single character strings, now deprecated
  attsallo =. allononnullstring@> 2 {.!.(<'')"1 att  NB. allocate attachment strings
  attallo =. allononnullstring longwords , (0 0 _1"_ , ] , 0:)"1 attsallo  NB. allocate file structures
else.
  attsallo =. attallo =. 0
end.

NB. Allocate the message text, and a structure for the whole message
msgallo =. allononnullstring longwords 0,(textallo =. allononnullstring@> 1 2 { y.),0,0,0,0,0,nrecip,recipallo,natt,attallo

mailrc =. dllretcode 'Mapi32 MAPISendMail i i i i i i' cd x.;0;msgallo;1;0
deallostring msgallo,recipallo,textallo,attallo,(,attsallo), ,recipsallolist  NB. Release storage for nonnull pointers
mailrc  NB. Return DLL errcode for error calling DLL, otherwise the DLL retcode
)

NB. Get next message id.  y. is list of messages read so far (boxed), or null to start with first message.
NB. x. is session (the return from logonmail)
NB. result is list of boxed strings: new list of messages read
findnextmail =: 4 : 0 "0 1
retarea =. mema 512
if. #y. do.
  mailrc =. 'Mapi32 MAPIFindNext i i i i *c i i i' cd x.;0;0;({:y.),16384;0;retarea
else.
  mailrc =. 'Mapi32 MAPIFindNext i i i i i i i i' cd x.;0;0;0;16384;0;retarea
end.
if. 0 = dllretcode mailrc do.
  newresult =. <memr retarea,0,_1
else.
  newresult =. 0 $ <''
end.
memf retarea
y.,newresult
)

NB.*readmail v-- Read an email message
NB. y. is the message_id;flags.  Flags defaults to 0.
NB.     (2048=no attachments, 512=make text an attachment, 128=don't mark
NB.     the messages as read, 64=read headers only, no text, 32=unread only)
NB. x. is the session id returned from logonmail
NB. result is originator_name;originator_addr;subject;text;date;attchments for the message
NB.  attachments are a list of character_position;filename;original_filename
NB.    position=_1 means end-of-file
NB. NOTE: future releases may add items to the returned value
readmail =: 4 : 0 "0 1
NB. y. is addr,offset,len;  result is pointer value
loadint =. 13 : '_2 (3!:4) memr y.'
NB. y. is structure_address,offset
NB. Result is the string pointed to by the pointer at that offset, or '' if pointer is null
loadstring =. ( (''"_) ` (memr@(,&0 _1)) @. ({.@(0&~:)) ) @ loadint @ (,&4) "1

'mid flgs' =. 2 {. y. , <0
if. mid -: '' do. '';'';'';'';'' return. end.
if. 0 = dllretcode mailrc =. 'Mapi32 MAPIReadMail i i i *c i i *i' cd x.;0;mid;flgs;0;(,_1) do.
  pmsgstr =. {. 6 {:: mailrc
  if. 0 ~: precipstr =. {. loadint pmsgstr,28,4 do.
    onmaddr =. <@loadstring precipstr ,"_ 0 (8 12)
  else.
    onmaddr =. '';''
  end.

  if. 0 ~: *./ 'natt aatt' =. loadint pmsgstr,40,8 do.
    cpos =. <@{.@loadint"1 aatt ,"_ 1 (8 + 24 * i. natt) ,"0 (4)  NB. character position
    cfn =. <@loadstring aatt ,"_ 0 (12 16 +/~ 24 * i. natt)  NB. full filename, original filename
    onatt =. cpos ,. cfn
  else.
    onatt =. 0 3 $ a:
  end.

  osubtxdt =. <@loadstring pmsgstr ,"_ 0 (4 8 16)

  'Mapi32 MAPIFreeBuffer i i' cd pmsgstr  NB. Free the message and all its strings
  onmaddr , osubtxdt , <onatt
else.
  '';'';'';'';''
end.
)

NB.*deletemail v-- Delete a mail message.
NB. y. is message id (boxed).  x. is session returned from logonmail.
NB. Result is return code from delete
deletemail =: 4 : 0 "0
dllretcode 'Mapi32 MAPIDeleteMail i i i *c i i ' cd x.;0;y.,0;0
)

NB.*collectmail v-- Retrieve all mail, or just the headers
NB. x. is session id, y. is flags (2048=no attachments, 512=make text an attachment, 128=don't mark
NB.   the messages as read, 64=read headers only, no text, 32=unread only)
NB. Result is message_id;origin_name;origin_addr;subject;text;rcvdate;attachments for all mail messages
NB.  attachments are a list of character_position;filename;original_filename
NB.    position=_1 means end-of-file
NB. NOTE: future releases may add items to the returned value
collectmail =: 4 : '(,. x.&readmail@(,&(<y.))"0) x.&findnextmail^:_ (0$a:)' "0 0

publishentrypoints 'logonmail logoffmail sendmail findnextmail readmail deletemail collectmail'
