| [613] | 1 | XMRPOP ;ISC-SF/GMB-POP3 Server (RFC 1939) ;05/20/2002  07:05
 | 
|---|
 | 2 |  ;;8.0;MailMan;;Jun 28, 2002
 | 
|---|
 | 3 |  ; Replaces the class III routines ^XMRPOPA, ^XMRPOPB, ^XMRPOPC,
 | 
|---|
 | 4 |  ; which were written by Chiao-Ming Wu, WASH-ISC.
 | 
|---|
 | 5 |  ;
 | 
|---|
 | 6 |  ; Implements RFC 1939 (replaces RFC 1725)
 | 
|---|
 | 7 |  ; Post Office Protocol - Version 3 (POP3) maildrop service
 | 
|---|
 | 8 |  ;
 | 
|---|
 | 9 |  ; Rather than locking the user's IN basket, which severely disrupts
 | 
|---|
 | 10 |  ; mail delivery, we take a snapshot of it, and keep the snapshot in
 | 
|---|
 | 11 |  ; a temp global.  We then use the temp global during the session.
 | 
|---|
 | 12 |  ; Here is the layout of the global:
 | 
|---|
 | 13 |  ;
 | 
|---|
 | 14 |  ; ^TMP("XM",$J,"POP3")=# msgs^# octets   ; total msgs in IN basket
 | 
|---|
 | 15 |  ;                                        ; (updated if msgs are deleted)
 | 
|---|
 | 16 |  ; ^TMP("XM",$J,"POP3",1)=XMZ^# octets    ; msgs 1 thru n are in
 | 
|---|
 | 17 |  ;         ...                            ; IN basket.
 | 
|---|
 | 18 |  ; ^TMP("XM",$J,"POP3",i)=XMZ^# octets    ; 
 | 
|---|
 | 19 |  ; ^TMP("XM",$J,"POP3",j)=XMZ^# octets    ; 
 | 
|---|
 | 20 |  ;         ...                            ; 
 | 
|---|
 | 21 |  ; ^TMP("XM",$J,"POP3",n)=XMZ^# octets    ; 
 | 
|---|
 | 22 |  ;                                        ;
 | 
|---|
 | 23 |  ; ^TMP("XM",$J,"POP3","D",i)=XMZ         ; user deleted msg i
 | 
|---|
 | 24 |  ; ^TMP("XM",$J,"POP3","D",j)=XMZ         ; user deleted msg j
 | 
|---|
 | 25 | ENTRY ;
 | 
|---|
 | 26 |  N XMK,XMSTATE,XMCMDS,XMCMD,XMDUZ,XMACCESS,XMVERIFY,XMTRY,XMTMSGS,XMTOCTS,XMV
 | 
|---|
 | 27 |  I '$D(ZTQUEUED) S X=$S($D(^%ZOSF("ERRTN")):^("ERRTN"),1:"ERR^ZU"),@(^%ZOSF("TRAP"))
 | 
|---|
 | 28 |  I '$G(DUZ) S DUZ=.5
 | 
|---|
 | 29 |  I '$D(XMDUZ) S XMDUZ=DUZ
 | 
|---|
 | 30 |  I '$D(XMC("BATCH")) S XMC("BATCH")=0
 | 
|---|
 | 31 |  I $S('$D(XMCHAN):1,XMCHAN="":1,1:0) S XMCHAN="TCP/IP-MAILMAN"
 | 
|---|
 | 32 |  D OPEN^XML
 | 
|---|
 | 33 |  I $G(ER)=1 D ^%ZISC:IO'=$G(IO(0)) W !,"Device open failed !",$C(7) Q
 | 
|---|
 | 34 |  S:'$D(XM) XM=""
 | 
|---|
 | 35 |  I 'XMC("BATCH") X ^%ZOSF("EOFF") S X=255 X ^%ZOSF("RM"),^%ZOSF("TYPE-AHEAD")
 | 
|---|
 | 36 |  S ER=0
 | 
|---|
 | 37 |  S XMK=1
 | 
|---|
 | 38 |  S XMSG="+OK "_^XMB("NETNAME")_" POP3 server ready (Comments to: POSTMASTER@"_^XMB("NETNAME")_")" X XMSEN Q:ER
 | 
|---|
 | 39 |  S XMCMDS("AUTH")="^PASS^QUIT^USER^"
 | 
|---|
 | 40 |  S XMCMDS("TRAN")="^DELE^LIST^NOOP^QUIT^RETR^RSET^STAT^TOP^UIDL^"
 | 
|---|
 | 41 |  S XMSTATE="AUTH"
 | 
|---|
 | 42 |  F  X XMREC Q:ER  D  Q:XMCMD="QUIT"!ER
 | 
|---|
 | 43 |  . I XMRG="" S ER=1,XMCMD="" Q
 | 
|---|
 | 44 |  . S XMCMD=$P(XMRG," ",1)
 | 
|---|
 | 45 |  . I $L(XMCMD)<3!($L(XMCMD)>4)!(XMCMD'?.U) S XMSG="-ERR no such command" X XMSEN Q
 | 
|---|
 | 46 |  . I $T(@XMCMD)'[";;" S XMSG="-ERR no such command" X XMSEN Q
 | 
|---|
 | 47 |  . I XMCMDS(XMSTATE)'[(U_XMCMD_U)="" S XMSG="-ERR no such command in "_XMSTATE_" state" X XMSEN Q
 | 
|---|
 | 48 |  . D @XMCMD
 | 
|---|
 | 49 |  I ER,$G(XMCMD)'="QUIT" D QUIT
 | 
|---|
 | 50 |  Q
 | 
|---|
 | 51 | DELE ;;
 | 
|---|
 | 52 |  N XMID
 | 
|---|
 | 53 |  S XMID=$P(XMRG," ",2,999)
 | 
|---|
 | 54 |  Q:'$$OKID(XMID)
 | 
|---|
 | 55 |  N XMREC,XMZ,XMOCTS
 | 
|---|
 | 56 |  S XMZ=+^TMP("XM",$J,"POP3",XMID),XMOCTS=$P(^(XMID),U,2)
 | 
|---|
 | 57 |  S ^TMP("XM",$J,"POP3","D",XMID)=XMZ
 | 
|---|
 | 58 |  S XMREC=^TMP("XM",$J,"POP3")
 | 
|---|
 | 59 |  S ^TMP("XM",$J,"POP3")=($P(XMREC,U,1)-1)_U_($P(XMREC,U,2)-XMOCTS)
 | 
|---|
 | 60 |  S XMSG="+OK message "_XMID_" deleted" X XMSEN
 | 
|---|
 | 61 |  Q
 | 
|---|
 | 62 | OKID(XMID) ;
 | 
|---|
 | 63 |  I XMID="" S XMSG="-ERR message-id required" X XMSEN Q 0
 | 
|---|
 | 64 |  I +XMID'=XMID S XMSG="-ERR improper message-id" X XMSEN Q 0
 | 
|---|
 | 65 |  I '$D(^TMP("XM",$J,"POP3",XMID)) S XMSG="-ERR no such message" X XMSEN Q 0
 | 
|---|
 | 66 |  I $D(^TMP("XM",$J,"POP3","D",XMID)) S XMSG="-ERR message "_XMID_" already deleted" X XMSEN Q 0
 | 
|---|
 | 67 |  Q 1
 | 
|---|
 | 68 | LIST ;;
 | 
|---|
 | 69 |  N XMID,XMOCTS
 | 
|---|
 | 70 |  S XMID=$P(XMRG," ",2,999)
 | 
|---|
 | 71 |  I XMID="" D  Q
 | 
|---|
 | 72 |  . S XMSG="+OK "_$P(^TMP("XM",$J,"POP3"),U,1)_" messages ("_$P(^("POP3"),U,2)_" octets)" X XMSEN Q:ER
 | 
|---|
 | 73 |  . F  S XMID=$O(^TMP("XM",$J,"POP3",XMID)) Q:'XMID  S XMOCTS=$P(^(XMID),U,2) D  Q:ER
 | 
|---|
 | 74 |  . . Q:$D(^TMP("XM",$J,"POP3","D",XMID))
 | 
|---|
 | 75 |  . . S XMSG=XMID_" "_XMOCTS X XMSEN
 | 
|---|
 | 76 |  . S XMSG="." X XMSEN
 | 
|---|
 | 77 |  Q:'$$OKID(XMID)
 | 
|---|
 | 78 |  S XMSG="+OK "_XMID_" "_$P(^TMP("XM",$J,"POP3",XMID),U,2) X XMSEN
 | 
|---|
 | 79 |  Q
 | 
|---|
 | 80 | NOOP ;;
 | 
|---|
 | 81 |  S XMSG="+OK" X XMSEN
 | 
|---|
 | 82 |  Q
 | 
|---|
 | 83 | PASS ;;
 | 
|---|
 | 84 |  I '$D(XMACCESS) D LOGINERR("-ERR sorry, USER access code expected") Q
 | 
|---|
 | 85 |  S XMVERIFY=$P(XMRG," ",2,999)
 | 
|---|
 | 86 |  I XMVERIFY'="" D LOGIN Q
 | 
|---|
 | 87 |  D LOGINERR("-ERR sorry, PASS verify code expected")
 | 
|---|
 | 88 |  Q
 | 
|---|
 | 89 | LOGIN ;
 | 
|---|
 | 90 |  N XMLOGIN
 | 
|---|
 | 91 |  S XMLOGIN=$$LOGINOK
 | 
|---|
 | 92 |  I 'XMLOGIN D LOGINERR("-ERR "_$P(XMLOGIN,U,2)) Q
 | 
|---|
 | 93 |  K XMACCESS,XMVERIFY
 | 
|---|
 | 94 |  S XMSTATE="TRAN"
 | 
|---|
 | 95 |  S XMDUZ=DUZ
 | 
|---|
 | 96 |  D INIT^XMVVITAE
 | 
|---|
 | 97 |  D MAILDROP
 | 
|---|
 | 98 |  D RSET
 | 
|---|
 | 99 |  Q
 | 
|---|
 | 100 | LOGINOK() ;
 | 
|---|
 | 101 |  I $T(@"USERSET^XUSRA")="" Q $$OLDCHK
 | 
|---|
 | 102 |  Q $$USERSET^XUSRA(XMACCESS_";"_XMVERIFY)
 | 
|---|
 | 103 | OLDCHK() ;
 | 
|---|
 | 104 |  N XUSER,XUF,%1,XMLOGIN
 | 
|---|
 | 105 |  S XUF=0
 | 
|---|
 | 106 |  S XMLOGIN=$$CHECKAV^XUS(XMACCESS_";"_XMVERIFY)
 | 
|---|
 | 107 |  I XMLOGIN S DUZ=XMLOGIN Q 1
 | 
|---|
 | 108 |  Q "0^Not a valid ACCESS CODE/VERIFY CODE pair"
 | 
|---|
 | 109 | MAILDROP ;
 | 
|---|
 | 110 |  N XMKZ,XMZ,XMOCTS,XMID
 | 
|---|
 | 111 |  K ^TMP("XM",$J,"POP3")
 | 
|---|
 | 112 |  S (XMID,XMKZ,XMTOCTS)=0
 | 
|---|
 | 113 |  F  S XMKZ=$O(^XMB(3.7,XMDUZ,2,XMK,1,"C",XMKZ)) Q:'XMKZ  D
 | 
|---|
 | 114 |  . S XMZ=$O(^XMB(3.7,XMDUZ,2,XMK,1,"C",XMKZ,0))
 | 
|---|
 | 115 |  . I '$D(^XMB(3.7,XMDUZ,2,XMK,1,XMZ,0)) D ADDITC^XMUT4A(XMDUZ,XMK,XMZ,XMKZ)
 | 
|---|
 | 116 |  . I '$D(^XMB(3.9,XMZ,0)) D ZAPIT^XMXMSGS2(XMDUZ,XMK,XMZ) Q
 | 
|---|
 | 117 |  . S XMID=XMID+1
 | 
|---|
 | 118 |  . S XMOCTS=$$OCTETS(XMZ)
 | 
|---|
 | 119 |  . S XMTOCTS=XMTOCTS+XMOCTS
 | 
|---|
 | 120 |  . S ^TMP("XM",$J,"POP3",XMID)=XMZ_U_XMOCTS
 | 
|---|
 | 121 |  S XMTMSGS=XMID
 | 
|---|
 | 122 |  Q
 | 
|---|
 | 123 | OCTETS(XMZ) ; Returns the number of 'octets' in a message.
 | 
|---|
 | 124 |  ; Basically, that's a count of the number of characters.
 | 
|---|
 | 125 |  ; We estimate it by multiplying the number of lines by 50.
 | 
|---|
 | 126 |  Q $P($G(^XMB(3.9,XMZ,2,0)),U,4)*50
 | 
|---|
 | 127 | LOGINERR(XMSG) ;
 | 
|---|
 | 128 |  K XMACCESS,XMVERIFY
 | 
|---|
 | 129 |  S XMTRY=$G(XMTRY)+1
 | 
|---|
 | 130 |  I XMTRY<3 X XMSEN Q
 | 
|---|
 | 131 |  D SIGNOFF(XMSG_"; 3 tries and you're out!")
 | 
|---|
 | 132 |  S XMCMD="QUIT"
 | 
|---|
 | 133 |  Q
 | 
|---|
 | 134 | QUIT ;;
 | 
|---|
 | 135 |  I XMSTATE="TRAN",'ER D UPDATE
 | 
|---|
 | 136 |  K ^TMP("XM",$J,"POP3")
 | 
|---|
 | 137 |  D SIGNOFF("")
 | 
|---|
 | 138 |  Q
 | 
|---|
 | 139 | SIGNOFF(XMSG) ;
 | 
|---|
 | 140 |  S XMSG=$S(XMSG'="":XMSG_"; ",ER:"-ERR ",1:"+OK ")_^XMB("NETNAME")_" POP3 server signing off" X XMSEN
 | 
|---|
 | 141 |  Q
 | 
|---|
 | 142 | RETR ;;
 | 
|---|
 | 143 |  N XMID
 | 
|---|
 | 144 |  S XMID=$P(XMRG," ",2,999)
 | 
|---|
 | 145 |  Q:'$$OKID(XMID)
 | 
|---|
 | 146 |  S XMSG="+OK "_$P(^TMP("XM",$J,"POP3",XMID),U,2)_" octets" X XMSEN Q:ER
 | 
|---|
 | 147 |  D RETRIEVE(XMID,"*")
 | 
|---|
 | 148 |  Q
 | 
|---|
 | 149 | RSET ;;
 | 
|---|
 | 150 |  K ^TMP("XM",$J,"POP3","D")
 | 
|---|
 | 151 |  S ^TMP("XM",$J,"POP3")=XMTMSGS_U_XMTOCTS
 | 
|---|
 | 152 |  S XMSG="+OK maildrop has "_XMTMSGS_" messages ("_XMTOCTS_" octets)" X XMSEN
 | 
|---|
 | 153 |  Q
 | 
|---|
 | 154 | STAT ;;
 | 
|---|
 | 155 |  S XMSG="+OK "_$P(^TMP("XM",$J,"POP3"),U,1)_" "_$P(^("POP3"),U,2) X XMSEN
 | 
|---|
 | 156 |  Q
 | 
|---|
 | 157 | TOP ;;
 | 
|---|
 | 158 |  N XMID,XMLINES
 | 
|---|
 | 159 |  S XMID=$P(XMRG," ",2)
 | 
|---|
 | 160 |  Q:'$$OKID(XMID)
 | 
|---|
 | 161 |  S XMLINES=$P(XMRG," ",3,999)
 | 
|---|
 | 162 |  I +XMLINES'=XMLINES S XMSG="-ERR improper number of lines" X XMSEN Q
 | 
|---|
 | 163 |  S XMSG="+OK" X XMSEN Q:ER
 | 
|---|
 | 164 |  D RETRIEVE(XMID,XMLINES)
 | 
|---|
 | 165 |  Q
 | 
|---|
 | 166 | UIDL ;;
 | 
|---|
 | 167 |  N XMID,XMZ
 | 
|---|
 | 168 |  S XMID=$P(XMRG," ",2,999)
 | 
|---|
 | 169 |  I XMID="" D  Q
 | 
|---|
 | 170 |  . S XMSG="+OK" X XMSEN Q:ER
 | 
|---|
 | 171 |  . F  S XMID=$O(^TMP("XM",$J,"POP3",XMID)) Q:'XMID  S XMZ=+^(XMID) D  Q:ER
 | 
|---|
 | 172 |  . . Q:$D(^TMP("XM",$J,"POP3","D",XMID))
 | 
|---|
 | 173 |  . . S XMSG=XMID_" "_XMZ X XMSEN
 | 
|---|
 | 174 |  . S XMSG="." X XMSEN
 | 
|---|
 | 175 |  Q:'$$OKID(XMID)
 | 
|---|
 | 176 |  S XMSG="+OK "_XMID_" "_+^TMP("XM",$J,"POP3",XMID) X XMSEN
 | 
|---|
 | 177 |  Q
 | 
|---|
 | 178 | USER ;;
 | 
|---|
 | 179 |  S XMACCESS=$P(XMRG," ",2,999)
 | 
|---|
 | 180 |  I XMACCESS'="" S XMSG="+OK" X XMSEN Q
 | 
|---|
 | 181 |  D LOGINERR("-ERR sorry, USER access code expected")
 | 
|---|
 | 182 |  Q
 | 
|---|
 | 183 | UPDATE ;
 | 
|---|
 | 184 |  N XMID,XMZ
 | 
|---|
 | 185 |  S XMID=0
 | 
|---|
 | 186 |  F  S XMID=$O(^TMP("XM",$J,"POP3","D",XMID)) Q:'XMID  S XMZ=+^(XMID) D DEL^XMXMSGS2(XMDUZ,"",XMZ)
 | 
|---|
 | 187 |  Q
 | 
|---|
 | 188 | RETRIEVE(XMID,XMLINES) ;
 | 
|---|
 | 189 |  N XMZ,XMRESP,XMIM,XMINSTR,XMIU
 | 
|---|
 | 190 |  S XMZ=+^TMP("XM",$J,"POP3",XMID)
 | 
|---|
 | 191 |  D INMSG^XMXUTIL2(XMDUZ,"",XMZ,"","I",.XMIM,.XMINSTR,.XMIU)
 | 
|---|
 | 192 |  D RETRXMZ(XMZ,XMLINES,.XMIM) Q:ER
 | 
|---|
 | 193 |  I 'XMLINES,XMIM("RESPS") D  Q:ER
 | 
|---|
 | 194 |  . F XMRESP=XMIU("RESP")+1:1:XMIM("RESPS") D  Q:ER
 | 
|---|
 | 195 |  . . N XMIR
 | 
|---|
 | 196 |  . . D INRESP^XMXUTIL2(XMZ,XMRESP,"I",.XMIR) Q:'$D(XMIR)
 | 
|---|
 | 197 |  . . I XMIR("SUBJ")?1"R".N S XMIR("SUBJ")="Re: "_XMIM("SUBJ")
 | 
|---|
 | 198 |  . . S XMSG="" X XMSEN Q:ER  ; just for visual separation
 | 
|---|
 | 199 |  . . D RETRXMZ(XMIR("XMZ"),"*",.XMIR,XMZ) Q:ER
 | 
|---|
 | 200 |  E  S XMRESP=0
 | 
|---|
 | 201 |  S XMSG="." X XMSEN Q:ER
 | 
|---|
 | 202 |  D LASTACC^XMXUTIL(XMDUZ,XMK,XMZ,XMRESP,.XMIM,.XMINSTR,.XMIU)
 | 
|---|
 | 203 |  I $D(^XMB(3.7,XMDUZ,"N0",XMK,XMZ)),+XMRESP=+$P($G(^XMB(3.9,XMZ,3,0)),U,4) D NONEW^XMXUTIL(XMDUZ,XMK,XMZ,1)
 | 
|---|
 | 204 |  Q
 | 
|---|
 | 205 | RETRXMZ(XMZ,XMLINES,XMIM,XMZO) ;
 | 
|---|
 | 206 |  N XMI
 | 
|---|
 | 207 |  I $O(^XMB(3.9,XMZ,2,0))'<1 D CRE8HDR(XMZ,.XMIM,.XMZO) Q:ER
 | 
|---|
 | 208 |  S XMI=0
 | 
|---|
 | 209 |  F  S XMI=$O(^XMB(3.9,XMZ,2,XMI)) Q:'XMI  S XMSG=^(XMI,0) S:$E(XMSG)="." XMSG="."_XMSG X XMSEN Q:ER  I XMLINES,XMI'<XMLINES Q
 | 
|---|
 | 210 |  Q
 | 
|---|
 | 211 | CRE8HDR(XMZ,XMIM,XMZO) ;
 | 
|---|
 | 212 |  S XMSG="Message-ID: <"_XMZ_"@"_^XMB("NETNAME")_">" X XMSEN Q:ER
 | 
|---|
 | 213 |  S XMSG="From: <"_$$NETNAME^XMXUTIL(XMIM("FROM"))_">" X XMSEN Q:ER
 | 
|---|
 | 214 |  S XMSG="To: <"_XMV("NETNAME")_">" X XMSEN Q:ER
 | 
|---|
 | 215 |  S XMSG="Subject: "_XMIM("SUBJ") X XMSEN Q:ER
 | 
|---|
 | 216 |  S XMSG="Date: "_$$INDT^XMXUTIL1(XMIM("DATE")) X XMSEN Q:ER
 | 
|---|
 | 217 |  S XMSG="" X XMSEN Q:ER
 | 
|---|
 | 218 |  Q
 | 
|---|