View Javadoc

1   /*
2    * Copyright (c) 2004-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.mercury.smtp;
14  
15  import java.io.EOFException;
16  import java.io.IOException;
17  import java.io.InputStream;
18  
19  import org.abstracthorizon.mercury.smtp.exception.ParserException;
20  import org.abstracthorizon.mercury.smtp.util.Path;
21  
22  /**
23   * A class implementing a lexical scanner for an IMAP server.
24   *
25   * @author Daniel Sendula
26   */
27  public class SMTPScanner {
28  
29      /** Input stream */
30      protected InputStream in;
31  
32      /** Buffer */
33      protected char[] buffer;
34  
35      /** Current literal */
36      protected boolean literal;
37  
38      /** Current pointer */
39      protected int ptr = -1;
40  
41      /** END OF LINE is recognised */
42      protected boolean eol = false;
43  
44      /**
45       * Constructor
46       * @param in input stream
47       */
48      public SMTPScanner(InputStream in) {
49          this.in = in;
50          in.mark(128);
51      }
52  
53      /**
54       * Resets EOL indicator
55       */
56      public void resetEOL() {
57          eol = false;
58      }
59  
60      protected boolean atom_char(char c) {
61          if ((c >= 31) && (c != '(') && (c != ')') && (c != '{') && (c != ' ') && (c != '%') && (c != '*') && (c != '"') && (c != ']') && (c != '\\') && (c != '.') && (c != '>') && (c != '@')) { return true; }
62          return false;
63      }
64  
65      protected boolean astring_char(char c) {
66          if (atom_char(c) || (c == ']')) { return true; }
67          return false;
68      }
69  
70      protected boolean text_char(char c) {
71          if ((c != '\r') && (c != '\n')) { return true; }
72          return false;
73      }
74  
75      protected boolean digit_nz(char c) {
76          return (c >= '1') && (c <= '9');
77      }
78  
79      protected boolean digit(char c) {
80          return (c >= '0') && (c <= '9');
81      }
82  
83      protected boolean list_char(char c) {
84          return atom_char(c) || (c == '%') || (c == '*') || (c == ']');
85      }
86  
87      protected boolean alfa(char c) {
88          return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
89      }
90  
91      protected boolean alfa_digit(char c) {
92          return alfa(c) || digit(c);
93      }
94  
95      protected boolean ldh(char c) {
96          return ((c == '-') || alfa(c) || digit(c));
97      }
98  
99      public char readChar() throws IOException {
100         int i = in.read();
101         if (i >= 0) {
102             return (char)i;
103         }
104         throw new EOFException();
105     }
106 
107     public void skip_line() throws IOException {
108         if (eol) {
109             eol = false;
110             return;
111         }
112         char c = readChar();
113         while (true) {
114             while (c != '\r') {
115                 c = readChar();
116             } // while
117             c = readChar();
118             if (c == '\n') {
119                 eol = true;
120                 return;
121             }
122         } // while
123     }
124 
125     public void check_eol() throws IOException, ParserException {
126         char c = readChar();
127         if (c != '\r') { throw new ParserException("<CR>"); }
128         c = readChar();
129         if (c != '\n') { throw new ParserException("<LF>"); }
130         eol = true;
131     }
132 
133     public boolean is_char(char r) throws IOException {
134         in.mark(1);
135         char c = readChar();
136         if (c == r) { return true; }
137         in.reset();
138         return false;
139     }
140 
141     public boolean peek_char(char r) throws IOException {
142         in.mark(1);
143         char c = readChar();
144         in.reset();
145         if (c == r) { return true; }
146         return false;
147     }
148 
149     public boolean number(Number num) throws IOException {
150         in.mark(10);
151         int len = 0;
152         num.number = 0;
153         char c = readChar();
154         if ((c < '0') && (c > '9')) {
155             in.reset();
156             return false;
157         }
158         num.number = num.number * 10 + (c - '0');
159         len = len + 1;
160         c = readChar();
161         while ((c >= '0') && (c <= '9')) {
162             num.number = num.number * 10 + (c - '0');
163             len = len + 1;
164             c = readChar();
165         } // while
166         in.reset();
167         in.skip(len);
168         return true;
169     }
170 
171     public boolean nz_number(Number num) throws IOException {
172         in.mark(10);
173         int len = 0;
174         num.number = 0;
175         char c = readChar();
176         if ((c < '1') || (c > '9')) {
177             in.reset();
178             return false;
179         }
180         num.number = num.number * 10 + (c - '0');
181         len = len + 1;
182         c = readChar();
183         while ((c >= '0') && (c <= '9')) {
184             num.number = num.number * 10 + (c - '0');
185             len = len + 1;
186             c = readChar();
187         } // while
188         in.reset();
189         in.skip(len);
190         return true;
191     }
192 
193     public boolean keyword(String keyword) throws IOException {
194         in.mark(keyword.length() + 1);
195         ptr = 0;
196         while (ptr < keyword.length()) {
197             char c = readChar();
198             if (Character.toUpperCase(c) != Character.toUpperCase(keyword.charAt(ptr))) {
199                 in.reset();
200 
201                 return false;
202             }
203             ptr = ptr + 1;
204         } // while
205         return true;
206     }
207 
208     public boolean quoted(StringBuffer quoted) throws IOException, ParserException {
209         in.mark(512);
210         char c = readChar();
211         if (c != '"') {
212             in.reset();
213             return false;
214         }
215         c = readChar();
216         while (text_char(c) && (c != '"')) {
217             if (c == '\\') {
218                 c = readChar();
219                 if ((c == '\\') || (c == '"')) {
220                     quoted.append(c);
221                 } else {
222                     in.reset();
223                     throw new ParserException("'" + c + "'");
224                 }
225             } else {
226                 quoted.append(c);
227             }
228             c = readChar();
229         } // while
230         if (c != '"') {
231             in.reset();
232             throw new ParserException("'\"'");
233         }
234         return true;
235     }
236 
237     public boolean atom(StringBuffer buffer) throws IOException, ParserException {
238         in.mark(128);
239         char c = readChar();
240         if (!atom_char(c)) {
241             in.reset();
242             return false;
243         }
244         buffer.append(c);
245         c = readChar();
246         while (atom_char(c)) {
247             buffer.append(c);
248             c = readChar();
249         }
250         in.reset();
251         in.skip(buffer.length());
252         return true;
253     }
254 
255     public boolean ldhStr(StringBuffer buffer) throws IOException, ParserException {
256         in.mark(128);
257         char c = readChar();
258         char l = c;
259         if (!alfa_digit(c)) {
260             in.reset();
261             return false;
262         }
263         buffer.append(c);
264         l = c;
265         c = readChar();
266         while (ldh(c)) {
267             buffer.append(c);
268             l = c;
269             c = readChar();
270         }
271         if (!alfa_digit(l)) { throw new ParserException("alfa-digit"); }
272         in.reset();
273         in.skip(buffer.length());
274         return true;
275     }
276 
277     public boolean path(Path path) throws IOException, ParserException {
278         char c = readChar();
279         if (c != '<') {
280             in.reset();
281             return false;
282         }
283         StringBuffer domain = new StringBuffer();
284         if (atDomain(domain)) {
285             path.addReturnPath(domain.toString());
286             domain.delete(0, domain.length());
287             c = readChar();
288             while (c == ',') {
289                 if (!atDomain(domain)) {
290                     in.reset();
291                     throw new ParserException("atDomain");
292                 }
293                 path.addReturnPath(domain.toString());
294                 domain.delete(0, domain.length());
295                 c = readChar();
296             }
297             if (c != ':') {
298                 in.reset();
299                 throw new ParserException(":");
300             }
301         }
302         StringBuffer local = new StringBuffer();
303         if (!localPart(local)) {
304             in.reset();
305             throw new ParserException("local-part");
306         }
307         path.setMailbox(local.toString());
308         if (!atDomain(domain)) {
309             in.reset();
310             throw new ParserException("atDomain");
311         }
312         path.setDomain(domain.toString());
313         if (!is_char('>')) { throw new ParserException(">"); }
314         return true;
315     }
316 
317     public boolean atDomain(StringBuffer domain) throws IOException, ParserException {
318         in.mark(1);
319         char c = readChar();
320         if (c != '@') {
321             in.reset();
322             return false;
323         }
324         return domain(domain);
325     }
326 
327     public boolean domain(StringBuffer domain) throws IOException, ParserException {
328         if (!ldhStr(domain)) { return false; }
329         in.mark(1);
330         char c = readChar();
331         while (c == '.') {
332             domain.append(c);
333             StringBuffer sd = new StringBuffer();
334             if (!ldhStr(sd)) { throw new ParserException("ldhStr"); }
335             domain.append(sd);
336             sd.delete(0, sd.length());
337             in.mark(1);
338             c = readChar();
339         }
340         in.reset();
341         return true;
342     }
343 
344     public boolean localPart(StringBuffer buffer) throws IOException, ParserException {
345         if (quoted(buffer)) { return true; }
346         if (!atom(buffer)) { return false; }
347         in.mark(1);
348         char c = readChar();
349         while (c == '.') {
350             buffer.append(c);
351             StringBuffer p = new StringBuffer();
352             if (!atom(p)) { throw new ParserException("atom"); }
353             buffer.append(p);
354             in.mark(1);
355             c = readChar();
356         }
357         in.reset();
358         return true;
359     }
360 
361     public static class Number {
362 
363         public int number = 0;
364     }
365 
366 }