| 1 | HLCSTCP1 ;SFIRMFO/RSD - BI-DIRECTIONAL TCP ;7/28/07  08:58
 | 
|---|
| 2 |  ;;1.6;HEALTH LEVEL SEVEN;**19,43,57,64,71,133,132,122**;OCT 13,1995;Build 4
 | 
|---|
| 3 |  ;Per VHA Directive 2004-038, this routine should not be modified.
 | 
|---|
| 4 |  ;Receiver
 | 
|---|
| 5 |  ;connection is initiated by sender and listener accepts connection
 | 
|---|
| 6 |  ;and calls this routine
 | 
|---|
| 7 |  ;
 | 
|---|
| 8 |  N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP1"
 | 
|---|
| 9 |  N HLMIEN,HLASTMSG
 | 
|---|
| 10 |  ;
 | 
|---|
| 11 |  ; patch HL*1.6*122 start
 | 
|---|
| 12 |  ; variable to replace ^TMP
 | 
|---|
| 13 |  N HLTMBUF
 | 
|---|
| 14 |  ; for HL7 application proxy user
 | 
|---|
| 15 |  N HLDUZ,DUZ
 | 
|---|
| 16 |  D MON^HLCSTCP("Open")
 | 
|---|
| 17 |  ; K ^TMP("HLCSTCP",$J,0)
 | 
|---|
| 18 |  S HLMIEN=0,HLASTMSG=""
 | 
|---|
| 19 |  ; set DUZ for application proxy user
 | 
|---|
| 20 |  D PROXY^HLCSTCP4
 | 
|---|
| 21 |  F  D  Q:$$STOP^HLCSTCP  I 'HLMIEN D MON^HLCSTCP("Idle") H 3
 | 
|---|
| 22 |  . ; clean variables
 | 
|---|
| 23 |  . D CLEANVAR^HLCSTCP4
 | 
|---|
| 24 |  . S HLMIEN=$$READ
 | 
|---|
| 25 |  . Q:'HLMIEN
 | 
|---|
| 26 |  . ; DUZ comparison/reset for application proxy user
 | 
|---|
| 27 |  . D HLDUZ^HLCSTCP4
 | 
|---|
| 28 |  . ; protect HLDUZ 
 | 
|---|
| 29 |  . N HLDUZ
 | 
|---|
| 30 |  . D PROCESS
 | 
|---|
| 31 |  ; patch HL*1.6*122 end
 | 
|---|
| 32 |  Q
 | 
|---|
| 33 |  ;
 | 
|---|
| 34 | PROCESS ;check message and reply
 | 
|---|
| 35 |  ;HLDP=LL in 870
 | 
|---|
| 36 |  N HLTCP,HLTCPI,HLTCPO
 | 
|---|
| 37 |  S HLTCP="",HLTCPO=HLDP,HLTCPI=+HLMIEN
 | 
|---|
| 38 |  ;update monitor, msg. received
 | 
|---|
| 39 |  D LLCNT^HLCSTCP(HLDP,1)
 | 
|---|
| 40 |  D NEW^HLTP3(HLMIEN)
 | 
|---|
| 41 |  ;update monitor, msg. processed
 | 
|---|
| 42 |  D LLCNT^HLCSTCP(HLDP,2)
 | 
|---|
| 43 |  Q
 | 
|---|
| 44 |  ;
 | 
|---|
| 45 | READ() ;read 1 message, returns ien in 773^ien in 772 for message
 | 
|---|
| 46 |  D MON^HLCSTCP("Reading")
 | 
|---|
| 47 |  N HLDB,HLDT,HLDEND,HLACKWT,HLDSTRT,HLHDR,HLIND1,HLINE,HLMSG,HLRDOUT,HLRS,HLX,X
 | 
|---|
| 48 |  ;HLDSTRT=start char., HLDEND=end char., HLRS=record seperator
 | 
|---|
| 49 |  S HLDSTRT=$C(11),HLDEND=$C(28),HLRS=$C(13)
 | 
|---|
| 50 |  ;HLRDOUT=exit read loop, HLINE=line count, HLIND1=ien 773^ien 772
 | 
|---|
| 51 |  ;HLHDR=have a header, HLTMBUF()=excess from last read, HLACKWT=wait for ack
 | 
|---|
| 52 |  ; HL*1.6*122 start
 | 
|---|
| 53 |  ; S (HLRDOUT,HLINE,HLIND1,HLHDR)=0,HLX=$G(^TMP("HLCSTCP",$J,0)),HLACKWT=HLDBACK
 | 
|---|
| 54 |  S (HLRDOUT,HLINE,HLIND1,HLHDR)=0,HLX=$G(HLTMBUF(0)),HLACKWT=HLDBACK
 | 
|---|
| 55 |  N HLBUFF,HLXX,MAXWAIT
 | 
|---|
| 56 |  ; based on patch 132 for readtime
 | 
|---|
| 57 |  S MAXWAIT=$S((HLACKWT>HLDREAD):HLACKWT,1:HLDREAD)
 | 
|---|
| 58 |  S HLRS("START-FLAG")=0
 | 
|---|
| 59 |  S HLTMBUF(0)=""
 | 
|---|
| 60 |  ; variable used to store data in HLBUFF
 | 
|---|
| 61 |  S HLX(1)=$G(HLTMBUF(1))
 | 
|---|
| 62 |  S HLTMBUF(1)=""
 | 
|---|
| 63 |  S HLBUFF("START")=0
 | 
|---|
| 64 |  S HLBUFF("END")=0
 | 
|---|
| 65 |  I (HLX]"")!(HLX(1)]"") D
 | 
|---|
| 66 |  . I (HLX[HLDSTRT)!(HLX(1)[HLDSTRT) D
 | 
|---|
| 67 |  .. S HLBUFF("START")=1
 | 
|---|
| 68 |  . I (HLX[HLDEND)!(HLX(1)[HLDEND) D
 | 
|---|
| 69 |  .. S HLBUFF("END")=1
 | 
|---|
| 70 |  F  D RDBLK Q:HLRDOUT
 | 
|---|
| 71 |  ;**132**
 | 
|---|
| 72 |  ;switch to null device if opened to prevent 'leakage'
 | 
|---|
| 73 |  I $G(IO(0))]"",IO(0)'=IO U IO(0)
 | 
|---|
| 74 |  ;
 | 
|---|
| 75 |  ;save any excess for next time
 | 
|---|
| 76 |  S:HLX]"" HLTMBUF(0)=HLX
 | 
|---|
| 77 |  S:HLX(1)]"" HLTMBUF(1)=HLX(1)
 | 
|---|
| 78 |  I +HLIND1,'$P(HLIND1,U,3) D DELMSG(HLIND1) S HLIND1=0
 | 
|---|
| 79 |  Q HLIND1
 | 
|---|
| 80 |  ;
 | 
|---|
| 81 | RDBLK ;
 | 
|---|
| 82 |  ; initialize
 | 
|---|
| 83 |  S HLBUFF=""
 | 
|---|
| 84 |  ;
 | 
|---|
| 85 |  ;S HLDB=HLDBSIZE-$L(HLX)
 | 
|---|
| 86 |  ; store the total length of HLX and HLX(1) in HLDB(1)
 | 
|---|
| 87 |  S HLDB(1)=$L(HLX)+$L(HLX(1))
 | 
|---|
| 88 |  ;
 | 
|---|
| 89 |  ;**132 **
 | 
|---|
| 90 |  ;U IO R X#HLDB:HLDREAD
 | 
|---|
| 91 |  ; U IO R X#HLDB:MAXWAIT
 | 
|---|
| 92 |  ;
 | 
|---|
| 93 |  ; remove the readcount to speedup GT.M
 | 
|---|
| 94 |  U IO
 | 
|---|
| 95 |  R:(HLDB(1)<HLDBSIZE) HLBUFF:MAXWAIT
 | 
|---|
| 96 |  I HLBUFF]"" D
 | 
|---|
| 97 |  . I HLBUFF[HLDSTRT,(HLBUFF("START")=0) D
 | 
|---|
| 98 |  .. ; remove the extraneous text prefixing the "START" char
 | 
|---|
| 99 |  .. I $P(HLBUFF,HLDSTRT)]"" S HLBUFF=HLDSTRT_$P(HLBUFF,HLDSTRT,2,99)
 | 
|---|
| 100 |  .. S HLBUFF("START")=1
 | 
|---|
| 101 |  . ;
 | 
|---|
| 102 |  . I HLBUFF[HLDEND,(HLBUFF("END")=0) S HLBUFF("END")=1
 | 
|---|
| 103 |  ; detect disconnect for GT.M
 | 
|---|
| 104 |  I $G(^%ZOSF("OS"))["GT.M",$DEVICE S $ECODE=""
 | 
|---|
| 105 |  ; timedout, <clean up>, quit
 | 
|---|
| 106 |  ;I '$T,X="",HLX="" S HLACKWT=HLACKWT-HLDREAD D:HLACKWT<0&'HLHDR CLEAN Q
 | 
|---|
| 107 |  ;I '$T,X="",HLX="" D:'HLHDR CLEAN Q
 | 
|---|
| 108 |  I '$T,HLBUFF="",HLX="",HLX(1)="" D  Q
 | 
|---|
| 109 |  . D:('HLHDR)&('HLIND1) CLEAN
 | 
|---|
| 110 |  ;add incoming line to what wasn't processed in last read
 | 
|---|
| 111 |  ;S HLX=$G(HLX)_X
 | 
|---|
| 112 |  ;
 | 
|---|
| 113 |  ; get block of characters from read buffer HLBUFF
 | 
|---|
| 114 |  ; every 'for-loop' deal with one read at most, and one message at most
 | 
|---|
| 115 |  ; if HLX is not empty, loop continues even no data is read
 | 
|---|
| 116 |  ; quit, if both HLDBUFF and HLX(1) are empty, means one read is done
 | 
|---|
| 117 |  ; quit, when HLRDOUT is set to 1, means one message is encountered
 | 
|---|
| 118 |  ; an "end"
 | 
|---|
| 119 |  ; F  D  Q:HLXX=""!(HLRDOUT)
 | 
|---|
| 120 |  F  D  Q:(HLRDOUT)!(HLBUFF=""&(HLX(1)=""))
 | 
|---|
| 121 |  . ;
 | 
|---|
| 122 |  . ; if HLX(1) is not empty
 | 
|---|
| 123 |  . I HLX(1)]"" D
 | 
|---|
| 124 |  .. ; hldb(2) is the number of characters extracted from hlx(1)
 | 
|---|
| 125 |  .. ; to be concatenated with hlx
 | 
|---|
| 126 |  .. S HLDB(2)=HLDBSIZE-$L(HLX)
 | 
|---|
| 127 |  .. ; hlx(2) stores the first hldb(2) characters extracted
 | 
|---|
| 128 |  .. ; from hlx(1)
 | 
|---|
| 129 |  .. S HLX(2)=$E(HLX(1),1,HLDB(2))
 | 
|---|
| 130 |  .. S HLX(1)=$E(HLX(1),HLDB(2)+1,$L(HLX(1)))
 | 
|---|
| 131 |  .. S HLX=$G(HLX)_HLX(2)
 | 
|---|
| 132 |  . ;
 | 
|---|
| 133 |  . ; if HLX(1) is empty, and HLBUFF contains data
 | 
|---|
| 134 |  . ; all the data in hlx(1) need to be extracted first
 | 
|---|
| 135 |  . I HLX(1)="",HLBUFF]"" D
 | 
|---|
| 136 |  .. S HLDB=HLDBSIZE-$L(HLX)
 | 
|---|
| 137 |  .. S HLXX=$E(HLBUFF,1,HLDB)
 | 
|---|
| 138 |  .. S HLBUFF=$E(HLBUFF,HLDB+1,$L(HLBUFF))
 | 
|---|
| 139 |  .. S HLX=$G(HLX)_HLXX
 | 
|---|
| 140 |  . ; quit when HLX is empty
 | 
|---|
| 141 |  . Q:(HLX="")
 | 
|---|
| 142 |  . ; ** 132 **
 | 
|---|
| 143 |  . ; if no segment end, HLX not full, go back for more
 | 
|---|
| 144 |  . I $L(HLX)<HLDBSIZE,HLX'[HLRS,HLX'[HLDEND Q
 | 
|---|
| 145 |  . ;add incoming line to what wasn't processed
 | 
|---|
| 146 |  . D RDBLK2
 | 
|---|
| 147 |  ;
 | 
|---|
| 148 |  ; it is possible one message is encountered an "end" and other
 | 
|---|
| 149 |  ; messages left in buffer,HLBUFF, save it in HLX for next run
 | 
|---|
| 150 |  I HLBUFF]"" D
 | 
|---|
| 151 |  . ; variable HLBUFF may remain data with size more than HLDBSIZE
 | 
|---|
| 152 |  . ; variable HLBUFF is not empty, only if the total length of
 | 
|---|
| 153 |  . ; HLX and HLX(1) is less than HLDBSIZE and HLX(1) should be
 | 
|---|
| 154 |  . ; empty when the command s hlx(1)=$g(hlx(1))_hlbuff is executed
 | 
|---|
| 155 |  . ; use hlx(1) to store the data of hlbuff to avoid "MAXTRING" error
 | 
|---|
| 156 |  . S HLX(1)=$G(HLX(1))_HLBUFF
 | 
|---|
| 157 |  . S HLBUFF=""
 | 
|---|
| 158 |  Q
 | 
|---|
| 159 |  ;
 | 
|---|
| 160 | RDBLK2 ;data stream: <sb>dddd<cr><eb><cr>
 | 
|---|
| 161 |  ; HL*1.6*122 end
 | 
|---|
| 162 |  ; look for segment= <CR>
 | 
|---|
| 163 |  F  Q:HLX'[HLRS  D  Q:HLRDOUT
 | 
|---|
| 164 |  . ; Get the first piece, save the rest of the line
 | 
|---|
| 165 |  . S HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLRS),HLX=$P(HLX,HLRS,2,999)
 | 
|---|
| 166 |  . ; check for start block, Quit if no ien
 | 
|---|
| 167 |  . I HLMSG(HLINE,0)[HLDSTRT!HLHDR D  Q
 | 
|---|
| 168 |  .. S HLRS("START-FLAG")=1 ; HL*1.6*122
 | 
|---|
| 169 |  .. D:HLMSG(HLINE,0)[HLDSTRT
 | 
|---|
| 170 |  ... S X=$L(HLMSG(HLINE,0),HLDSTRT)
 | 
|---|
| 171 |  ... S:X>2 HLMSG(HLINE,0)=HLDSTRT_$P(HLMSG(HLINE,0),HLDSTRT,X)
 | 
|---|
| 172 |  ... S HLMSG(HLINE,0)=$P(HLMSG(HLINE,0),HLDSTRT,2)
 | 
|---|
| 173 |  ... D RESET:(HLINE>1)
 | 
|---|
| 174 |  .. ;
 | 
|---|
| 175 |  .. ; patch HL*1.6*122
 | 
|---|
| 176 |  .. ; if the first line less than 10 characters
 | 
|---|
| 177 |  .. I HLHDR,$L(HLMSG(1,0))<10,$D(HLMSG(2,0)) D
 | 
|---|
| 178 |  ... S HLMSG(1,0)=HLMSG(1,0)_$E(HLMSG(2,0),1,10)
 | 
|---|
| 179 |  ... S HLMSG(2,0)=$E(HLMSG(2,0),11,9999999)
 | 
|---|
| 180 |  .. ;
 | 
|---|
| 181 |  .. ;ping message
 | 
|---|
| 182 |  .. I $E(HLMSG(1,0),1,9)="MSH^PING^" D PING Q
 | 
|---|
| 183 |  .. ; get next ien to store
 | 
|---|
| 184 |  .. D MIEN^HLCSTCP4
 | 
|---|
| 185 |  .. K HLMSG
 | 
|---|
| 186 |  .. S (HLINE,HLHDR)=0
 | 
|---|
| 187 |  . ; check for end block; <eb><cr>
 | 
|---|
| 188 |  . I HLMSG(HLINE,0)[HLDEND D
 | 
|---|
| 189 |  .. ; patch HL*1.6*122 start
 | 
|---|
| 190 |  .. ;no msg. ien
 | 
|---|
| 191 |  .. ; Q:'HLIND1
 | 
|---|
| 192 |  .. I 'HLIND1 D CLEAN Q
 | 
|---|
| 193 |  .. ; Kill just the last line if no data before HLDEND
 | 
|---|
| 194 |  .. I $P(HLMSG(HLINE,0),HLDEND)']"" D
 | 
|---|
| 195 |  ... K HLMSG(HLINE,0) S HLINE=HLINE-1
 | 
|---|
| 196 |  .. E  S HLMSG(HLINE,0)=$P(HLMSG(HLINE,0),HLDEND)
 | 
|---|
| 197 |  .. ; patch HL*1.6*122 end
 | 
|---|
| 198 |  .. ;
 | 
|---|
| 199 |  .. ; move into 772
 | 
|---|
| 200 |  .. D SAVE(.HLMSG,"^HL(772,"_+$P(HLIND1,U,2)_",""IN"")")
 | 
|---|
| 201 |  .. ;mark that end block has been received
 | 
|---|
| 202 |  .. ;HLIND1=ien in 773^ien in 772^1 if end block was received
 | 
|---|
| 203 |  .. S $P(HLIND1,U,3)=1
 | 
|---|
| 204 |  .. S HLBUFF("HLIND1")=HLIND1
 | 
|---|
| 205 |  .. ;reset variables for next message
 | 
|---|
| 206 |  .. D CLEAN
 | 
|---|
| 207 |  . ;add blank line for carriage return
 | 
|---|
| 208 |  . I HLINE'=0,HLMSG(HLINE,0)]"" S HLINE=HLINE+1,HLMSG(HLINE,0)=""
 | 
|---|
| 209 |  Q:HLRDOUT
 | 
|---|
| 210 |  ;If the line is long and no <CR> move it into the array.
 | 
|---|
| 211 |  I ($L(HLX)=HLDBSIZE),(HLX'[HLRS),(HLX'[HLDEND),(HLX'[HLDSTRT) D  Q
 | 
|---|
| 212 |  . S HLINE=HLINE+1,HLMSG(HLINE,0)=HLX,HLX=""
 | 
|---|
| 213 |  ;have start block but no record seperator
 | 
|---|
| 214 |  I HLX[HLDSTRT D  Q
 | 
|---|
| 215 |  . ;check for more than 1 start block
 | 
|---|
| 216 |  . S X=$L(HLX,HLDSTRT) S:X>2 HLX=HLDSTRT_$P(HLX,HLDSTRT,X)
 | 
|---|
| 217 |  . ;
 | 
|---|
| 218 |  . ; patch HL*1.6*122
 | 
|---|
| 219 |  . ; S:$L($P(HLX,HLDSTRT,2))>8 HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLDSTRT,2),HLX="",HLHDR=1
 | 
|---|
| 220 |  . S HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLDSTRT,2),HLX="",HLHDR=1
 | 
|---|
| 221 |  . ;
 | 
|---|
| 222 |  . D RESET:(HLHDR&(HLINE>1))
 | 
|---|
| 223 |  ;if no ien, reset
 | 
|---|
| 224 |  ; patch HL*1.6*122
 | 
|---|
| 225 |  ; I 'HLIND1 D CLEAN Q
 | 
|---|
| 226 |  I (HLRS("START-FLAG")=1),'HLIND1 D CLEAN Q
 | 
|---|
| 227 |  ; big message-merge from local to global every 100 lines
 | 
|---|
| 228 |  I (HLINE-$O(HLMSG(0)))>100 D
 | 
|---|
| 229 |  . M ^HL(772,+$P(HLIND1,U,2),"IN")=HLMSG
 | 
|---|
| 230 |  . ; reset working array
 | 
|---|
| 231 |  . K HLMSG
 | 
|---|
| 232 |  Q
 | 
|---|
| 233 |  ;
 | 
|---|
| 234 | SAVE(SRC,DEST) ;save into global & set top node
 | 
|---|
| 235 |  ;SRC=source array (passed by ref.), DEST=destination global
 | 
|---|
| 236 |  M @DEST=SRC
 | 
|---|
| 237 |  S @DEST@(0)="^^"_HLINE_"^"_HLINE_"^"_DT_"^"
 | 
|---|
| 238 |  Q
 | 
|---|
| 239 |  ;
 | 
|---|
| 240 | DELMSG(HLMAMT) ;delete message from Message Administration/Message Text files.
 | 
|---|
| 241 |  N DIK,DA
 | 
|---|
| 242 |  S DA=+HLMAMT,DIK="^HLMA("
 | 
|---|
| 243 |  D ^DIK
 | 
|---|
| 244 |  S DA=$P(HLMAMT,U,2),DIK="^HL(772,"
 | 
|---|
| 245 |  D ^DIK
 | 
|---|
| 246 |  Q
 | 
|---|
| 247 | PING ;process PING message
 | 
|---|
| 248 |  S X=HLMSG(1,0)
 | 
|---|
| 249 |  I X[HLDEND U IO W X,! D
 | 
|---|
| 250 |  . ; switch to null device if opened to prevent 'leakage'
 | 
|---|
| 251 |  . I $G(IO(0))]"",$G(IO(0))'=IO U IO(0)
 | 
|---|
| 252 | CLEAN ;reset var. for next message
 | 
|---|
| 253 |  K HLMSG
 | 
|---|
| 254 |  S HLINE=0,HLRDOUT=1
 | 
|---|
| 255 |  Q
 | 
|---|
| 256 |  ;
 | 
|---|
| 257 | ERROR ; Error trap for disconnect error and return back to the read loop.
 | 
|---|
| 258 |  S $ETRAP="D UNWIND^%ZTER"
 | 
|---|
| 259 |  I $$EC^%ZOSV["IOEOF" D UNWIND^%ZTER Q  ;VOE change for GT.M
 | 
|---|
| 260 |  I $$EC^%ZOSV["READ"!($$EC^%ZOSV["NOTOPEN")!($$EC^%ZOSV["DEVNOTOPN") D UNWIND^%ZTER Q
 | 
|---|
| 261 |  I $$EC^%ZOSV["WRITE" D CC("Wr-err") D UNWIND^%ZTER Q
 | 
|---|
| 262 |  I $ECODE["UREAD" D UNWIND^%ZTER Q  ; HL*1.6*122 GT.M
 | 
|---|
| 263 |  S HLCSOUT=1 D ^%ZTER,CC("Error")
 | 
|---|
| 264 |  D UNWIND^%ZTER
 | 
|---|
| 265 |  Q
 | 
|---|
| 266 |  ;
 | 
|---|
| 267 | CC(X) ;cleanup and close
 | 
|---|
| 268 |  D MON^HLCSTCP(X)
 | 
|---|
| 269 |  H 2
 | 
|---|
| 270 |  Q
 | 
|---|
| 271 | RESET ;reset info as a result of no end block
 | 
|---|
| 272 |  N %
 | 
|---|
| 273 |  S HLMSG(1,0)=HLMSG(HLINE,0)
 | 
|---|
| 274 |  F %=2:1:HLINE K HLMSG(%,0)
 | 
|---|
| 275 |  S HLINE=1
 | 
|---|
| 276 |  Q
 | 
|---|