home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
clipper
/
nettos11.zip
/
MHS
/
MHS.PRG
Wrap
Text File
|
1993-04-17
|
19KB
|
573 lines
/*
* File......: MHS.PRG
* Author....: Norbert Sommer
* CIS ID....: 100016,1241
* Date......: $Date$
* Revision..: $Revision$
* Log file..: $Logfile$
*
* This is an original program by Norbert Sommer
* and is hereby placed in the public domain.
*
* Modification history:
* ---------------------
*
* $Log$
*
*/
#include "fileio.ch"
#include "ftint86.ch"
#include "netto.ch" // with MHS extensions
#define MHS_HOST 0 // Record types in netdir.tab
#define MHS_USERS 2
#define MHS_HOSTS_WGROUPS_GWAYS 4
#define MHS_AFF_WGROUPS 7
#define MHS_APPS 9
#define CRLF chr(13)+chr(10)
STATIC cMhsPath := "" // storing MHS path in variable
// has to end with \
STATIC aMonthAm := {"Jan", "Feb", "Mar", "Apr",; // has to be american
"May", "Jun", "Jul", "Aug",;
"Sep", "Oct", "Nov", "Dec" }
#ifdef FT_TEST
// ----------------------------------
FUNCTION mhs ( cTo, cFrom, cSubject, cMessage, cFile )
// ----------------------------------
LOCAL nErrorCode, cHost, aUser, aWGroups, aAffWGr, aApps
DEFAULT cMessage TO "Testmessage fn_MhsSndM()" + CRLF + ;
"send " + dtoc(date()) , ;
cSubject TO "Test fn_mhs "+time()
CLS
IF pcount() < 2
? "Minimum usage: MHS ToUser@Host1 Me@Host2"
ELSE
nErrorCode := FN_MHSSndM ( {cTo}, cFrom, cSubject, cMessage, {cFile} )
? "Mail Return Code:" + str(nErrorCode,3)
inkey(0.5)
IF nErrorcode == ESUCCESS
cHost :=fn_MhsHost() ; qout("Host: " + cHost)
aUser :=fn_MhsUser() ; qout("User: ")
aeval(aUser ,{|e|qout(e)})
aWGroups:=fn_MhsHWG() ; qout("Hosts, Workgroups and Gateways:")
aeval(aWGroups,{|e|qout(e)})
aAffWGr :=fn_MhsAfWG() ; qout("Affiliated Workgroups:")
aeval(aAffWgr ,{|e|qout(e)})
aApps :=fn_MhsApps() ; qout("Registered applications:")
aeval(aApps ,{|e|qout(e)})
ENDIF
ENDIF
?
RETURN ( nil )
#endif
/* $DOC$
* $FUNCNAME$
* Overview
* $CATEGORY$
* MHS
* $ONELINER$
* MHS Send Mail Services
* $DESCRIPTION$
*
* These MHS Services provide functions for _sending_ email
* messages with attached files from within your Clipper
* application. For example, mails can be maintenance infos or automatic
* report files.
* Mails can be sent to multiple recipients and with multiple
* attached files with one function call.
* MHS tables can be read to find known users and hosts.
*
* To use these functions "NetWare MHS" version 1.5 or higher or
* "NetWare Global Messaging" (NGM) must be installed in your network
* environment.
* The reciever may use every version of MHS or NGM and needs an
* email application such as daVinci EMail, daVinci Coordinator or
* Pegasus Mail.
*
* The DOS variable MV points to the MHS directory structure and has
* been set properly if one of the above products is installed.
* Personal or network versions of NetWare MHS are detected.
*
* All the modem and routing stuff will be done by MHS! The only
* thing we are really doing is writing our files with the right
* structure into the MHS directories under %MV%\MHS.
*
* Please inform your email administator that you are testing because
* he will receive all undelivarable mail and error messages.
*
* Receiving MHS mail in an application is a much more complicated
* problem because the application
* needs!!! tto be registration with MHS and a lot
* of error checking is necessary.
* Program to program communcation can be done with semaphores,
* IPX/SPX sockets or broadcasting.
*
* $END$
*/
/* $DOC$
* $FUNCNAME$
* FN_MhsSndM()
* $CATEGORY$
* MHS
* $ONELINER$
* Send MHS Message to multiple recipients with attachments
* $SYNTAX$
* FN_MhsSndM( <aTo>, <cFrom>, <cSubject>, <cMessage> ;
* [,<aFiles>] [,<aCC>] [,<nSMFVer>] ) ;
* => nErrorCode
* $ARGUMENTS$
* <aTo> is the list of addressees containing complete
* addresses User[.App] @ Host|Workgroup|Gateway .
* Max Length = 64 elements
*
* <cFrom> Sender of the message. Complete address necessary.
*
* <cSubject> Short subject of the message.
* Maximum Length 64 Bytes.
*
* <cMessage> Long message to be sent. Max Length = 64 KB
*
* <aFiles> List of files to be sent as attachments to the
* message. Give complete path. Max Length 64 ele-
* ments. If nSMFVer is set to 64, only one attach-
* ment is possible.
*
* <aCC> List of addressees to get a copy of the message.
* Complete address necessary. Max Length = 63 ele-
* ments. The sum of elements of aTo and aCC may
* not exceed 64.
*
* <nSMFVer> is the SMF-Version of the message format.
* Allowed are 64 (MHS 1.1), 70 (MHS 1.5) and
* 71 (MHS 2.0, NGM).
* Default is 70, normally there is no need to change this.
* $RETURNS$
* <nErrorCode>
* ESUCCESS 0 ok
* EMHS_PARAM -1 parameter error
* EMHS_MV -2 MV variable not found
* EMHS_MAILSND -3 directory mhs\mail\snd not found
* EMHS_CREATE -4 file creating error
* EMHS_SEND -5 error sending message
* EMHS_LIST -6 list too long
*
* $DESCRIPTION$
* Sends a message to multiple recipients using Novell MHS,
* which must be installed. Files can be attached.
*
* $EXAMPLES$
* // This will send a message from user NSommer to
* UZyka in the Hannover office, 2 files are attached:
*
* nErrorCode:= FN_MHSSndM({"UZyka@dcs-ha"}, "NSommer@dcs-sg", ;
* "Reports Oct and Nov", "MessageBody", ;
* {"c:\rep\oct92.dbf", "c:\pict\nov92.pcx"} )
*
* // if a mhs-fax gateway is installed with extended addressing:
*
* nErrorcode:= FN_MHSSndM({"fax@fax {fax:299-399-499}"}, ;
* "NSommer@dcs-sg", "TestFax", cLongMessage )
*
* $INCLUDE$
* netto.CH
* $SEEALSO$
* fn_MhsHost() fn_MhsUser()
* $END$
*/
FUNCTION fn_MhsSndM(aTo, cFrom, cSubject, cMessage, aFiles, aCC, nSMFVer)
LOCAL nErrorCode:=0, cMV:="", hMessFile, cHeader:="", ;
aSmfOk:={64,70,71}, aTmpFiles:={}
DEFAULT nSMFVer TO 70, cSubject TO "", cMessage TO ""
DO CASE
CASE empty(aTo) .or. ;
valtype(aTo) # "A" .or. ;
len(aTo) > 64 .or. ;
empty(cFrom) .or. ;
valtype(cFrom) # "C" .or. ;
valtype(cSubject) # "C" .or. ;
valtype(cMessage) # "C" .or. ;
len(cMessage) > 65500 .or. ;
ascan(aSmfOk,nSMFVer) == 0
nErrorCode:=EMHS_PARAM // Parameter ok ?
CASE empty(cMV:=gete("MV")) // MV found ?
nErrorCode:=EMHS_MV
CASE empty(cMhsPath:=_fnMhsPath(cMV)) // Mail path found ?
nErrorCode:=EMHS_MAILSND
CASE (hMessFile:=fopen(ft_TempFil(cMhsPath+"MHS\MAIL\SND"),2)) < 0
nErrorCode:=EMHS_CREATE // Unique File R/W
ENDCASE
IF nErrorCode == 0 // Building message
cHeader := "SMF-" + str(nSMFVer,2) + CRLF + ; // SMF Version
"To: " + aTo[1]
aeval(aTo, {|to| cHeader+=", "+to} , 2, 64) // To
cHeader += CRLF + ;
"From: " + cFrom + CRLF // From
IF ! empty(aCC)
cHeader += "Copies-to: " + aCC[1] // CC
aeval(aCC, {|cc| cHeader+=","+cc} , 2, 64)
cHeader+= CRLF
ENDIF
cHeader += "Date: " + str(day(date()),2) + "-" + ; // Date
aMonthAm[month(date())] + "-" + ;
right(str(year(date())),2) + " " + ;
time() + CRLF
IF !empty(cSubject)
cHeader += "Subject: " + cSubject + CRLF // Subject
ENDIF
// Files attached
IF ! empty( aFiles ) .and. ;
! empty( aTmpFiles := _fnMHSTmAt(@aFiles) )
IF nSMFVer < 70 .and. len(aFiles) > 1 // SMF-64 only one
asize(aFiles,1) ; asize (aTmpFiles,1) // attachment
nErrorCode:=EMHS_LIST
ENDIF
cHeader += "Attachment: " + aTmpFiles[1]
aeval(aTmpFiles, { |Tmpfile| cHeader += ", " + TmpFile }, 2, 64)
cHeader += CRLF+ "Attachment-name: " + aFiles[1]
aeval(aFiles, { |file| cHeader += ", "+ file }, 2, 64)
cHeader += CRLF
ENDIF
cHeader += CRLF // empty line required
IF fwrite(hMessFile, cHeader) < len(cHeader) .or. ; // Write header
fwrite(hMessFile, cMessage) < len(cMessage) // Write Message
nErrorCode:=EMHS_SEND
ENDIF
fwrite(hMessFile, CRLF)
fclose(hMessFile) // Closing file
ENDIF
RETURN (nErrorCode)
*--------------------------------------
STATIC FUNCTION _fnMHSTmAt(aFiles) // copies files using unique names
// into %mhs%\mail\parcel and
// returns an array of the copied files!!!
// filesnames
// => aTmpFiles
*--------------------------------------
LOCAL aTmpFiles:={}, i, tmpFile:="", nDel:=0, nPosBsp:=0, nPosDp:=0
asize(aTmpFiles,len(aFiles))
FOR i:=len(aFiles) TO 1 STEP -1
IF file ( aFiles[i] ) .and. ;
!empty ( tmpFile:=ft_TempFil(cMhsPath+"MHS\MAIL\PARCEL") )
COPY FILE ( aFiles[i] ) TO ( tmpFile )
aTmpFiles[i] := substr(tmpFile, RAT("\",TmpFile)+1)
IF ( nPosBsp := RAT("\",aFiles[i]) ) > 0 .or. ; // extract filename
( nPosDp := RAT(":",aFiles[i]) ) > 0
aFiles[i] := substr(aFiles[i],max(nPosBsp,nPosDp)+1)
ENDIF
ELSE
adel(aFiles,i); adel(aTmpFiles,i); nDel ++
ENDIF
NEXT i
asize(aFiles ,len(afiles)-nDel)
asize(aTmpFiles,len(aTmpFiles)-nDel)
RETURN (aTmpFiles)
/* $DOC$
* $FUNCNAME$
* FN_MHSUSER()
* $CATEGORY$
* MHS
* $ONELINER$
* Get MHS user list
* $SYNTAX$
* FN_MhsUser() => aUser
* $ARGUMENTS$
* None
* $RETURNS$
* <aUser> Array of known local users at your MHS location
* $DESCRIPTION$
* Reading the MHS table file gives information on known MHS users
* at your local MHS host.
*
* If the MHS DOS variable USR is found, the mail id of the
* currectly logged user can be read by gete("USR").
*
* !!!Can be used to check input before sending a message to a local user
* using fn_MhsSndM().
*
* $EXAMPLES$
* fnMhsUser() => {"GSCOTT","CYELLICK","ADMIN","CBROWN"}
*
* $INCLUDE$
*
* $SEEALSO$
* FN_MhsHost() FN_MhsHWG() FN_MhsAfWG() FN_MhsApps()
* $END$
*/
FUNCTION fn_MhsUser()
RETURN _fnMhsTab(MHS_USERS)
/* $DOC$
* $FUNCNAME$
* FN_MHSHWG()
* $CATEGORY$
* MHS
* $ONELINER$
* Get MHS table file of hosts, workgroups, and gateways
* $SYNTAX$
* FN_MhsHWG() => aHoWoGw
* $ARGUMENTS$
* None
* $RETURNS$
* <aHoWoGw> Array
* $DESCRIPTION$
* Reading the MHS table file gives information on known
* hosts, workgroups and gateways.
*
* They are used in the same way ( MHS knows what to do):
* user @ host, user @ workgroup, user @ gateway .
*
* Can be used to check input before sending a message to a local user
* using fn_MhsSndM().
*
* $EXAMPLES$
* cToHost := "CSERVE"
* if ascan( fn_MhsHWG(), cToHost ) > 0
* fn_MhsSndM({"BMargos@"+cToHost}, "NSommer@dcs-sg", cMessage)
* else
* ? "Host not found"
* endif
*
* $INCLUDE$
*
* $SEEALSO$
* FN_MhsHost() FN_MhsUser() FN_MhsAfWG() FN_MhsApps()
* $END$
*/
FUNCTION fn_MhsHWG()
RETURN ( _fnMhsTab(MHS_HOSTS_WGROUPS_GWAYS) )
/* $DOC$
* $FUNCNAME$
* FN_MHSAFWG()
* $CATEGORY$
* MHS
* $ONELINER$
* Get MHS list of affilitated workgroups
* $SYNTAX$
* FN_MhsAfWG() => aAffWGr
* $ARGUMENTS$
* None
* $RETURNS$
* <aUser> Array of affiliated workgroups at your MHS location
* $DESCRIPTION$
* Reading the MHS table file gives information on registered
* affiliated workgroups at your local MHS host.
*
* Only interesting for people who know about the workgroup
* concept in Novell's MHS.
*
* $EXAMPLES$
*
* $INCLUDE$
*
* $SEEALSO$
* FN_MhsHost() FN_MhsUser() FN_MhsHWG() FN_MhsApps()
* $END$
*/
FUNCTION fn_MhsAfWG()
RETURN ( _fnMhsTab(MHS_AFF_WGROUPS) )
/* $DOC$
* $FUNCNAME$
* FN_MHSAPPS()
* $CATEGORY$
* MHS
* $ONELINER$
* Get MHS list of registered applications
* $SYNTAX$
* FN_MhsApps() => aApps
* $ARGUMENTS$
* None
* $RETURNS$
* <aUser> Array of registered applications at your MHS location
* $DESCRIPTION$
* Generally one Email user can be reached in different mail
* applications. MHS knows the preferred application,
* but the receiving application can be predetermined.
*
* fn_MhsApps() gives an array on locally known mail
* applications at your MHS host.
*
* $EXAMPLES$
*
* cMyHost := "@" + fn_MhsHost()
* if ascan( fn_MhsApps(), cApp ) > 0
* fn_MhsSndM({"BMargos"+cMyHost,"CDragoi.ATC"+cMyHost},;
* "NSommer@dcs-sg", cMessage)
* else
* ? "App. not found"
* endif
*
* BMargos will receive the message at his preferred mail
* application, but CDragoi will receive it using Action
* Technologies Coordinator (ATC).
*
* Registering applications and managing MHS is not
* handled by this function and should be done by the
* network's MHS administrator.
*
* $INCLUDE$
*
* $SEEALSO$
* FN_MhsHost() FN_MhsUser() FN_MhsHWG() FN_MhsAfWG()
* $END$
*/
FUNCTION fn_MhsApps()
RETURN ( _fnMhsTab(MHS_APPS) )
/* $DOC$
* $FUNCNAME$
* FN_MhsHost()
* $CATEGORY$
* MHS
* $ONELINER$
* Get name of your MHS host
* $SYNTAX$
* FN_MhsHost() => cHost
* $ARGUMENTS$
* none
* $RETURNS$
* <cHost> Name of Host
* $DESCRIPTION$
* Reads the name of the MHS Host to which the MV variable
* is pointing.
*
* $EXAMPLES$
* FN_MhsHost() => "NHUB"
*
* Building the sender address:
* gete("USR") + "@" + fn_MhsHost() or
* fn_whoami() + "@" + fn_MhsHost()
*
* $SEEALSO$
* FN_MhsSndM() FN_MhsUser() FN_MhsApps() FN_MhsHWG()
* $END$
*/
FUNCTION fn_MhsHost()
LOCAL aHost:=_fnMhsTab(MHS_HOST), cHost:=""
IF !empty(aHost)
cHost :=substr(aHost[1],2,8)
ENDIF
RETURN(cHost)
*--------------------------------------
FUNCTION _fnMhsTab(nRecType)
*--------------------------------------
LOCAL hTabHndl, buffer:=space(128), aReturn:={}, nType
IF !empty(cMhsPath:=_fnMhsPath(gete("MV")) ) .AND. ;
(hTabHndl:=fopen(cMhsPath+"MHS\MAIL\PUBLIC\NETDIR.TAB",FO_READ) ) > 0
// File sorted by nType
DO WHILE fread(hTabHndl,@buffer,128) > 0 .and. ;
(nType:=asc(buffer)) <= nRecType
IF nType == nRecType
aadd(aReturn, upper(substr(buffer,2,9)) ) // last char may be chr(0)
ENDIF
ENDDO
fclose(hTabHndl)
ENDIF
RETURN(aReturn)
*--------------------------------------
STATIC FUNCTION _fnMhsPath(cMV) // find MHS directory structure
// and give drive
// personal MHS: MV=d:\
// network MHS: MV=[server/]vol:[dir]
// Directory \SND exists in MHS 1.5 and above
// Directory Handle will be cleared by
// implicit fn_eoj() at end of application
*--------------------------------------
LOCAL cDrive:=" ", cPath:="", hMhsSnd, cSndDir:="MHS\MAIL\SND", ;
nPosSlash, nPosDp, cServer, cVolumeDir, nTmpDrive
DEFAULT cMV TO ""
IF right(cMV:=upper(cMV),1)#"\"
cMV += "\"
ENDIF
DO CASE
CASE !empty(cMhsPath) // has been found before and stored in static
cPath := cMhsPath // nothing to do, give it back
CASE substr(cMV,2,2) == ":\" // MHS Personal d:\[dir]
IF file(cMV + cSndDir +"\NUL") // works on local directory
cPath := cMV
ENDIF
OTHERWISE // network
// find free temp drive
if (nTmpDrive:=ascan(fn_gDrvFT(),0,27)) > 0 // 27..32 are tmp drives
cDrive := chr(64+nTmpDrive)
else
cDrive := "]" // catch a used one
endif // later: give error
nPosSlash := ft_at2(iif("/"$cMV,"/","\"), cMV, 1)
nPosDp := ft_at2(":", cMV, 1)
IF nPosSlash < nPosDp // server/vol:[dir]
cServer := left (cMV, nPosSlash-1)
cVolumeDir := substr(cMV, nPosSlash+1)
fn_sPfCID ( ASCAN( fn_FSName(), cServer ) ) // set pref. server
ELSE // vol:[dir]
cVolumeDir := cMV
ENDIF
hMhsSnd := fn_AlTemDH(0, cDrive, cVolumeDir + cSndDir)
IF !empty(hMhsSnd) .and. !empty(hMhsSnd[1])
cPath := cDrive + substr(cMV, nPosDp)
ENDIF
ENDCASE
cMhsPath := cPath
RETURN (cPath)
*---- EOF MHS.PRG Nanforum Network Toolkit ----*