Skip to contentPackage: IMAPAddress
IMAPAddress
Coverage
1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.eclipse.angus.mail.imap.protocol;
18:
19: import java.util.List;
20: import java.util.ArrayList;
21: import java.util.Date;
22: import java.text.ParseException;
23: import jakarta.mail.internet.InternetAddress;
24: import jakarta.mail.internet.AddressException;
25: import jakarta.mail.internet.MailDateFormat;
26:
27: import org.eclipse.angus.mail.iap.*;
28: import org.eclipse.angus.mail.util.PropUtil;
29: import org.eclipse.angus.mail.iap.ParsingException;
30: import org.eclipse.angus.mail.iap.Response;
31:
32: /**
33: * The ENEVELOPE item of an IMAP FETCH response.
34: *
35: * @author John Mani
36: * @author Bill Shannon
37: */
38:
39: public class ENVELOPE implements Item {
40:
41: // IMAP item name
42: static final char[] name = {'E','N','V','E','L','O','P','E'};
43: public int msgno;
44:
45: public Date date = null;
46: public String subject;
47: public InternetAddress[] from;
48: public InternetAddress[] sender;
49: public InternetAddress[] replyTo;
50: public InternetAddress[] to;
51: public InternetAddress[] cc;
52: public InternetAddress[] bcc;
53: public String inReplyTo;
54: public String messageId;
55:
56: // Used to parse dates
57: private static final MailDateFormat mailDateFormat = new MailDateFormat();
58:
59: // special debugging output to debug parsing errors
60: private static final boolean parseDebug =
61:         PropUtil.getBooleanSystemProperty("mail.imap.parse.debug", false);
62:
63: public ENVELOPE(FetchResponse r) throws ParsingException {
64:         if (parseDebug)
65:          System.out.println("parse ENVELOPE");
66:         msgno = r.getNumber();
67:
68:         r.skipSpaces();
69:
70:         if (r.readByte() != '(')
71:          throw new ParsingException("ENVELOPE parse error");
72:         
73:         String s = r.readString();
74:         if (s != null) {
75:          try {
76: synchronized (mailDateFormat) {
77: date = mailDateFormat.parse(s);
78: }
79:          } catch (ParseException pex) {
80:          }
81:         }
82:         if (parseDebug)
83:          System.out.println(" Date: " + date);
84:
85:         subject = r.readString();
86:         if (parseDebug)
87:          System.out.println(" Subject: " + subject);
88:         if (parseDebug)
89:          System.out.println(" From addresses:");
90:         from = parseAddressList(r);
91:         if (parseDebug)
92:          System.out.println(" Sender addresses:");
93:         sender = parseAddressList(r);
94:         if (parseDebug)
95:          System.out.println(" Reply-To addresses:");
96:         replyTo = parseAddressList(r);
97:         if (parseDebug)
98:          System.out.println(" To addresses:");
99:         to = parseAddressList(r);
100:         if (parseDebug)
101:          System.out.println(" Cc addresses:");
102:         cc = parseAddressList(r);
103:         if (parseDebug)
104:          System.out.println(" Bcc addresses:");
105:         bcc = parseAddressList(r);
106:         inReplyTo = r.readString();
107:         if (parseDebug)
108:          System.out.println(" In-Reply-To: " + inReplyTo);
109:         messageId = r.readString();
110:         if (parseDebug)
111:          System.out.println(" Message-ID: " + messageId);
112:
113:         if (!r.isNextNonSpace(')'))
114:          throw new ParsingException("ENVELOPE parse error");
115: }
116:
117: private InternetAddress[] parseAddressList(Response r)
118:                 throws ParsingException {
119:         r.skipSpaces(); // skip leading spaces
120:
121:         byte b = r.readByte();
122:         if (b == '(') {
123:          /*
124:          * Some broken servers (e.g., Yahoo Mail) return an empty
125:          * list instead of NIL. Handle that here even though it
126:          * doesn't conform to the IMAP spec.
127:          */
128:          if (r.isNextNonSpace(')'))
129:                 return null;
130:
131:          List<InternetAddress> v = new ArrayList<>();
132:
133:          do {
134:                 IMAPAddress a = new IMAPAddress(r);
135:                 if (parseDebug)
136:                  System.out.println(" Address: " + a);
137:                 // if we see an end-of-group address at the top, ignore it
138:                 if (!a.isEndOfGroup())
139:                  v.add(a);
140:          } while (!r.isNextNonSpace(')'));
141:
142:          return v.toArray(new InternetAddress[v.size()]);
143:         } else if (b == 'N' || b == 'n') { // NIL
144:          r.skip(2); // skip 'NIL'
145:          return null;
146:         } else
147:          throw new ParsingException("ADDRESS parse error");
148: }
149: }
150:
151: class IMAPAddress extends InternetAddress {
152: private boolean group = false;
153: private InternetAddress[] grouplist;
154: private String groupname;
155:
156: private static final long serialVersionUID = -3835822029483122232L;
157:
158: IMAPAddress(Response r) throws ParsingException {
159: r.skipSpaces(); // skip leading spaces
160:
161:• if (r.readByte() != '(')
162: throw new ParsingException("ADDRESS parse error");
163:
164: encodedPersonal = r.readString();
165:
166: r.readString(); // throw away address_list
167:         String mb = r.readString();
168:         String host = r.readString();
169:         // skip bogus spaces inserted by Yahoo IMAP server if
170:         // "undisclosed-recipients" is a recipient
171:         r.skipSpaces();
172:•        if (!r.isNextNonSpace(')')) // skip past terminating ')'
173: throw new ParsingException("ADDRESS parse error");
174:
175:•        if (host == null) {
176:          // it's a group list, start or end
177:          group = true;
178:          groupname = mb;
179:•         if (groupname == null)        // end of group list
180:                 return;
181:          // Accumulate a group list. The members of the group
182:          // are accumulated in a List and the corresponding string
183:          // representation of the group is accumulated in a StringBuilder.
184:          StringBuilder sb = new StringBuilder();
185:          sb.append(groupname).append(':');
186:          List<InternetAddress> v = new ArrayList<>();
187:•         while (r.peekByte() != ')') {
188:                 IMAPAddress a = new IMAPAddress(r);
189:•                if (a.isEndOfGroup())        // reached end of group
190:                  break;
191:•                if (v.size() != 0)        // if not first element, need a comma
192:                  sb.append(',');
193:                 sb.append(a.toString());
194:                 v.add(a);
195:          }
196:          sb.append(';');
197:          address = sb.toString();
198:          grouplist = v.toArray(new IMAPAddress[v.size()]);
199:         } else {
200:•         if (mb == null || mb.length() == 0)
201:                 address = host;
202:•         else if (host.length() == 0)
203:                 address = mb;
204:          else
205:                 address = mb + "@" + host;
206:         }
207:
208: }
209:
210: boolean isEndOfGroup() {
211:•        return group && groupname == null;
212: }
213:
214: @Override
215: public boolean isGroup() {
216:         return group;
217: }
218:
219: @Override
220: public InternetAddress[] getGroup(boolean strict) throws AddressException {
221:•        if (grouplist == null)
222:          return null;
223:         return grouplist.clone();
224: }
225: }