1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.message;
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.HeaderFactoryExt;
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.HeaderFactoryImpl;
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.parser.StringMsgParser;
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Iterator;
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList;
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.List;
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContentDispositionHeader;
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.ContentTypeHeader;
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.Header;
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.HeaderFactory;
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Message;
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Content list for multipart mime content type.
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class MultipartMimeContentImpl implements MultipartMimeContent {
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private List<Content> contentList = new LinkedList<Content>();
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ContentTypeHeader multipartMimeContentTypeHeader;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String boundary;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static String BOUNDARY = "boundary";
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a default content list.
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MultipartMimeContentImpl(ContentTypeHeader contentTypeHeader) {
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.multipartMimeContentTypeHeader = contentTypeHeader;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.boundary = contentTypeHeader.getParameter(BOUNDARY);
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#add(gov.nist.javax.sip.message.Content)
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean add(Content content) {
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return contentList.add((ContentImpl) content);
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentTypeHeader()
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ContentTypeHeader getContentTypeHeader() {
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return multipartMimeContentTypeHeader;
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#toString()
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    @Override
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String toString() {
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer stringBuffer = new StringBuffer();
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        for (Content content : this.contentList) {
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stringBuffer.append(content.toString());
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return stringBuffer.toString();
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * unpack a multipart mime packet and return a list of content packets.
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- an iterator of Content blocks.
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void createContentList(String body) throws ParseException {
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            HeaderFactoryExt headerFactory = new HeaderFactoryImpl();
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String delimiter = this.getContentTypeHeader().getParameter(BOUNDARY);
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (delimiter == null) {
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.contentList = new LinkedList<Content>();
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ContentImpl content = new ContentImpl(body, delimiter);
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                content.setContentTypeHeader(this.getContentTypeHeader());
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.contentList.add(content);
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String[] fragments = body.split("--" + delimiter + "\r\n");
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (String nextPart : fragments) {
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // NOTE - we are not hanlding line folding for the sip header here.
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (nextPart == null) {
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                StringBuffer strbuf = new StringBuffer(nextPart);
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (strbuf.length() > 0
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && (strbuf.charAt(0) == '\r' || strbuf.charAt(0) == '\n'))
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    strbuf.deleteCharAt(0);
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (strbuf.length() == 0)
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    continue;
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextPart = strbuf.toString();
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int position = nextPart.indexOf("\r\n\r\n");
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int off = 4;
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (position == -1) {
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    position = nextPart.indexOf("\n");
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    off = 2;
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (position == -1)
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new ParseException("no content type header found in " + nextPart, 0);
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String rest = nextPart.substring(position + off);
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (rest == null)
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new ParseException("No content [" + nextPart + "]", 0);
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // logger.debug("rest = [[" + rest + "]]");
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String headers = nextPart.substring(0, position);
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ContentImpl content = new ContentImpl(rest, boundary);
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String[] headerArray = headers.split("\r\n");
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                for (String hdr : headerArray) {
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    Header header = headerFactory.createHeader(hdr);
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (header instanceof ContentTypeHeader) {
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        content.setContentTypeHeader((ContentTypeHeader) header);
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else if (header instanceof ContentDispositionHeader) {
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        content.setContentDispositionHeader((ContentDispositionHeader) header);
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        throw new ParseException("Unexpected header type " + header.getName(), 0);
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    contentList.add(content);
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (StringIndexOutOfBoundsException ex) {
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("Invalid Multipart mime format", 0);
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentByType(java.lang.String,
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *      java.lang.String)
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Content getContentByType(String contentType, String contentSubtype) {
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Content retval = null;
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (contentList == null)
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        for (Content content : contentList) {
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (content.getContentTypeHeader().getContentType().equalsIgnoreCase(contentType)
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && content.getContentTypeHeader().getContentSubType().equalsIgnoreCase(
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            contentSubtype)) {
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval = content;
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                break;
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.message.MultipartMimeContentExt#setContent(java.lang.String,
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *      java.lang.String, gov.nist.javax.sip.message.Content)
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addContent(Content content) {
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.add(content);
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Iterator<Content> getContents() {
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.contentList.iterator();
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getContentCount() {
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.contentList.size();
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
191