// Copyright 2000-2005 the Contributors, as shown in the revision logs. // Licensed under the Apache Public Source License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.mail; import static org.ibex.mail.MailException.*; import org.ibex.crypto.*; import org.ibex.util.*; import org.ibex.mail.protocol.*; import org.ibex.js.*; import org.ibex.io.*; import org.ibex.io.Fountain; import java.util.*; import java.net.*; import java.io.*; // FEATURE: construct hash lazily? public class Headers extends JS.Immutable implements Fountain { /** * constructs a new set of Headers based on a preexisting set -- * keyval's even-numbered elements are keys, odd elements are * values -- a null value deletes, non-null value replaces */ public Headers(Headers old, String[] keyval) { this(old.updateHeaders(keyval), false); } public Headers(String[] keyval) { this(new Headers(), keyval); } public Headers() { this(new String[0]); } public Headers(Fountain fountain) throws Malformed { this(fountain, false); } public Headers(Fountain fountain, boolean assumeMime) throws Malformed { this(extractEntries(fountain), assumeMime); } // public ////////////////////////////////////////////////////////////////////////////// public String[] getHeaderNames() { return (String[])head.dumpkeys(new String[head.size()]); } public String get(String s) { return (String)head.get(s.toLowerCase()); } public JS get(JS s) throws JSExn { return JSU.S(get(JSU.toString(s).toLowerCase())); } public Stream getStream() { return fountain().getStream(); } public long getLength() { return fountain().getLength(); } public int getNumLines() { return fountain().getNumLines(); } // private ////////////////////////////////////////////////////////////////////////////// private final Hash head = new Hash(); private final boolean mime; private final Entry[] entries; private Fountain fountain = null; private synchronized Fountain fountain() { // lazily constructed if (fountain == null) { StringBuffer sb = new StringBuffer(); for(Entry e : entries) sb.append(e.toString()); this.fountain = Fountain.Util.create(sb.toString()); } return fountain; } private static class Entry { public final String key; public final String val; public String toString() { return key+":"+val; } public Entry(String key, String val) throws Malformed { this.key = key; this.val = val; for(int i=0; i 126) throw new Malformed("Header key \""+key+"\" contains invalid character \"" + key.charAt(i) + "\" (0x"+Integer.toString(key.charAt(i), 16) +")"); } } private Headers(Entry[] entries, boolean assumeMime) { this.entries = entries; this.mime = assumeMime | (get("mime-version") != null && get("mime-version").trim().equals("1.0")); for(Entry e : entries) { String val = (String)head.get(e.key.toLowerCase()); val = val==null ? e.val.trim() : val+" "+e.val.trim(); // introduce folding whitespace =( // FEATURE //if (mime) k = Encode.RFC2047.decode(k); //if (mime) v = Encode.RFC2047.decode(v); head.put(e.key.toLowerCase(), val); } } private static Entry[] extractEntries(Fountain fountain) throws Malformed { String key = null; Stream stream = fountain.getStream(); ArrayList entries = new ArrayList(); for(String s = stream.readln(); s != null && !s.equals(""); s = stream.readln()) { s += "\r\n"; // this is the only place where we introduce manglage -- we normalize EOLs if (Character.isSpace(s.charAt(0))) { if (key == null) throw new Malformed("Message began with a blank line; no headers"); Entry e = entries.remove(entries.size()-1); entries.add(new Entry(e.key, e.val+s)); continue; } if (s.indexOf(':') == -1) throw new Malformed("Header line does not contain colon: " + s); key = s.substring(0, s.indexOf(':')); entries.add(new Entry(key, s.substring(s.indexOf(':') + 1))); } return (Entry[])entries.toArray(new Entry[entries.size()]); } private Entry[] updateHeaders(String[] keyval) { ArrayList entries = new ArrayList(); for(int i=0; i 0;) s = stream.readln(); return stream; } // designed to remove CFWS, but doesn't work right public static String removeCFWS(String val) { boolean inquotes = false; for(int i=0; i