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
|
---|