TMGPAT2 ;TMG/kst/Patching tools Suport;09/17/08 ;;1.0;TMG-LIB;**1**;09/17/08 ; ;"Kevin Toppenberg MD ;"GNU General Public License (GPL) applies ;"9/17/08 ;"======================================================================= ;" API -- Public Functions. ;"======================================================================= ;"MAKFRESH(PckInit,Msg,PckDirFName) --ensure that the Package list of files avilable on server is fresh ;"RefreshPackge(PckInit,.Msg,NeedsRefresh,PckDirFName) -- query server for one package, and refresh info stored in TMG REMOTE PATCH SOURCE file ;"GetNextIENS(LastPatch,NextPatchName) -- return IENS in file TMG REMOTE PATCH SOURCE (22709) ;"GetIENS(PatchName) -- Given patch name, return IENS in file TMG REMOTE PATCH SOURCE (22709) ;"GetIENS2(PatchName) -- Given partial patch name, return IENS in file 22709.01 ;"FORCEPAT -- All user to enter a patch entry ;"IsInstalled(PatchName) -- return if a given patch has already been installed. ;"ParsePatchName(PatchName,PckInit,Ver,PatchNum,SeqNum) -- parse a patch name into it's composit parts. ;"EnsureLocal(IENS,Info,Msg,Option) -- Ensure files downloaded from server and stored locally ;"DownloadPatch(PatchName,protocol,Option,Msg,Info) -- Ensure that the Patch has been downloaded from server and stored locally ;"MakePatchEntry(PatchName,Msg) -- make pseudo-entries to show that something was processed. ;"AddMsg(s,IsError,Msg) -- add a message to Msg Array ;"ShowMsg(Msg) -- display the message array ;"======================================================================= ;"Private Functions ;"======================================================================= ;"EmptyPackage(IEN9d4,Msg) - delete info for Package in file TMG REMOTE PATCH SOURCE ;"LoadPackage(IEN9d4,Array,protocol,Msg,SomeAdded) -- load info for Package info file TMG REMOTE PATCH SOURCE ;"LoadOne(PckIEN,Ver,PatchNum,SeqNum,RemoteURL,Msg) -- file one entry info TMG REMOTE PATCH SOURCE ;"======================================================================= ;"======================================================================= MAKFRESH(PckInit,Msg,PckDirFName) ;"Purpose: to ensure that the Package list of files avilable on server is fresh ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;" PckDirFName -- Optional. PASS BY REFERNCE, an OUT PARAMETER. Filled with HFS filename of file ;"Results: none new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) if IEN9d4'>0 do goto ENSFDone . do AddMsg("Can't find PACKAGE named '"_PckInit_"'",1,.Msg) new PckIEN,lastFMDate set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) if PckIEN>0 set lastFMDate=$piece($get(^TMG(22709,PckIEN,2)),"^",1) else set lastFMDate="" new %,X,X1,X2,NeedsRefresh set NeedsRefresh=0 if lastFMDate'="" do . do NOW^%DTC ;"returns date in X . set X1=lastFMDate,X2=X . do ^%DTC . if X>7 set NeedsRefresh=1 ;"hard code in fresh if > 7 days since last scan. else set NeedsRefresh=1 if $$RefreshPackge(PckInit,.Msg,NeedsRefresh,.PckDirFName) ENSFDone quit RefreshPackge(PckInit,Msg,NeedsRefresh,PckDirFName,Option) ;"Purpose: To query server for one package, and refresh info stored in TMG REMOTE PATCH SOURCE file ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;" NeedsRefresh -- 0 if refreshing not needed (just return PckDirFName, but ensure file exists) ;" PckDirFName -- Optional. PASS BY REFERANCE, an OUT PARAMETER. Filled with HFS filename of file ;" Option -- Optional. PASS BY REFERANCE. ;" Option("VERBOSE")=1 puts out text to console. (1 is default value) ;"Result : 1=success, 0=failure new Array,result new verbose set verbose=+$get(Option("VERBOSE"),1) set NeedsRefresh=+$get(NeedsRefresh) if NeedsRefresh,verbose write "Fetching list of available "_PckInit_" patches from VA ftp server..." set result=$$GetPckList^TMGKERNL(PckInit,.Array,.NeedsRefresh,.PckDirFName) if NeedsRefresh,verbose write " Done.",! if $get(NeedsRefresh)'>0 goto RPDone if result=0 goto RPDone new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) if IEN9d4'>0 do goto RPDone . do AddMsg("Can't find PACKAGE named '"_PckInit_"'",1,.Msg) new SomeAdded set result=$$LoadPackage(IEN9d4,.Array,"ftp://",.Msg,.SomeAdded) RPDone quit result EmptyPackage(IEN9d4,Msg) ;"Purpose: to delete info for Package in file TMG REMOTE PATCH SOURCE ;"Input: IEN9d4 -- IEN in 9.4 to get patches for ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 new PckIEN set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) if PckIEN=0 goto EPDone new TMGFDA,TMGMSG set TMGFDA(22709,PckIEN_",",.01)="@" do FILE^DIE("EK","TMGFDA","TMGMSG") if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) EPDone quit LoadPackage(IEN9d4,Array,protocol,Msg,SomeAdded) ;"Purpose: to load info for Package info file TMG REMOTE PATCH SOURCE ;"Input: IEN9d4 -- IEN in 9.4 to get patches for ;" Array -- This is file with available filepaths, as returned from GetPckList ;" protocol -- OPTIONAL. Default is 'ftp://' ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;" SomeAdded -- PASS BY REFERENCE, an OUT PARAMETER ;" set to 1 if some added, otherwise 0 ;"Result : 2=patch added, 1=no problems, 0=failure or error occured new result set result=1 set SomeAdded=0 set protocol=$get(protocol,"ftp://") set IEN9d4=+$get(IEN9d4) if IEN9d4'>0 do goto LPDone . do AddMsg("Can't find record #"_IEN9d4_" in INSTALL file.",1,.Msg) new PckIEN set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) new TMGFDA,TMGMSG,TMGIEN,X,% do NOW^%DTC ;"output in % if PckIEN>0 do . set TMGFDA(22709,PckIEN_",",2)=% . do FILE^DIE("K","TMGFDA","TMGMSG") else do . set TMGFDA(22709,"+1,",.01)=IEN9d4 . set TMGFDA(22709,"+1,",2)=% ;"the time downloaded . do UPDATE^DIE("K","TMGFDA","TMGIEN","TMGMSG") . set PckIEN=$get(TMGIEN(1)) if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) if PckIEN'>0 goto LPDone new i set i=0 ;"skip first line, a header line for set i=$order(Array(i)) quit:(i="") do . new Name,Path,FullNamePath,Ver,PatchNum,SeqNum . set FullNamePath=$get(Array(i)) quit:FullNamePath="" . do SplitFNamePath^TMGIOUTL(FullNamePath,.Path,.Name,"/") . if (Path="")!(Name="") quit . new UName set UName=$$UP^XLFSTR(Name) . if UName?2.4A1"_"1.4N1"_"0.1"P"1.N1".KID" do ;"e.g. DG_53_P481.KID or EAS_1_47.KID . . set Ver=$piece($piece(Name,"_",2),"_",1) . . new verIEN set verIEN=+$order(^TMG(22709,PckIEN,1,"C",Ver,"")) . . if verIEN=0 set Ver="" quit . . set Ver=$piece($get(^TMG(22709,PckIEN,1,verIEN,0)),"^",1) . . if Ver="" quit . . set PatchNum=$piece($piece(Name,"_",3),".",1) . . if PatchNum?1A.N set PatchNum=$extract(PatchNum,2,99) . . set SeqNum="" ;"signal for no seq number provided . else do . . set Ver=$piece($piece(Name,"_",1),"-",2) quit:(Ver="") . . if Ver?.N1(1"p",1"P").N set Ver=$translate(Ver,"Pp","..") . . set SeqNum=$piece($piece(Name,"_",2),"-",2) quit:(SeqNum="") . . set PatchNum=$piece($piece(Name,"_",3),"-",2) quit:(PatchNum="") . . set PatchNum=$piece(PatchNum,".",1) quit:(PatchNum="") . if Ver="" do quit . . do AddMsg("Unable to process file name: "_Name_". Couldn't determine version number.",1,.Msg) . ;"if SeqNum="" do quit ;Removed because sometimes the sequence # comes from the TXT file, not the patch file. . ;". do AddMsg("Unable to process file name: "_Name_". Couldn't determine sequence number.",1,.Msg) . if PatchNum="" do quit . . do AddMsg("Unable to process file name: "_Name_". Couldn't determine patch number.",1,.Msg) . new tempResult . set tempResult=$$LoadOne(PckIEN,Ver,PatchNum,SeqNum,protocol_FullNamePath) . if tempResult=2 set SomeAdded=1 LPDone quit result LoadOne(PckIEN,Ver,PatchNum,SeqNum,RemoteURL,Msg) ;"Purpose: to file one entry info TMG REMOTE PATCH SOURCE ;" This doesn't actually get the file from the server, just store ;" the directory info, for later retrieval ;"Input: PckIEN -- the IEN in TMG REMOTE PATCH SOURCE for Package ;" Ver -- the version of the patch ;" PatchNum -- the patch number ;" SeqNum -- the patch sequence number (the release sequence number) (if provided) ;" RemoteURL -- The protocol_remoteURL of the patch on the server ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;"Result : 1=success, 0=failure new result set result=0 ;"default to failure set PckIEN=+$get(PckIEN) if PckIEN'>0 goto LODone set Ver=$get(Ver) if Ver="" goto LODone if Ver'["." set Ver=Ver_".0" set PatchNum=$get(PatchNum) if PatchNum="" goto LODone set SeqNum=$get(SeqNum) ;"OK if no sequence number new VerIEN set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",Ver,"")) if VerIEN'>0 do . new TMGFDA,TMGIEN,TMGMSG . set TMGFDA(22709.01,"+1,"_PckIEN_",",".01")=Ver . set TMGFDA(22709.01,"+1,"_PckIEN_",",".02")=$translate(Ver,".","") ;"synonym . do UPDATE^DIE("","TMGFDA","TMGIEN","TMGMSG") . if $data(TMGMSG("DIERR")) do . . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . set VerIEN=+$get(TMGIEN(1)) if VerIEN'>0 goto LODone new patchIEN set patchIEN=+$order(^TMG(22709,PckIEN,1,VerIEN,1,"B",PatchNum,"")) if patchIEN'>0 do . new TMGFDA,TMGIEN,TMGMSG . set TMGFDA(22709.11,"+1,"_VerIEN_","_PckIEN_",",".01")=PatchNum . do UPDATE^DIE("","TMGFDA","TMGIEN","TMGMSG") . if $data(TMGMSG("DIERR")) do . . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . set patchIEN=+$get(TMGIEN(1)) . set result=2 ;"something added if patchIEN'>0 goto LODone new TMGFDA,TMGMSG new Ext set Ext=$piece(RemoteURL,".",$length(RemoteURL,".")) new spec set spec("'")="'\''",spec("*")="'\*'",spec("&")="'\&'",spec("?")="'\?'" set spec("\ ")=" " set RemoteURL=$$REPLACE^XLFSTR(RemoteURL,.spec) new field if $$UP^XLFSTR(Ext)="TXT" set field=1.5 else set field=1 set TMGFDA(22709.11,patchIEN_","_VerIEN_","_PckIEN_",",field)=RemoteURL if SeqNum'="" set TMGFDA(22709.11,patchIEN_","_VerIEN_","_PckIEN_",",".02")=SeqNum do FILE^DIE("K","TMGFDA","TMGMSG") if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) if $data(TMGMSG("DIERR"))=0 do . if result>0 quit . set result=1 ;"success LODone quit result GetNextIENS(LastPatch,NextPatchName) ;"Purpose: Given last patch name, return IENS in file TMG REMOTE PATCH SOURCE (22709) ;" that points to record with information about next appropriate patch. ;"Input: LastPatch -- expected Format: e.g. DI*22.0*100 SEQ #123 ;" NextPatchName -- PASS BY REFERENCE, an OUT PARAMETER ;" Will be filled with name of next patch. ;"Output: returns IENS to record in 22709.11, or "" if problem. new result set result="" set NextPatchName="" if $get(LastPatch)="" goto GNPDone new seqNum,PckInit,Ver,PatchNum,seqNum do ParsePatchName(LastPatch,.PckInit,.Ver,.PatchNum,.seqNum) if seqNum="" goto GNPDone new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) if IEN9d4'>0 goto GNPDone new PckIEN set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) if PckIEN'>0 goto GNPDone new VerIEN set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",Ver,"")) if VerIEN'>0 set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",$piece(Ver,".0",1),"")) if VerIEN'>0 goto GNPDone new patchIEN,nextSeq set nextSeq=+$order(^TMG(22709,PckIEN,VerIEN,"SEQ",seqNum)) if nextSeq'>0 goto GNPDone set patchIEN=+$order(^TMG(22709,PckIEN,VerIEN,"SEQ",nextSeq,"")) if patchIEN'>0 goto GNPDone set result=patchIEN_","_VerIEN_","_PckIEN_"," set NextPatchName=$piece(LastPatch," ",1) new node0 set node0=$get(^TMG(22709,PckIEN,1,VerIEN,1,patchIEN,0)) new nextPatchNum set nextPatchNum=$piece(node0,"^",1) set $piece(NextPatchName,"*",3)=nextPatchNum set NextPatchName=NextPatchName_" SEQ #"_nextSeq GNPDone quit result GetIENS(PatchName) ;"Purpose: Given patch name, return IENS in file TMG REMOTE PATCH SOURCE (22709) ;"Input: PatchName -- expected Format: e.g. DI*22.0*100 SEQ #123 ;"Output: returns IENS to record in 22709.11, or "" if problem. new result set result="" if $get(PatchName)="" goto GIDone new seqNum,PckInit,Ver,PatchNum,seqNum new IEN9d4,PckIEN,VerIEN,patchIEN do ParsePatchName(PatchName,.PckInit,.Ver,.PatchNum,.seqNum) goto:(seqNum="") GIDone set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) goto:(IEN9d4'>0) GIDone set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) goto:(PckIEN'>0) GIDone set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",Ver,"")) if VerIEN'>0 set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",$piece(Ver,".0",1),"")) if VerIEN'>0 goto GIDone set patchIEN=+$order(^TMG(22709,PckIEN,VerIEN,"SEQ",seqNum,"")) goto:(patchIEN'>0) GIDone set result=patchIEN_","_VerIEN_","_PckIEN_"," GIDone quit result GetIENS2(PatchName) ;"Purpose: Given partial patch name, return IENS in file 22709.01 ;" (i.e. just patch*ver) ;"Input: PatchName -- expected Format: e.g. DI*22.0*.... or DI*22.0 ;"Output: returns IENS to record in 22709.01, or "" if problem. new result set result="" if $get(PatchName)="" goto GI2Done new seqNum,PckInit,Ver,PatchNum,seqNum new IEN9d4,PckIEN,VerIEN,patchIEN do ParsePatchName(PatchName,.PckInit,.Ver,.PatchNum,.seqNum) if (PckInit="")!(Ver="") goto GI2Done set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) goto:(IEN9d4'>0) GI2Done set PckIEN=+$order(^TMG(22709,"B",IEN9d4,"")) goto:(PckIEN'>0) GI2Done set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",Ver,"")) if VerIEN'>0 set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",$piece(Ver,".0",1),"")) if VerIEN'>0 goto GI2Done set result=VerIEN_","_PckIEN_"," GI2Done quit result EnsureLocal(IENS,Info,Msg,Option) ;"Purpose: Ensure that the files have been downloaded from server and stored locally ;"Input: IENS -- IENS in 22709.11 ;" Info -- PASS BY REFERENCE, an OUT PARAMETER. ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;" Option -- optional. Pass by reference. ;" Option("VERBOSE")=1, means messaages also written directly to output ;"Output: Info will be filled as follows: ;" Info("PATH")=Path in HFS ;" Info("KID FILE")=HFS filename of .KID patch ;" Info("TEXT FILE")=HFS filename of .TXT accompanying patch ;" Info("TEXT ONLY")=1 if there is a text file, but no .KIDS file ;" Info("KID URL")=URL on server for KID file ;" Info("TEXT URL")=URL on server for TXT file ;"results: 1 if OK, 0 if problem. new TMGMSG,TMGDATA,TMGFDA new verbose set verbose=$get(Option("VERBOSE")) new result set result=1 ;"default to success kill Info if $get(IENS)="" goto ELDone do GETS^DIQ(22709.11,IENS,"1;1.5;2;3;4","","TMGDATA","TMGMSG") if $data(TMGMSG("DIERR")) do goto ELDone . new tempS set tempS=$$GetErrStr^TMGDEBUG(.TMGMSG) . do AddMsg(tempS,1,.Msg) . if verbose write tempS,! new URL set URL=$get(TMGDATA(22709.11,IENS,1)) set Info("KID URL")=URL new textURL set textURL=$get(TMGDATA(22709.11,IENS,1.5)) set Info("TEXT URL")=textURL if URL="" do . if textURL'="" set Info("TEXT ONLY")=1 quit . new tempS set tempS="No URL found for KIDS patch or accompanying Info text file in FM File #22709.22, IENS="_IENS . do AddMsg(tempS,1,.Msg) . if verbose write tempS,! new Path set Path=$get(TMGDATA(22709.11,IENS,2)) if Path="" do . set Path=$get(^TMG("KIDS","PATCH DIR"),"/tmp/") . set TMGFDA(22709.11,IENS,2)=Path set Info("PATH")=Path new Filename set Filename=$get(TMGDATA(22709.11,IENS,3)) new textFilename set textFilename=$get(TMGDATA(22709.11,IENS,4)) if (Filename'=""),$$FileExists^TMGIOUTL(Path_Filename) do . set Info("KID FILE")=Filename else if (URL'="") do . if verbose write "Downloading KID file from FTP.VA.GOV..." . if $$DownloadFile^TMGKERNL(URL,Path) . set Filename=$$FNameExtract^TMGIOUTL(URL) . if $$FileExists^TMGIOUTL(Path_Filename) do . . if $$Dos2Unix^TMGKERNL(Path_Filename) . . set TMGFDA(22709.11,IENS,3)=Filename . . set Info("KID FILE")=Filename . else set result=0 . if verbose write ! if (textFilename'=""),$$FileExists^TMGIOUTL(Path_textFilename) do . set Info("TEXT FILE")=textFilename else if (textURL'="") do . if verbose write "Downloading TEXT file from FTP.VA.GOV..." . if $$DownloadFile^TMGKERNL(textURL,Path) . set textFilename=$$FNameExtract^TMGIOUTL(textURL) . if $$FileExists^TMGIOUTL(Path_textFilename) do . . set TMGFDA(22709.11,IENS,4)=textFilename . . set Info("TEXT FILE")=textFilename . set result=0 . if verbose write ! set result=1 ;"success ELDone kill TMGMSG if $data(TMGFDA) do . do FILE^DIE("","TMGFDA","TMGMSG") . if $data(TMGMSG("DIERR")) do . . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . . set result=0 . . if verbose write Msg("ERROR",MsgI),! quit result DownloadPatch(PatchName,protocol,Option,Msg,Info) ;"Purpose: Ensure that the Patch has been downloaded from server and stored locally ;"Input: PatchName -- the name of the patch to get, e.g. ABC*12.34*1234 [SEQ #123] ;" protocol -- OPTIONAL. Default is 'ftp://' ;" Option -- optional. Pass by reference. ;" Option("VERBOSE")=1, means messaages also written directly to output ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;" Info -- PASS BY REFERENCE, an IN and OUT PARAMETER. ;" Info("PATH")=Path in HFS ;" Info("KID FILE")=HFS filename of .KID patch ;" Info("TEXT FILE")=HFS filename of .TXT accompanying patch ;" Info("TEXT ONLY")=1 if there is a text file, but no .KIDS file ;" Info("KID URL")=URL on server for KID file ;" Info("TEXT URL")=URL on server for TXT file ;"Output: Info will be filled as follows: ;" Info("PATH")=Path in HFS ;" Info("KID FILE")=HFS filename of .KID patch ;"results: 1 if OK, 0 if problem. new result set result=1 new seqNum,PckInit,Ver,PatchNum,seqNum,PckDirFName,URL new verbose set verbose=($get(Option("VERBOSE"))=1) set protocol=$get(protocol,"ftp://") if PatchName?2.4N1"*"1.3N.(1"."1.4N)1"*"1.4N do . do ParsePatchName(PatchName,.PckInit,.Ver,.PatchNum,.seqNum) else if PatchName?1.4A1"_".E do . set PckInit=$piece(PatchName,"_",1) else do goto:(result=0) DLPDone . new tempName set tempName=$get(Info("TEXT FILE")) . if tempName="" set result=0 quit . if tempName?1.4A1"_".E do . . set PckInit=$piece(tempName,"_",1) . else if tempName?1.4A1"-".E do . . set PckInit=$piece(tempName,"-",1) . if $get(PckInit)="" set result=0 set result=$$RefreshPackge(PckInit,.Msg,0,.PckDirFName) goto:(result=0) DLPDone set result=$$FindMultPatch^TMGPAT4(PatchName,PckInit,.Option,.URL,.Info) goto:(result=0) DLPDone new Filename,Path set Path=$get(^TMG("KIDS","PATCH DIR"),"/tmp/") set Info("PATH")=Path set Filename=$$FNameExtract^TMGIOUTL(URL) if $$FileExists^TMGIOUTL(Path_Filename) goto DLPDone if verbose write "Downloading "_Filename_" from FTP.VA.GOV...",! new spec set spec("\ ")="%20" set URL=$$REPLACE^XLFSTR(URL,.spec) if $$DownloadFile^TMGKERNL(protocol_URL,Path,0) if $$FileExists^TMGIOUTL(Path_Filename)=0 set result=0 goto DLPDone if $$Dos2Unix^TMGKERNL(Path_Filename) set Info("KID FILE")=Filename DLPDone quit result FORCEPAT ;"Purpose: All user to enter a patch entry new PckInit,Ver,DIR,PatchNum,SeqNum,NewPatch do GetPckVer^TMGPAT1(.PckInit,.Ver) set DIR(0)="N",DIR("A")="Enter PATCH NUMBER" do ^DIR write ! set PatchNum=Y if $get(DIRUT) goto FPDone set DIR(0)="N",DIR("A")="Enter SEQUENCE NUMBER" do ^DIR write ! set SeqNum=Y if $get(DIRUT) goto FPDone do ForceP2(.PckInit,.Ver,.PatchNum,.SeqNum) quit ForceP2(PckInit,Ver,PatchNum,SeqNum) ;"Purpose: Hack write a patch into Package file, based in componant parts. ;"Results: None new NewPatch set NewPatch=PckInit_"*"_Ver_"*"_PatchNum_" SEQ #"_SeqNum new DIR set DIR(0)="Y" set DIR("A")="HACK/FORCE an entry in the Package file for: "_NewPatch_" (Y/N)" do ^DIR write ! if $get(DIRUT)!(Y'=1) goto FPDone new Msg if $$MakePatchEntry^TMGPAT2(NewPatch,.Msg) if $$ShowMsg^TMGPAT2(.Msg) FPDone quit MakePatchEntry(PatchName,Msg) ;"Purpose: For times when a patch was informational only, and there was ;" no KIDS file to actually install, then this can make pseudo-entries ;" to show that something was processed. ;"Input: PatchName -- The name of the patch. Eg: DI*22*123 SEQ #456" ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;"Results: 1 if OK, 0 if error new %,X,result new TMGMSG,TMGFDA,TMGIEN set result=1 new justPatch set justPatch=$piece(PatchName," SEQ",1) new tempIEN set tempIEN=+$order(^XPD(9.7,"B",justPatch,"")) if tempIEN>0 goto MPE2 ;"INSTALL entry already made do NOW^%DTC set TMGFDA(9.7,"+1,",.01)=justPatch set TMGFDA(9.7,"+1,",.02)=3 ;"2 = status set TMGFDA(9.7,"+1,",6)="Text_Only "_PatchName ;"6 = file comment set TMGFDA(9.7,"+1,",9)=DUZ ;"9 = Installed by set TMGFDA(9.7,"+1,",11)=% ;"11 = Install start time set TMGFDA(9.7,"+1,",17)=% ;"17 = Install completion time do UPDATE^DIE("","TMGFDA","TMGIEN","TMGMSG") if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . set result=0 MPE2 set PckInit=$piece(PatchName,"*",1) set Ver=$piece(PatchName,"*",2) if (PckInit="")!(Ver="") set result=0 goto MPEDone new IEN9d4,IEN9d49 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) if IEN9d4'>0 set result=0 goto MPEDone set IEN9d49=+$order(^DIC(9.4,IEN9d4,22,"B",Ver,"")) if IEN9d49'>0 set result=0 goto MPEDone new PatchSeq set PatchSeq=$piece(PatchName,"*",3) set tempIEN=$order(^DIC(9.4,IEN9d4,22,IEN9d49,"PAH","B",PatchSeq,"")) if tempIEN>0 do goto MPE3 . set TMGIEN(1)=tempIEN new IENS set IENS="+1,"_IEN9d49_","_IEN9d4_"," kill TMGFDA,TMGMSG,TMGIEN set TMGFDA(9.4901,IENS,.01)=PatchSeq ;".01=Patch Hx, e.g. 10 SEQ #10 set TMGFDA(9.4901,IENS,.02)="NOW" ;".02=date applied set TMGFDA(9.4901,IENS,.03)="`"_DUZ ;".03=Applied by do UPDATE^DIE("E","TMGFDA","TMGIEN","TMGMSG") if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . set result=0 MPE3 if result=0 goto MPEDone new TMGWP kill TMGFDA,TMGMSG set TMGWP(1)="Patch was informational only. No installed code etc." set TMGWP(2)="This entry was created as a marker that information was processed." set IENS=TMGIEN(1)_","_IEN9d49_","_IEN9d4_"," do WP^DIE(9.4901,IENS,1,"","TMGWP","TMGMSG") if $data(TMGMSG("DIERR")) do . do AddMsg($$GetErrStr^TMGDEBUG(.TMGMSG),1,.Msg) . set result=0 MPEDone quit result IsInstalled(PatchName) ;"Purpose: To return if a given patch has already been installed. ;"Input: PatchName -- format aaaa*nn.nn*mmm [SEQ #xxx] ;"Result: 1 if installed, 0 if not, or problem. new result set result=0 new PckInit,Ver,PatchNum set PatchName=$piece(PatchName," ",1) set PatchName=$$TrimRType^TMGSTUTL(PatchName,"C") ;"trim any characters off end of patch name, e.g. 'ABC*5.5*123<==' set PckInit=$piece(PatchName,"*",1) set Ver=$piece(PatchName,"*",2) set PatchNum=$piece(PatchName,"*",3) if (PckInit="")!(Ver="")!(PatchNum="") goto IIDone new IEN9d4,IEN9d49 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,"")) if IEN9d4'>0 goto IIDone set IEN9d49=+$order(^DIC(9.4,IEN9d4,22,"B",Ver,"")) if IEN9d49'>0 do . new oneVer set oneVer="" . new found set found=0 . for set oneVer=$order(^DIC(9.4,IEN9d4,22,"B",oneVer)) quit:(oneVer="")!found do . . new Int,oneInt,Dec,oneDec . . set Int=$piece(Ver,".",1),Dec=+$piece(Ver,".",2) . . set oneInt=$piece(oneVer,".",1),oneDec=+$piece(oneVer,".",2) . . if (Int=oneInt)&(Dec=oneDec) do . . . set IEN9d49=+$order(^DIC(9.4,IEN9d4,22,"B",oneVer,"")) . . . set found=1 if IEN9d49'>0 goto IIDone goto:(IEN9d49'>0) IIDone new i,array,done set i="",done=0 for set i=$order(^DIC(9.4,IEN9d4,22,IEN9d49,"PAH","B",i)) quit:(i="") do . new onePatchNum set onePatchNum=$piece(i," ",1) . if onePatchNum=PatchNum do . . set result=1,done=1 IIDone quit result ParsePatchName(PatchName,PckInit,Ver,PatchNum,SeqNum) ;"Purpose: to parse a patch name into it's composit parts. ;"Input: PatchName -- the patch name to parse, e.g. ABC*12.34*1234 SEQ #123 ;" PckInit,Ver,PatchNum,SeqNum -- PASS BY REFERENCE, OUT PARAMETERS ;"Results: none set SeqNum=+$piece(PatchName,"SEQ #",2) set PatchName=$piece(PatchName," SEQ #",1) set PckInit=$piece(PatchName,"*",1) set Ver=$piece(PatchName,"*",2) set PatchNum=$piece(PatchName,"*",3) quit AddMsg(s,IsError,Msg) ;"Purpose: to add a message to Msg Array ;"Input: s -- message. May be a string, or an array (or both) in format of: ;" s=A line ;" s(1)=line 1 ;" s(2)=line 2 ;" IsError -- 1 if is an error message ;" Msg -- PASS BY REFERENCE, an OUT PARAMETER. ;" Errors are stored in Msg("ERROR",x)=Message ;" Msg("ERROR")=count of last error ;" Message are store in Msg(x)=Message ;" Msg=count of last message+1 ;"Results: none set IsError=+$get(IsError) new oneLine,subI set subI="" set oneLine=$get(s) for do set subI=$order(s(subI)) quit:(subI="") set oneLine=$get(s(subI)) . if IsError do . . new MsgI set MsgI=$get(Msg("ERROR"),0)+1 . . set Msg("ERROR",MsgI)=oneLine . . set Msg("ERROR")=MsgI . else do . . set Msg=+$get(Msg,1) . . set Msg(Msg)=oneLine,Msg=Msg+1 quit ShowMsg(Msg,NoPause) ;"Purpose: to display the message array ;"Input: Msg - PASS BY REFERENCE. The message array to display. ;" NoPause -- OPTIONAL. If 1, then user not prompted to hit enter to cont. ;"Results: 0 if OK, 1 if ERROR found in message array. new errorFound set errorFound=0 if $data(Msg) do . new i set i="" . for set i=$order(Msg(i)) quit:(+i'>0) write " ",$get(Msg(i)),! . if $data(Msg("ERROR")) do . . write !!,"NOTE: ERRORS ENCOUNTERED:",! . . set i="" . . for set i=$order(Msg("ERROR",i)) quit:(+i'>0) write " ",$get(Msg("ERROR",i)),! . . set errorFound=1 . if $get(NoPause)'=1 do PressToCont^TMGUSRIF quit errorFound