/*
* Copyright (C) 2005 Luca Veltri - University of Parma - Italy
*
* This file is part of MjSip (http://www.mjsip.org)
*
* MjSip is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MjSip is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MjSip; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author(s):
* Luca Veltri (luca.veltri@unipr.it)
*/
package org.zoolu.sip.message;
import org.zoolu.sip.provider.*;
import org.zoolu.sip.header.*;
import org.zoolu.sip.address.*;
import org.zoolu.sip.message.SipMethods;
import org.zoolu.net.UdpPacket;
import java.util.*;
/** Class BaseMessageOtp implements a generic SIP Message.
* It extends class BaseMessage adding one-time-parsing functionality
* (it parses the entire Message just when it is costructed).
* <p/> At the contrary, class BaseMessage works in a just-in-time manner
* (it parses the message each time a particular header field is requested). */
public abstract class BaseMessageOtp extends BaseMessage
{
protected RequestLine request_line;
protected StatusLine status_line;
protected Vector headers;
protected String body;
/** Inits empty Message */
private void init()
{ request_line=null;
status_line=null;
headers=null;
body=null;
}
/** Costructs a new empty Message */
public BaseMessageOtp()
{ init();
headers=new Vector();
}
/** Costructs a new Message */
public BaseMessageOtp(byte[] data, int offset, int len)
{ init();
parseIt(new String(data,offset,len));
}
/** Costructs a new Message */
public BaseMessageOtp(UdpPacket packet)
{ init();
parseIt(new String(packet.getData(),packet.getOffset(),packet.getLength()));
}
/** Costructs a new Message */
public BaseMessageOtp(String str)
{ init();
parseIt(str);
}
/** Costructs a new Message */
public BaseMessageOtp(BaseMessageOtp msg)
{ init();
remote_addr=msg.remote_addr;
remote_port=msg.remote_port;
transport_proto=msg.transport_proto;
connection_id=msg.connection_id;
//packet_length=msg.packet_length;
request_line=msg.request_line;
status_line=msg.status_line;
headers=new Vector();
for (int i=0; i<msg.headers.size(); i++) headers.addElement(msg.headers.elementAt(i));
body=msg.body;
}
/** Sets the entire message */
public void setMessage(String str)
{ parseIt(str);
}
/** Parses the Message from a String. */
private void parseIt(String str)
{ SipParser par=new SipParser(str);
String version=str.substring(0,4);
if (version.equalsIgnoreCase("SIP/")) status_line=par.getStatusLine();
else request_line=par.getRequestLine();
headers=new Vector();
Header h=par.getHeader();
while (h!=null)
{ headers.addElement(h);
h=par.getHeader();
}
ContentLengthHeader clh=getContentLengthHeader();
if (clh!=null)
{ int len=clh.getContentLength();
body=par.getString(len);
}
else
if (getContentTypeHeader()!=null)
{ body=par.getRemainingString();
if (body.length()==0) body=null;
}
}
/** Gets string representation of Message */
public String toString()
{ StringBuffer str=new StringBuffer();
if (request_line!=null) str.append(request_line.toString());
else if (status_line!=null) str.append(status_line.toString());
for (int i=0; i<headers.size(); i++) str.append(((Header)headers.elementAt(i)).toString());
str.append("\r\n");
if (body!=null) str.append(body);
return str.toString();
}
/** Gets message length */
public int getLength()
{ return toString().length();
}
//**************************** Requests ****************************/
/** Whether Message is a Request */
public boolean isRequest()
{ if (request_line!=null) return true;
else return false;
}
/** Whether Message is a <i>method</i> request */
public boolean isRequest(String method)
{ if (request_line!=null && request_line.getMethod().equalsIgnoreCase(method)) return true;
else return false;
}
/** Whether Message has Request-line */
protected boolean hasRequestLine()
{ return request_line!=null;
}
/** Gets RequestLine in Message (Returns null if called for no request message) */
public RequestLine getRequestLine()
{ return request_line;
}
/** Sets RequestLine of the Message */
public void setRequestLine(RequestLine rl)
{ request_line=rl;
}
/** Removes RequestLine of the Message */
public void removeRequestLine()
{ request_line=null;
}
//**************************** Responses ****************************/
/** Whether Message is a Response */
public boolean isResponse() throws NullPointerException
{ if (status_line!=null) return true;
else return false;
}
/** Whether Message has Status-line */
protected boolean hasStatusLine()
{ return status_line!=null;
}
/** Gets StautsLine in Message (Returns null if called for no response message) */
public StatusLine getStatusLine()
{ return status_line;
}
/** Sets StatusLine of the Message */
public void setStatusLine(StatusLine sl)
{ status_line=sl;
}
/** Removes StatusLine of the Message */
public void removeStatusLine()
{ status_line=null;
}
//**************************** Generic Headers ****************************/
/** Removes Request\Status Line of the Message */
protected void removeFirstLine()
{ removeRequestLine();
removeStatusLine();
}
/** Gets the position of header <i>hname</i>. */
protected int indexOfHeader(String hname)
{ for (int i=0; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName())) return i;
}
return -1;
}
/** Gets the first Header of specified name (Returns null if no Header is found) */
public Header getHeader(String hname)
{ int i=indexOfHeader(hname);
if (i<0) return null;
else return (Header)headers.elementAt(i);
}
/** Gets a Vector of all Headers of specified name (Returns empty Vector if no Header is found) */
public Vector getHeaders(String hname)
{ Vector v=new Vector();
for (int i=0; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName())) v.addElement(h);
}
return v;
}
/** Adds Header at the top/bottom.
* The bottom is considered before the Content-Length and Content-Type headers */
public void addHeader(Header header, boolean top)
{ if (top) headers.insertElementAt(header,0); else headers.addElement(header);
}
/** Adds a Vector of Headers at the top/bottom */
public void addHeaders(Vector headers, boolean top)
{ for (int i=0; i<headers.size(); i++)
if (top) this.headers.insertElementAt(headers.elementAt(i),i);
else this.headers.addElement(headers.elementAt(i));
}
/** Adds MultipleHeader(s) <i>mheader</i> at the top/bottom */
public void addHeaders(MultipleHeader mheader, boolean top)
{ if (mheader.isCommaSeparated()) addHeader(mheader.toHeader(),top);
else addHeaders(mheader.getHeaders(),top);
}
/** Adds Header before the first header <i>refer_hname</i>
* . <p>If there is no header of such type, it is added at top */
public void addHeaderBefore(Header new_header, String refer_hname)
{ int i=indexOfHeader(refer_hname);
if (i<0) i=0;
headers.insertElementAt(new_header,i);
}
/** Adds MultipleHeader(s) before the first header <i>refer_hname</i>
* . <p>If there is no header of such type, they are added at top */
public void addHeadersBefore(MultipleHeader mheader, String refer_hname)
{ if (mheader.isCommaSeparated()) addHeaderBefore(mheader.toHeader(),refer_hname);
else
{ int index=indexOfHeader(refer_hname);
if (index<0) index=0;
Vector hs=mheader.getHeaders();
for (int k=0; k<hs.size(); k++) headers.insertElementAt(hs.elementAt(k),index+k);
}
}
/** Adds Header after the first header <i>refer_hname</i>
* . <p>If there is no header of such type, it is added at bottom */
public void addHeaderAfter(Header new_header, String refer_hname)
{ int i=indexOfHeader(refer_hname);
if (i>=0) i++; else i=headers.size();
headers.insertElementAt(new_header,i);
}
/** Adds MultipleHeader(s) after the first header <i>refer_hname</i>
* . <p>If there is no header of such type, they are added at bottom */
public void addHeadersAfter(MultipleHeader mheader, String refer_hname)
{ if (mheader.isCommaSeparated()) addHeaderAfter(mheader.toHeader(),refer_hname);
else
{ int index=indexOfHeader(refer_hname);
if (index>=0) index++; else index=headers.size();
Vector hs=mheader.getHeaders();
for (int k=0; k<hs.size(); k++) headers.insertElementAt(hs.elementAt(k),index+k);
}
}
/** Removes first Header of specified name */
public void removeHeader(String hname)
{ removeHeader(hname,true);
}
/** Removes first (or last) Header of specified name. */
public void removeHeader(String hname, boolean first)
{ int index=-1;
for (int i=0 ; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName()))
{ index=i;
if (first) i=headers.size();
}
}
if (index>=0) headers.removeElementAt(index);
}
/** Removes all Headers of specified name */
public void removeAllHeaders(String hname)
{ for (int i=0 ; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName()))
{ headers.removeElementAt(i);
i--;
}
}
}
/** Sets the Header <i>hd</i> removing any previous headers of the same type. */
public void setHeader(Header hd)
{ boolean first=true;
String hname=hd.getName();
for (int i=0 ; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName()))
{ if (first)
{ // replace it
headers.setElementAt(h,i);
first=false;
}
else
{ // remove it
headers.removeElementAt(i);
i--;
}
}
}
if (first) headers.addElement(hd);
}
/** Sets MultipleHeader <i>mheader</i> */
public void setHeaders(MultipleHeader mheader)
{ if (mheader.isCommaSeparated()) setHeader(mheader.toHeader());
else
{ boolean first=true;
String hname=mheader.getName();
for (int i=0 ; i<headers.size(); i++)
{ Header h=(Header)headers.elementAt(i);
if (hname.equalsIgnoreCase(h.getName()))
{ if (first)
{ // replace it
Vector hs=mheader.getHeaders();
for (int k=0; k<hs.size(); k++) headers.insertElementAt(hs.elementAt(k),i+k);
first=false;
i+=hs.size()-1;
}
else
{ // remove it
headers.removeElementAt(i);
i--;
}
}
}
}
}
//**************************** Specific Headers ****************************/
/** Whether Message has Body */
public boolean hasBody()
{ return this.body!=null;
}
/** Gets body(content) type */
public String getBodyType()
{ return getContentTypeHeader().getContentType();
}
/** Sets the message body */
public void setBody(String content_type, String body)
{ removeBody();
if (body!=null && body.length()>0)
{ setContentTypeHeader(new ContentTypeHeader(content_type));
setContentLengthHeader(new ContentLengthHeader(body.length()));
this.body=body;
}
else
{ setContentLengthHeader(new ContentLengthHeader(0));
this.body=null;
}
}
/** Gets message body. The end of body is evaluated
* from the Content-Length header if present (SIP-RFC compliant),
* or from the end of message if no Content-Length header is present (non-SIP-RFC compliant) */
public String getBody()
{ return this.body;
}
/** Removes the message body (if it exists) and the final empty line */
public void removeBody()
{ removeContentLengthHeader();
removeContentTypeHeader();
this.body=null;
}
}