/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * ****************************************************************/ package org.apache.james.mime4j.field.address; import java.util.ArrayList; import java.util.Iterator; import org.apache.james.mime4j.decoder.DecoderUtil; import org.apache.james.mime4j.field.address.parser.*; import org.apache.james.mime4j.field.address.parser.ASTaddr_spec; import org.apache.james.mime4j.field.address.parser.ASTaddress; import org.apache.james.mime4j.field.address.parser.ASTaddress_list; import org.apache.james.mime4j.field.address.parser.ASTangle_addr; import org.apache.james.mime4j.field.address.parser.ASTdomain; import org.apache.james.mime4j.field.address.parser.ASTgroup_body; import org.apache.james.mime4j.field.address.parser.ASTlocal_part; import org.apache.james.mime4j.field.address.parser.ASTmailbox; import org.apache.james.mime4j.field.address.parser.ASTname_addr; import org.apache.james.mime4j.field.address.parser.ASTphrase; import org.apache.james.mime4j.field.address.parser.ASTroute; import org.apache.james.mime4j.field.address.parser.Node; import org.apache.james.mime4j.field.address.parser.SimpleNode; import org.apache.james.mime4j.field.address.parser.Token; /** * Transforms the JJTree-generated abstract syntax tree * into a graph of org.apache.james.mime4j.field.address objects. * * */ class Builder { private static Builder singleton = new Builder(); public static Builder getInstance() { return singleton; } public AddressList buildAddressList(ASTaddress_list node) { ArrayList list = new ArrayList(); for (int i = 0; i < node.jjtGetNumChildren(); i++) { ASTaddress childNode = (ASTaddress) node.jjtGetChild(i); Address address = buildAddress(childNode); list.add(address); } return new AddressList(list, true); } private Address buildAddress(ASTaddress node) { ChildNodeIterator it = new ChildNodeIterator(node); Node n = it.nextNode(); if (n instanceof ASTaddr_spec) { return buildAddrSpec((ASTaddr_spec)n); } else if (n instanceof ASTangle_addr) { return buildAngleAddr((ASTangle_addr)n); } else if (n instanceof ASTphrase) { String name = buildString((ASTphrase)n, false); Node n2 = it.nextNode(); if (n2 instanceof ASTgroup_body) { return new Group(name, buildGroupBody((ASTgroup_body)n2)); } else if (n2 instanceof ASTangle_addr) { name = DecoderUtil.decodeEncodedWords(name); return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2)); } else { throw new IllegalStateException(); } } else { throw new IllegalStateException(); } } private MailboxList buildGroupBody(ASTgroup_body node) { ArrayList results = new ArrayList(); ChildNodeIterator it = new ChildNodeIterator(node); while (it.hasNext()) { Node n = it.nextNode(); if (n instanceof ASTmailbox) results.add(buildMailbox((ASTmailbox)n)); else throw new IllegalStateException(); } return new MailboxList(results, true); } private Mailbox buildMailbox(ASTmailbox node) { ChildNodeIterator it = new ChildNodeIterator(node); Node n = it.nextNode(); if (n instanceof ASTaddr_spec) { return buildAddrSpec((ASTaddr_spec)n); } else if (n instanceof ASTangle_addr) { return buildAngleAddr((ASTangle_addr)n); } else if (n instanceof ASTname_addr) { return buildNameAddr((ASTname_addr)n); } else { throw new IllegalStateException(); } } private NamedMailbox buildNameAddr(ASTname_addr node) { ChildNodeIterator it = new ChildNodeIterator(node); Node n = it.nextNode(); String name; if (n instanceof ASTphrase) { name = buildString((ASTphrase)n, false); } else { throw new IllegalStateException(); } n = it.nextNode(); if (n instanceof ASTangle_addr) { name = DecoderUtil.decodeEncodedWords(name); return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n)); } else { throw new IllegalStateException(); } } private Mailbox buildAngleAddr(ASTangle_addr node) { ChildNodeIterator it = new ChildNodeIterator(node); DomainList route = null; Node n = it.nextNode(); if (n instanceof ASTroute) { route = buildRoute((ASTroute)n); n = it.nextNode(); } else if (n instanceof ASTaddr_spec) ; // do nothing else throw new IllegalStateException(); if (n instanceof ASTaddr_spec) return buildAddrSpec(route, (ASTaddr_spec)n); else throw new IllegalStateException(); } private DomainList buildRoute(ASTroute node) { ArrayList results = new ArrayList(node.jjtGetNumChildren()); ChildNodeIterator it = new ChildNodeIterator(node); while (it.hasNext()) { Node n = it.nextNode(); if (n instanceof ASTdomain) results.add(buildString((ASTdomain)n, true)); else throw new IllegalStateException(); } return new DomainList(results, true); } private Mailbox buildAddrSpec(ASTaddr_spec node) { return buildAddrSpec(null, node); } private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) { ChildNodeIterator it = new ChildNodeIterator(node); String localPart = buildString((ASTlocal_part)it.nextNode(), true); String domain = buildString((ASTdomain)it.nextNode(), true); return new Mailbox(route, localPart, domain); } private String buildString(SimpleNode node, boolean stripSpaces) { Token head = node.firstToken; Token tail = node.lastToken; StringBuffer out = new StringBuffer(); while (head != tail) { out.append(head.image); head = head.next; if (!stripSpaces) addSpecials(out, head.specialToken); } out.append(tail.image); return out.toString(); } private void addSpecials(StringBuffer out, Token specialToken) { if (specialToken != null) { addSpecials(out, specialToken.specialToken); out.append(specialToken.image); } } private static class ChildNodeIterator implements Iterator { private SimpleNode simpleNode; private int index; private int len; public ChildNodeIterator(SimpleNode simpleNode) { this.simpleNode = simpleNode; this.len = simpleNode.jjtGetNumChildren(); this.index = 0; } public void remove() { throw new UnsupportedOperationException(); } public boolean hasNext() { return index < len; } public Object next() { return nextNode(); } public Node nextNode() { return simpleNode.jjtGetChild(index++); } } }