001 /*
002 * EmailDocumentHandler.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Cristian URSU, 3/Aug/2000
013 *
014 * $Id: EmailDocumentHandler.java 13531 2011-03-15 08:15:21Z markagreenwood $
015 */
016
017 package gate.email;
018
019 import gate.Factory;
020 import gate.FeatureMap;
021 import gate.GateConstants;
022 import gate.event.StatusListener;
023
024 import java.io.BufferedReader;
025 import java.io.IOException;
026 import java.io.StringReader;
027 import java.util.Collection;
028 import java.util.HashSet;
029 import java.util.Iterator;
030 import java.util.LinkedList;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.StringTokenizer;
034
035 import junit.framework.Assert;
036
037 /**
038 * This class implements the behaviour of the Email reader
039 * It takes the Gate Document representing a list with e-mails and
040 * creates Gate annotations on it.
041 */
042 public class EmailDocumentHandler {
043
044 /** Debug flag */
045 private static final boolean DEBUG = false;
046
047 private String content = null;
048 private long documentSize = 0;
049
050 /**
051 * Constructor used in tests mostly
052 */
053 public EmailDocumentHandler() {
054 setUp();
055 }//EmailDocumentHandler
056
057 /**
058 * Constructor initialises some private fields
059 */
060 public EmailDocumentHandler( gate.Document aGateDocument,
061 Map aMarkupElementsMap,
062 Map anElement2StringMap
063 ) {
064
065 gateDocument = aGateDocument;
066
067 // gets AnnotationSet based on the new gate document
068 if (basicAS == null)
069 basicAS = gateDocument.getAnnotations(
070 GateConstants.ORIGINAL_MARKUPS_ANNOT_SET_NAME);
071
072 markupElementsMap = aMarkupElementsMap;
073 element2StringMap = anElement2StringMap;
074 setUp();
075 }// EmailDocumentHandler
076
077 /**
078 * Reads the Gate Document line by line and does the folowing things:
079 * <ul>
080 * <li> Each line is analized in order to detect where an e-mail starts.
081 * <li> If the line belongs to an e-mail header then creates the
082 * annotation if the markupElementsMap allows that.
083 * <li> Lines belonging to the e-mail body are placed under a Gate
084 * annotation called messageBody.
085 * </ul>
086 */
087 public void annotateMessages() throws IOException,
088 gate.util.InvalidOffsetException {
089 // obtain a BufferedReader form the Gate document...
090 BufferedReader gateDocumentReader = null;
091 // Get the string representing the content of the document
092 // It is used inside CreateAnnotation method
093 content = gateDocument.getContent().toString();
094 // Get the sieze of the Gate Document. For the same purpose.
095 documentSize = gateDocument.getContent().size().longValue();
096
097 // gateDocumentReader = new BufferedReader(new InputStreamReader(
098 // gateDocument.getSourceUrl().openConnection().getInputStream()));
099 gateDocumentReader = new BufferedReader(new StringReader(content));
100
101 // for each line read from the gateDocumentReader do
102 // if the line begins an e-mail message then fire a status listener, mark
103 // that we are processing an e-mail, update the cursor and go to the next
104 // line.
105
106 // if we are inside an e-mail, test if the line belongs to the message
107 // header
108 // if so, create a header field annotation.
109
110 // if we are inside a a body and this is the first line from the body,
111 // create the message body annotation.
112 // Otherwise just update the cursor and go to the next line
113
114 // if the line doesn't belong to an e-mail message then just update the
115 // cursor.
116 // next line
117
118 String line = null;
119 String aFieldName = null;
120
121 long cursor = 0;
122 long endEmail = 0;
123 long startEmail = 0;
124 long endHeader = 0;
125 long startHeader = 0;
126 long endBody = 0;
127 long startBody = 0;
128 long endField = 0;
129 long startField = 0;
130
131 boolean insideAnEmail = false;
132 boolean insideHeader = false;
133 boolean insideBody = false;
134 boolean emailReadBefore = false;
135 boolean fieldReadBefore = false;
136
137 long nlSize = detectNLSize();
138
139 //Out.println("NL SIZE = " + nlSize);
140
141 // read each line from the reader
142 while ((line = gateDocumentReader.readLine()) != null){
143 // Here we test if the line delimitates two e-mail messages.
144 // Each e-mail message begins with a line like this:
145 // From P.Fairhurst Thu Apr 18 12:22:23 1996
146 // Method lineBeginsMessage() detects such lines.
147 if (lineBeginsMessage(line)){
148 // Inform the status listener to fire only
149 // if no. of elements processed.
150 // So far is a multiple of ELEMENTS_RATE
151 if ((++ emails % EMAILS_RATE) == 0)
152 fireStatusChangedEvent("Reading emails : " + emails);
153 // if there are e-mails read before, then the previous e-mail
154 // ends here.
155 if (true == emailReadBefore){
156 // Cursor points at the beggining of the line
157 // E-mail and Body ends before the \n char
158 // Email ends as cursor value indicates
159 endEmail = cursor - nlSize ;
160 // also the e-mail body ends when an e-mail ends
161 endBody = cursor - nlSize;
162 //Annotate an E-mail body (startBody, endEmail)
163 createAnnotation("Body",startBody,endBody,null);
164 //Annotate an E-mail message(startEmail, endEmail) Email starts
165 createAnnotation("Message",startEmail,endEmail,null);
166 }
167 // if no e-mail was read before, now there is at list one message
168 // read
169 emailReadBefore = true;
170 // E-mail starts imediately from the beginning of this line which
171 // sepatates 2 messages.
172 startEmail = cursor;
173 // E-mail header starts also from here
174 startHeader = cursor;
175 // The cursor is updated with the length of the line + the
176 // new line char
177 cursor += line.length() + nlSize;
178 // We are inside an e-mail
179 insideAnEmail = true;
180 // Next is the E-mail header
181 insideHeader = true;
182 // No field inside header has been read before
183 fieldReadBefore = false;
184 // Read the next line
185 continue;
186 }//if (lineBeginsMessage(line))
187 if (false == insideAnEmail){
188 // the cursor is update with the length of the line +
189 // the new line char
190 cursor += line.length() + nlSize;
191 // read the next line
192 continue;
193 }//if
194 // here we are inside an e-mail message (inside Header or Body)
195 if (true == insideHeader){
196 // E-mail spec sais that E-mail header is separated by E-mail body
197 // by a \n char
198 if (line.equals("")){
199 // this \n sepatates the header of an e-mail form its body
200 // If we are here it means that the header has ended.
201 insideHeader = false;
202 // e-mail header ends here
203 endHeader = cursor - nlSize;
204 // update the cursor with the length of \n
205 cursor += line.length() + nlSize;
206 // E-mail body starts from here
207 startBody = cursor;
208 // if fields were read before, it means that the e-mail has a header
209 if (true == fieldReadBefore){
210 endField = endHeader;
211 //Create a field annotation (fieldName, startField, endField)
212 createAnnotation(aFieldName, startField, endField, null);
213 //Create an e-mail header annotation
214 createAnnotation("Header",startHeader,endHeader,null);
215 }//if
216 // read the next line
217 continue;
218 }//if (line.equals(""))
219 // if line begins with a field then prepare to create an
220 // annotation with the name of the field
221 if (lineBeginsWithField(line)){
222 // if a field was read before, it means that the previous field ends
223 // here
224 if (true == fieldReadBefore){
225 // the previous field end here
226 endField = cursor - nlSize;
227 //Create a field annotation (fieldName, startField, endField)
228 createAnnotation(aFieldName, startField, endField, null);
229 }//if
230 fieldReadBefore = true;
231 aFieldName = getFieldName();
232 startField = cursor + aFieldName.length() + ":".length();
233 }//if
234 // in both cases the cursor is updated and read the next line
235 // the cursor is update with the length of the line +
236 // the new line char
237 cursor += line.length() + nlSize;
238 // read the next line
239 continue;
240 }//if (true == insideHeader)
241 // here we are inside the E-mail body
242 // the body will end when the e-mail will end.
243 // here we just update the cursor
244 cursor += line.length() + nlSize;
245 }//while
246 // it might be possible that the file to contain only one e-mail and
247 // if the file contains only one e-mail message then the variable
248 // emailReadBefore must be set on true value
249 if (true == emailReadBefore){
250 endBody = cursor - nlSize;
251 endEmail = cursor - nlSize;
252 //Annotate an E-mail body (startBody, endEmail)
253 createAnnotation("Body",startBody,endBody,null);
254 //Annotate an E-mail message(startEmail, endEmail) Email starts
255 createAnnotation("Message",startEmail,endEmail,null);
256 }
257 // if emailReadBefore is not set on true, that means that we didn't
258 // encounter any line like this:
259 // From P.Fairhurst Thu Apr 18 12:22:23 1996
260 }//annotateMessages
261
262 /**
263 * This method detects if the text file which contains e-mail messages
264 * is under MSDOS or UNIX format.
265 * Under MSDOS the size of NL is 2 (\n \r) and under UNIX (\n) the size is 1
266 * @return the size of the NL (1,2 or 0 = if no \n is found)
267 */
268 private int detectNLSize() {
269
270 // get a char array
271 char[] document = null;
272
273 // transform the gate Document into a char array
274 document = gateDocument.getContent().toString().toCharArray();
275
276 // search for the \n char
277 // when it is found test if is followed by the \r char
278 for (int i=0; i<document.length; i++){
279 if (document[i] == '\n'){
280
281 // we just found a \n char.
282 // here we test if is followed by a \r char or preceded by a \r char
283 if (
284 (((i+1) < document.length) && (document[i+1] == '\r'))
285 ||
286 (((i-1) >= 0) && (document[i-1] == '\r'))
287 ) return 2;
288 else return 1;
289 }
290 }
291 //if no \n char is found then the document is contained into a single text
292 // line.
293 return 0;
294
295 } // detectNLSize
296
297 /**
298 * This method creates a gate annotation given its name, start, end and
299 * feature map.
300 */
301 private void createAnnotation(String anAnnotationName, long anAnnotationStart,
302 long anAnnotationEnd, FeatureMap aFeatureMap)
303 throws gate.util.InvalidOffsetException{
304
305 /*
306 while (Character.isWhitespace(content.charAt((int) anAnnotationStart)))
307 anAnnotationStart ++;
308
309 // System.out.println(content.charAt((int) anAnnotationEnd));
310 while (Character.isWhitespace(content.charAt((int) anAnnotationEnd)))
311 anAnnotationEnd --;
312
313 anAnnotationEnd ++;
314 */
315 if (canCreateAnnotation(anAnnotationStart,anAnnotationEnd,documentSize)){
316 if (aFeatureMap == null)
317 aFeatureMap = Factory.newFeatureMap();
318 basicAS.add( new Long(anAnnotationStart),
319 new Long(anAnnotationEnd),
320 anAnnotationName.toLowerCase(),
321 aFeatureMap);
322 }// End if
323 }//createAnnotation
324 /**
325 * This method verifies if an Annotation can be created.
326 */
327 private boolean canCreateAnnotation(long start,
328 long end,
329 long gateDocumentSize){
330
331 if (start < 0 || end < 0 ) return false;
332 if (start > end ) return false;
333 if ((start > gateDocumentSize) || (end > gateDocumentSize)) return false;
334 return true;
335 }// canCreateAnnotation
336
337 /**
338 * Tests if the line begins an e-mail message
339 * @param aTextLine a line from the file containing the e-mail messages
340 * @return true if the line begins an e-mail message
341 * @return false if is doesn't
342 */
343 private boolean lineBeginsMessage(String aTextLine){
344 int score = 0;
345
346 // if first token is "From" and the rest contains Day, Zone, etc
347 // then this line begins a message
348 // create a new String Tokenizer with " " as separator
349 StringTokenizer tokenizer = new StringTokenizer(aTextLine," ");
350
351 // get the first token
352 String firstToken = null;
353 if (tokenizer.hasMoreTokens())
354 firstToken = tokenizer.nextToken();
355 else return false;
356
357 // trim it
358 firstToken = firstToken.trim();
359
360 // check against "From" word
361 // if the first token is not From then the entire line can not begin
362 // a message.
363 if (!firstToken.equals("From"))
364 return false;
365
366 // else continue the analize
367 while (tokenizer.hasMoreTokens()){
368
369 // get the next token
370 String token = tokenizer.nextToken();
371 token = token.trim();
372
373 // see if it has a meaning(analize if is a Day, Month,Zone, Time, Year )
374 if (hasAMeaning(token))
375 score += 1;
376 }
377
378 // a score greather or equql with 5 means that this line begins a message
379 if (score >= 5) return true;
380 else return false;
381
382 } // lineBeginsMessage
383
384 /**
385 * Tests if the line begins with a field from the e-mail header
386 * If the answer is true then it also sets the member fieldName with the
387 * value of this e-mail header field.
388 * @param aTextLine a line from the file containing the e-mail text
389 * @return true if the line begins with a field from the e-mail header
390 * @return false if is doesn't
391 */
392 private boolean lineBeginsWithField(String aTextLine){
393 if (containsSemicolon(aTextLine)){
394 StringTokenizer tokenizer = new StringTokenizer(aTextLine,":");
395
396 // get the first token
397 String firstToken = null;
398
399 if (tokenizer.hasMoreTokens())
400 firstToken = tokenizer.nextToken();
401 else return false;
402
403 if (firstToken != null){
404 // trim it
405 firstToken = firstToken.trim();
406 if (containsWhiteSpaces(firstToken)) return false;
407
408 // set the member field
409 fieldName = firstToken;
410 }
411 return true;
412 } else return false;
413
414 } // lineBeginsWithField
415
416 /**
417 * This method checks if a String contains white spaces.
418 */
419 private boolean containsWhiteSpaces(String aString) {
420 for (int i = 0; i<aString.length(); i++)
421 if (Character.isWhitespace(aString.charAt(i))) return true;
422 return false;
423 } // containsWhiteSpaces
424
425 /**
426 * This method checks if a String contains a semicolon char
427 */
428 private boolean containsSemicolon(String aString) {
429 for (int i = 0; i<aString.length(); i++)
430 if (aString.charAt(i) == ':') return true;
431 return false;
432 } // containsSemicolon
433
434 /**
435 * This method tests a token if is Day, Month, Zone, Time, Year
436 */
437 private boolean hasAMeaning(String aToken) {
438 // if token is a Day return true
439 if (day.contains(aToken)) return true;
440
441 // if token is a Month return true
442 if (month.contains(aToken)) return true;
443
444 // if token is a Zone then return true
445 if (zone.contains(aToken)) return true;
446
447 // test if is a day number or a year
448 Integer dayNumberOrYear = null;
449 try{
450 dayNumberOrYear = new Integer(aToken);
451 } catch (NumberFormatException e){
452 dayNumberOrYear = null;
453 }
454
455 // if the creation succeded, then test if is day or year
456 if (dayNumberOrYear != null) {
457 int number = dayNumberOrYear.intValue();
458
459 // if is a number between 1 and 31 then is a day
460 if ((number > 0) && (number < 32)) return true;
461
462 // if is a number between 1900 si 3000 then is a year ;))
463 if ((number > 1900) && (number < 3000)) return true;
464
465 // it might be the last two digits of 19xx
466 if ((number >= 0) && (number <= 99)) return true;
467 }
468 // test if is time: hh:mm:ss
469 if (isTime(aToken)) return true;
470
471 return false;
472 } // hasAMeaning
473
474 /**
475 * Tests a token if is in time format HH:MM:SS
476 */
477 private boolean isTime(String aToken) {
478 StringTokenizer st = new StringTokenizer(aToken,":");
479
480 // test each token if is hour, minute or second
481 String hourString = null;
482 if (st.hasMoreTokens())
483 hourString = st.nextToken();
484
485 // if there are no more tokens, it means that is not a time
486 if (hourString == null) return false;
487
488 // test if is a number between 0 and 23
489 Integer hourInteger = null;
490 try{
491 hourInteger = new Integer(hourString);
492 } catch (NumberFormatException e){
493 hourInteger = null;
494 }
495 if (hourInteger == null) return false;
496
497 // if is not null then it means is a number
498 // test if is in 0 - 23 range
499 // if is not in this range then is not an hour
500 int hour = hourInteger.intValue();
501 if ( (hour < 0) || (hour > 23) ) return false;
502
503 // we have the hour
504 // now repeat the test for minute and seconds
505
506 // minutes
507 String minutesString = null;
508 if (st.hasMoreTokens())
509 minutesString = st.nextToken();
510
511 // if there are no more tokens (minutesString == null) then return false
512 if (minutesString == null) return false;
513
514 // test if is a number between 0 and 59
515 Integer minutesInteger = null;
516 try {
517 minutesInteger = new Integer (minutesString);
518 } catch (NumberFormatException e){
519 minutesInteger = null;
520 }
521
522 if (minutesInteger == null) return false;
523
524 // if is not null then it means is a number
525 // test if is in 0 - 59 range
526 // if is not in this range then is not a minute
527 int minutes = minutesInteger.intValue();
528 if ( (minutes < 0) || (minutes > 59) ) return false;
529
530 // seconds
531 String secondsString = null;
532 if (st.hasMoreTokens())
533 secondsString = st.nextToken();
534
535 // if there are no more tokens (secondsString == null) then return false
536 if (secondsString == null) return false;
537
538 // test if is a number between 0 and 59
539 Integer secondsInteger = null;
540 try {
541 secondsInteger = new Integer (secondsString);
542 } catch (NumberFormatException e){
543 secondsInteger = null;
544 }
545 if (secondsInteger == null) return false;
546
547 // if is not null then it means is a number
548 // test if is in 0 - 59 range
549 // if is not in this range then is not a minute
550 int seconds = secondsInteger.intValue();
551 if ( (seconds < 0) || (seconds > 59) ) return false;
552
553 // if there are more tokens in st it means that we don't have this format:
554 // HH:MM:SS
555 if (st.hasMoreTokens()) return false;
556
557 // if we are here it means we have a time
558 return true;
559 }// isTime
560
561 /**
562 * Initialises the collections with data used by method lineBeginsMessage()
563 */
564 private void setUp(){
565 day = new HashSet();
566 day.add("Mon");
567 day.add("Tue");
568 day.add("Wed");
569 day.add("Thu");
570 day.add("Fri");
571 day.add("Sat");
572 day.add("Sun");
573
574 month = new HashSet();
575 month.add("Jan");
576 month.add("Feb");
577 month.add("Mar");
578 month.add("Apr");
579 month.add("May");
580 month.add("Jun");
581 month.add("Jul");
582 month.add("Aug");
583 month.add("Sep");
584 month.add("Oct");
585 month.add("Nov");
586 month.add("Dec");
587
588 zone = new HashSet();
589 zone.add("UT");
590 zone.add("GMT");
591 zone.add("EST");
592 zone.add("EDT");
593 zone.add("CST");
594 zone.add("CDT");
595 zone.add("MST");
596 zone.add("MDT");
597 zone.add("PST");
598 zone.add("PDT");
599 }//setUp
600
601 /**
602 * This method returns the value of the member fieldName.
603 * fieldName is set by the method lineBeginsWithField(String line).
604 * Each time the the line begins with a field name, that fiels will be stored
605 * in this member.
606 */
607 private String getFieldName() {
608 if (fieldName == null) return new String("");
609 else return fieldName;
610 } // getFieldName
611
612 // StatusReporter Implementation
613
614 /**
615 * This methos is called when a listener is registered with this class
616 */
617 public void addStatusListener(StatusListener listener){
618 myStatusListeners.add(listener);
619 }
620 /**
621 * This methos is called when a listener is removed
622 */
623 public void removeStatusListener(StatusListener listener){
624 myStatusListeners.remove(listener);
625 }
626
627 /**
628 * This methos is called whenever we need to inform the listener
629 * about an event.
630 */
631 protected void fireStatusChangedEvent(String text){
632 Iterator listenersIter = myStatusListeners.iterator();
633 while(listenersIter.hasNext())
634 ((StatusListener)listenersIter.next()).statusChanged(text);
635 }
636
637 private static final int EMAILS_RATE = 16;
638
639 // the content of the e-mail document, without any tag
640 // for internal use
641 private String tmpDocContent = null;
642
643 // a gate document
644 private gate.Document gateDocument = null;
645
646 // an annotation set used for creating annotation reffering the doc
647 private gate.AnnotationSet basicAS = null;
648
649 // this map marks the elements that we don't want to create annotations
650 private Map markupElementsMap = null;
651
652 // this map marks the elements after we want to insert some strings
653 private Map element2StringMap = null;
654
655 // listeners for status report
656 protected List myStatusListeners = new LinkedList();
657
658 // this reports the the number of emails that have beed processed so far
659 private int emails = 0;
660
661 // this is set by the method lineBeginsWithField(String line)
662 // each time the the line begins with a field name, that fiels will be stored
663 // in this member.
664 private String fieldName = null;
665
666 private Collection day = null;
667 private Collection month = null;
668 private Collection zone = null;
669
670
671 // TEST SECTION
672
673 /**
674 * Test containsSemicolon
675 */
676 private void testContainsSemicolon() {
677 String str1 = "X-Sender: oana@derwent";
678 String str2 = "X-Sender oana@derwent";
679 String str3 = ":X-Sender oana@derwent";
680 String str4 = "X-Sender oana@derwent:";
681
682 Assert.assertTrue((containsSemicolon(str1) == true));
683 Assert.assertTrue((containsSemicolon(str2)== false));
684 Assert.assertTrue((containsSemicolon(str3) == true));
685 Assert.assertTrue((containsSemicolon(str4) == true));
686 }// testContainsSemicolon
687
688 /**
689 * Test containsWhiteSpaces
690 */
691 private void testContainsWhiteSpaces(){
692 String str1 = "Content-Type: TEXT/PLAIN; charset=US-ASCII";
693 String str2 = "Content-Type:TEXT/PLAIN;charset=US-ASCII";
694 String str3 = " Content-Type:TEXT/PLAIN;charset=US-ASCII";
695 String str4 = "Content-Type:TEXT/PLAIN;charset=US-ASCII ";
696
697 Assert.assertTrue((containsWhiteSpaces(str1) == true));
698 Assert.assertTrue((containsWhiteSpaces(str2) == false));
699 Assert.assertTrue((containsWhiteSpaces(str3) == true));
700 Assert.assertTrue((containsWhiteSpaces(str4) == true));
701 }// testContainsWhiteSpaces
702
703 /**
704 * Test hasAMeaning
705 */
706 private void testHasAMeaning() {
707 String str1 = "12:05:22";
708 String str2 = "Sep";
709 String str3 = "Fri";
710 String str4 = "2000";
711 String str5 = "GMT";
712 String str6 = "Date: Wed, 13 Sep 2000 13:05:22 +0100 (BST)";
713 String str7 = "12:75:22";
714 String str8 = "September";
715 String str9 = "Friday";
716
717 Assert.assertTrue((hasAMeaning(str1) == true));
718 Assert.assertTrue((hasAMeaning(str2) == true));
719 Assert.assertTrue((hasAMeaning(str3) == true));
720 Assert.assertTrue((hasAMeaning(str4) == true));
721 Assert.assertTrue((hasAMeaning(str5) == true));
722 Assert.assertTrue((hasAMeaning(str6) == false));
723 Assert.assertTrue((hasAMeaning(str7) == false));
724 Assert.assertTrue((hasAMeaning(str8) == false));
725 Assert.assertTrue((hasAMeaning(str9) == false));
726 } // testHasAMeaning
727
728 /**
729 * Test isTime
730 */
731 private void testIsTime() {
732 String str1 = "13:05:22";
733 String str2 = "13/05/22";
734 String str3 = "24:05:22";
735
736 Assert.assertTrue((isTime(str1) == true));
737 Assert.assertTrue((isTime(str2) == false));
738 Assert.assertTrue((isTime(str3) == false));
739 }// testIsTime
740
741 /**
742 * Test lineBeginsMessage
743 */
744 private void testLineBeginsMessage(){
745 String str1 = "From oana@dcs.shef.ac.uk Wed Sep 13 13:05:23 2000";
746 String str2 = "Date: Wed, 13 Sep 2000 13:05:22 +0100 (BST)";
747 String str3 = "From oana@dcs.shef.ac.uk Sep 13 13:05:23 2000";
748
749 Assert.assertTrue((lineBeginsMessage(str1) == true));
750 Assert.assertTrue((lineBeginsMessage(str2) == false));
751 Assert.assertTrue((lineBeginsMessage(str3) == false));
752
753 }// testLineBeginsMessage
754
755 /**
756 * Test lineBeginsWithField
757 */
758 private void testLineBeginsWithField() {
759 String str1 = "Message-ID: <Pine.SOL.3.91.1000913130311.19537A-10@derwent>";
760 String str2 = "%:ContentType TEXT/PLAIN; charset=US-ASCII";
761
762 Assert.assertTrue((lineBeginsWithField(str1) == true));
763 Assert.assertTrue((lineBeginsWithField(str2) == true));
764 }// testLineBeginsWithField
765
766 /**
767 * Test final
768 */
769 public void testSelf(){
770 testContainsSemicolon();
771 testContainsWhiteSpaces();
772 testHasAMeaning();
773 testIsTime();
774 testLineBeginsMessage();
775 testLineBeginsWithField();
776 } // testSelf
777
778 } //EmailDocumentHandler
|