diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2010-11-30 16:47:27 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2010-11-30 16:47:27 -0800 |
commit | f35a2ce023b55701ae9ffde56082faa91647e624 (patch) | |
tree | 191104b8f7d19486b39bc16fdf98890679fbf435 | |
download | android_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.tar.gz android_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.tar.bz2 android_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.zip |
snapshot
Change-Id: I430fbda80eb4d33b1af1180e2e86de3a6167ebb4
514 files changed, 83764 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..892bce1 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,30 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sip"> + <uses-permission android:name="android.permission.INTERNET"></uses-permission> + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"></uses-permission> + <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> + <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission> + <uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission> + <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission> + <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission> + <uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission> + <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission> + <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission> + <uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission> + <uses-permission android:name="android.permission.CAMERA"></uses-permission> + <uses-permission android:name="android.permission.VIBRATE" ></uses-permission> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" ></uses-permission> + + <application android:label="@string/app_name"> + <activity android:name=".SipMain" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/CleanSpec.mk b/CleanSpec.mk new file mode 100644 index 0000000..b84e1b6 --- /dev/null +++ b/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/NIST-CONDITIONS-OF-USE.txt b/NIST-CONDITIONS-OF-USE.txt new file mode 100644 index 0000000..7c14b42 --- /dev/null +++ b/NIST-CONDITIONS-OF-USE.txt @@ -0,0 +1,27 @@ +/* +*********************************************************************** +* The following applies to the packages "gov.nist", "test" and +* "tools" and all subpackages thereof +*********************************************************************** +* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), and others. +* This software has been contributed to the public domain. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. +* As a result, a formal license is not needed to use this software. +* +* This software is provided "AS IS." +* NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* this software. +* +* +*/ diff --git a/TIMESTAMP b/TIMESTAMP new file mode 100644 index 0000000..dee261d --- /dev/null +++ b/TIMESTAMP @@ -0,0 +1 @@ +140 diff --git a/java/gov/nist/core/Debug.java b/java/gov/nist/core/Debug.java new file mode 100644 index 0000000..aae49d3 --- /dev/null +++ b/java/gov/nist/core/Debug.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.core; + + +/** + * A class to do debug printfs + */ +public class Debug { + + public static boolean debug = false; + public static boolean parserDebug = false; + + static StackLogger stackLogger; + + public static void setStackLogger(StackLogger stackLogger) { + Debug.stackLogger = stackLogger; + } + + public static void println(String s) { + if ((parserDebug || debug )&& stackLogger != null ) + stackLogger.logDebug(s + "\n"); + } + public static void printStackTrace(Exception ex) { + if ((parserDebug || debug ) && stackLogger != null) { + stackLogger.logError("Stack Trace",ex); + } + } + + public static void logError(String message, Exception ex) { + if ((parserDebug || debug) && stackLogger != null ) { + stackLogger.logError(message,ex); + } + } + +} diff --git a/java/gov/nist/core/DuplicateNameValueList.java b/java/gov/nist/core/DuplicateNameValueList.java new file mode 100644 index 0000000..53450af --- /dev/null +++ b/java/gov/nist/core/DuplicateNameValueList.java @@ -0,0 +1,261 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +package gov.nist.core; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * + * + * This is a Duplicate Name Value List that will allow multiple values map to the same key. + * + * The parsing and encoding logic for it is the same as that of NameValueList. Only the HashMap + * container is different. + * + * @author aayush.bhatnagar + * @since 2.0 + * + */ +public class DuplicateNameValueList implements Serializable, Cloneable { + + private MultiValueMapImpl<NameValue> nameValueMap = new MultiValueMapImpl<NameValue>(); + private String separator; + + private static final long serialVersionUID = -5611332957903796952L; + + public DuplicateNameValueList() + + { + this.separator = ";"; + } + + // ------------------ + + public void setSeparator(String separator) { + this.separator = separator; + } + + /** + * Encode the list in semicolon separated form. + * + * @return an encoded string containing the objects in this list. + * @since v1.0 + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (!nameValueMap.isEmpty()) { + Iterator<NameValue> iterator = nameValueMap.values().iterator(); + if (iterator.hasNext()) { + while (true) { + Object obj = iterator.next(); + if (obj instanceof GenericObject) { + GenericObject gobj = (GenericObject) obj; + gobj.encode(buffer); + } else { + buffer.append(obj.toString()); + } + if (iterator.hasNext()) + buffer.append(separator); + else + break; + } + } + } + return buffer; + } + + public String toString() { + return this.encode(); + } + + /** + * Set a namevalue object in this list. + */ + + public void set(NameValue nv) { + this.nameValueMap.put(nv.getName().toLowerCase(), nv); + } + + /** + * Set a namevalue object in this list. + */ + public void set(String name, Object value) { + NameValue nameValue = new NameValue(name, value); + nameValueMap.put(name.toLowerCase(), nameValue); + + } + + /** + * Compare if two NameValue lists are equal. + * + * @param otherObject is the object to compare to. + * @return true if the two objects compare for equality. + */ + public boolean equals(Object otherObject) { + if ( otherObject == null ) { + return false; + } + if (!otherObject.getClass().equals(this.getClass())) { + return false; + } + DuplicateNameValueList other = (DuplicateNameValueList) otherObject; + + if (nameValueMap.size() != other.nameValueMap.size()) { + return false; + } + Iterator<String> li = this.nameValueMap.keySet().iterator(); + + while (li.hasNext()) { + String key = (String) li.next(); + Collection nv1 = this.getNameValue(key); + Collection nv2 = (Collection) other.nameValueMap.get(key); + if (nv2 == null) + return false; + else if (!nv2.equals(nv1)) + return false; + } + return true; + } + + /** + * Do a lookup on a given name and return value associated with it. + */ + public Object getValue(String name) { + Collection nv = this.getNameValue(name.toLowerCase()); + if (nv != null) + return nv; + else + return null; + } + + /** + * Get the NameValue record given a name. + * + */ + public Collection getNameValue(String name) { + return (Collection) this.nameValueMap.get(name.toLowerCase()); + } + + /** + * Returns a boolean telling if this NameValueList has a record with this name + */ + public boolean hasNameValue(String name) { + return nameValueMap.containsKey(name.toLowerCase()); + } + + /** + * Remove the element corresponding to this name. + */ + public boolean delete(String name) { + String lcName = name.toLowerCase(); + if (this.nameValueMap.containsKey(lcName)) { + this.nameValueMap.remove(lcName); + return true; + } else { + return false; + } + + } + + public Object clone() { + DuplicateNameValueList retval = new DuplicateNameValueList(); + retval.setSeparator(this.separator); + Iterator<NameValue> it = this.nameValueMap.values().iterator(); + while (it.hasNext()) { + retval.set((NameValue) ((NameValue) it.next()).clone()); + } + return retval; + } + + /** + * Return an iterator for the name-value pairs of this list. + * + * @return the iterator. + */ + public Iterator<NameValue> iterator() { + return this.nameValueMap.values().iterator(); + } + + /** + * Get a list of parameter names. + * + * @return a list iterator that has the names of the parameters. + */ + public Iterator<String> getNames() { + return this.nameValueMap.keySet().iterator(); + + } + + /** + * Get the parameter as a String. + * + * @return the parameter as a string. + */ + public String getParameter(String name) { + Object val = this.getValue(name); + if (val == null) + return null; + if (val instanceof GenericObject) + return ((GenericObject) val).encode(); + else + return val.toString(); + } + + public void clear() { + nameValueMap.clear(); + + } + + public boolean isEmpty() { + return this.nameValueMap.isEmpty(); + } + + public NameValue put(String key, NameValue value) { + return (NameValue) this.nameValueMap.put(key, value); + } + + public NameValue remove(Object key) { + return (NameValue) this.nameValueMap.remove(key); + } + + public int size() { + return this.nameValueMap.size(); + } + + public Collection<NameValue> values() { + return this.nameValueMap.values(); + } + + public int hashCode() { + return this.nameValueMap.keySet().hashCode(); + } + +} diff --git a/java/gov/nist/core/GenericObject.java b/java/gov/nist/core/GenericObject.java new file mode 100644 index 0000000..53eea6b --- /dev/null +++ b/java/gov/nist/core/GenericObject.java @@ -0,0 +1,712 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.core; +import java.lang.reflect.*; +import java.io.Serializable; +import java.util.*; + +/** +* The base class from which all the other classes in the +* sipheader, sdpfields and sipmessage packages are extended. +* Provides a few utility funcitons such as indentation and +* pretty printing that all other classes benifit from. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ + +public abstract class GenericObject implements Serializable, Cloneable { + // Useful constants. + protected static final String SEMICOLON = Separators.SEMICOLON; + protected static final String COLON = Separators.COLON; + protected static final String COMMA = Separators.COMMA; + protected static final String SLASH = Separators.SLASH; + protected static final String SP = Separators.SP; + protected static final String EQUALS = Separators.EQUALS; + protected static final String STAR = Separators.STAR; + protected static final String NEWLINE = Separators.NEWLINE; + protected static final String RETURN = Separators.RETURN; + protected static final String LESS_THAN = Separators.LESS_THAN; + protected static final String GREATER_THAN = Separators.GREATER_THAN; + protected static final String AT = Separators.AT; + protected static final String DOT = Separators.DOT; + protected static final String QUESTION = Separators.QUESTION; + protected static final String POUND = Separators.POUND; + protected static final String AND = Separators.AND; + protected static final String LPAREN = Separators.LPAREN; + protected static final String RPAREN = Separators.RPAREN; + protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE; + protected static final String QUOTE = Separators.QUOTE; + protected static final String HT = Separators.HT; + protected static final String PERCENT = Separators.PERCENT; + + protected static final Set<Class<?>> immutableClasses = new HashSet<Class<?>> (10); + static final String[] immutableClassNames ={ + "String", "Character", + "Boolean", "Byte", "Short", "Integer", "Long", + "Float", "Double" + }; + + protected int indentation; + protected String stringRepresentation; + protected Match matchExpression; // Pattern matcher. + + static { + try { + for (int i = 0; i < immutableClassNames.length; i++) + immutableClasses.add(Class.forName("java.lang." + immutableClassNames [i])); + } catch (ClassNotFoundException e) { + throw new RuntimeException ("Internal error", e); + } + } + + /** Set the pattern matcher. To match on the + * field of a sip message, set the match expression in the match template + * and invoke the match function. This useful because + * SIP headers and parameters may appear in different orders and are not + * necessarily in canonical form. This makes it hard to write a pattern + * matcher that relies on regular expressions alone. + * Thus we rely on the following strategy i.e. To do pattern matching on + * an incoming message, first parse it, and then construct a match template, + * filling in the fields that you want to + * match. The rules for matching are: A null object matches wild card - + * that is a match template of null matches any parsed SIP object. + * To match with any subfield, set the match template on a template object + * of the same type and invoke the match interface. + * Regular expressions matching implements the gov.nist.sip.Match interface + * that can be done using the Jakarta regexp package for example. + * package included herein. This can be used to implement the Match interface + * <a href=http://www.apache.org> See the APACHE website for documents </a> + * + */ + public void setMatcher(Match matchExpression) { + if (matchExpression == null) + throw new IllegalArgumentException("null arg!"); + this.matchExpression = matchExpression; + } + + /** Return the match expression. + *@return the match expression that has previously been set. + */ + public Match getMatcher() { + return matchExpression; + } + + public static Class<?> getClassFromName(String className) { + try { + return Class.forName(className); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + return null; + } + } + + public static boolean isMySubclass(Class<?> other) { + + return GenericObject.class.isAssignableFrom(other); + + } + + /** Clones the given object. + * If the object is a wrapped type, an array, a GenericObject + * or a GenericObjectList, it is cast to the appropriate type + * and the clone() method is invoked. Else if the object implements + * Cloneable, reflection is used to discover and invoke + * clone() method. Otherwise, the original object is returned. + */ + public static Object makeClone(Object obj) { + if (obj == null) + throw new NullPointerException("null obj!"); + Class<?> c = obj.getClass(); + Object clone_obj = obj; + if (immutableClasses.contains (c)) + return obj; + else if (c.isArray ()) { + Class<?> ec = c.getComponentType(); + if (! ec.isPrimitive()) + clone_obj = ((Object []) obj).clone(); + else { + if (ec == Character.TYPE) + clone_obj = ((char []) obj).clone(); + else if (ec == Boolean.TYPE) + clone_obj = ((boolean []) obj).clone(); + if (ec == Byte.TYPE) + clone_obj = ((byte []) obj).clone(); + else if (ec == Short.TYPE) + clone_obj = ((short []) obj).clone(); + else if (ec == Integer.TYPE) + clone_obj = ((int []) obj).clone(); + else if (ec == Long.TYPE) + clone_obj = ((long []) obj).clone(); + else if (ec == Float.TYPE) + clone_obj = ((float []) obj).clone(); + else if (ec == Double.TYPE) + clone_obj = ((double []) obj).clone(); + } + } else if (GenericObject.class.isAssignableFrom (c)) + clone_obj = ((GenericObject) obj).clone(); + else if (GenericObjectList.class.isAssignableFrom (c)) + clone_obj = ((GenericObjectList) obj).clone(); + else if (Cloneable.class.isAssignableFrom (c)) { + // If a clone method exists for the object, then + // invoke it + try { + Method meth = c.getMethod("clone", (Class[]) null); + clone_obj = meth.invoke(obj,(Object[]) null); + } catch (SecurityException ex) { + } catch (IllegalArgumentException ex) { + InternalErrorHandler.handleException(ex); + } catch (IllegalAccessException ex) { + } catch (InvocationTargetException ex) { + } catch (NoSuchMethodException ex) { + } + } + return clone_obj; + } + + /** Clones this object. + */ + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Internal error"); + } + } + /** + * Recursively override the fields of this object with the fields + * of a new object. This is useful when you want to genrate a template + * and override the fields of an incoming SIPMessage with another + * SIP message that you have already generated. + * + * @param mergeObject is the replacement object. The override + * obect must be of the same class as this object. + * Set any fields that you do not want to override as null in the + * mergeOject object. + */ + public void merge(Object mergeObject) { + // Base case. + if (mergeObject == null) + return; + + if (!mergeObject.getClass().equals(this.getClass())) + throw new IllegalArgumentException("Bad override object"); + + Class<?> myclass = this.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + int modifier = f.getModifiers(); + if (Modifier.isPrivate(modifier)) { + continue; + } else if (Modifier.isStatic(modifier)) { + continue; + } else if (Modifier.isInterface(modifier)) { + continue; + } + Class<?> fieldType = f.getType(); + String fname = fieldType.toString(); + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + if (fname.compareTo("int") == 0) { + int intfield = f.getInt(mergeObject); + f.setInt(this, intfield); + } else if (fname.compareTo("short") == 0) { + short shortField = f.getShort(mergeObject); + f.setShort(this, shortField); + } else if (fname.compareTo("char") == 0) { + char charField = f.getChar(mergeObject); + f.setChar(this, charField); + } else if (fname.compareTo("long") == 0) { + long longField = f.getLong(mergeObject); + f.setLong(this, longField); + } else if (fname.compareTo("boolean") == 0) { + boolean booleanField = f.getBoolean(mergeObject); + f.setBoolean(this, booleanField); + } else if (fname.compareTo("double") == 0) { + double doubleField = f.getDouble(mergeObject); + f.setDouble(this, doubleField); + } else if (fname.compareTo("float") == 0) { + float floatField = f.getFloat(mergeObject); + f.setFloat(this, floatField); + } + } else { + Object obj = f.get(this); + Object mobj = f.get(mergeObject); + if (mobj == null) + continue; + if (obj == null) { + f.set(this, mobj); + continue; + } + if (obj instanceof GenericObject) { + GenericObject gobj = (GenericObject) obj; + gobj.merge(mobj); + } else { + f.set(this, mobj); + } + } + } catch (IllegalAccessException ex1) { + ex1.printStackTrace(); + continue; // we are accessing a private field... + } + } + myclass = myclass.getSuperclass(); + if (myclass.equals(GenericObject.class)) + break; + } + } + + protected GenericObject() { + indentation = 0; + stringRepresentation = ""; + } + + protected String getIndentation() { + char [] chars = new char [indentation]; + java.util.Arrays.fill (chars, ' '); + return new String (chars); + } + + /** + * Add a new string to the accumulated string representation. + */ + + protected void sprint(String a) { + if (a == null) { + stringRepresentation += getIndentation(); + stringRepresentation += "<null>\n"; + return; + } + if (a.compareTo("}") == 0 || a.compareTo("]") == 0) { + indentation--; + } + stringRepresentation += getIndentation(); + stringRepresentation += a; + stringRepresentation += "\n"; + if (a.compareTo("{") == 0 || a.compareTo("[") == 0) { + indentation++; + } + + } + + /** + * Pretty printing function accumulator for objects. + */ + + protected void sprint(Object o) { + sprint(o.toString()); + } + + /** + * Pretty printing accumulator function for ints + */ + + protected void sprint(int intField) { + sprint(String.valueOf(intField)); + } + + /** + * Pretty printing accumulator function for shorts + */ + protected void sprint(short shortField) { + sprint(String.valueOf(shortField)); + } + + /** + * Pretty printing accumulator function for chars + */ + + protected void sprint(char charField) { + sprint(String.valueOf(charField)); + + } + + /** + * Pretty printing accumulator function for longs + */ + + protected void sprint(long longField) { + sprint(String.valueOf(longField)); + } + + /** + * Pretty printing accumulator function for booleans + */ + + protected void sprint(boolean booleanField) { + sprint(String.valueOf(booleanField)); + } + + /** + * Pretty printing accumulator function for doubles + */ + + protected void sprint(double doubleField) { + sprint(String.valueOf(doubleField)); + } + + /** + * Pretty printing accumulator function for floats + */ + + protected void sprint(float floatField) { + sprint(String.valueOf(floatField)); + } + + /** + * Debug printing function. + */ + + protected void dbgPrint() { + Debug.println(debugDump()); + } + + /** + * Debug printing function. + */ + protected void dbgPrint(String s) { + Debug.println(s); + } + + /** + * An introspection based equality predicate for GenericObjects. + *@param that is the other object to test against. + *@return true if the objects are euqal and false otherwise + */ + public boolean equals(Object that) { + if ( that == null ) return false; + if (!this.getClass().equals(that.getClass())) + return false; + Class<?> myclass = this.getClass(); + Class<?> hisclass = that.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } + } else if (g.get(that) == f.get(this)) + return true; + else if (f.get(this) == null) + return false; + else if (g.get(that) == null) + return false; + else if (g.get(that) == null && f.get(this) != null) + return false; + else if (!f.get(this).equals(g.get(that))) + return false; + } catch (IllegalAccessException ex1) { + InternalErrorHandler.handleException(ex1); + } + } + if (myclass.equals(GenericObject.class)) + break; + else { + myclass = myclass.getSuperclass(); + hisclass = hisclass.getSuperclass(); + } + + } + return true; + } + + /** An introspection based predicate matching using a template + * object. Allows for partial match of two protocl Objects. + *@param other the match pattern to test against. The match object + * has to be of the same type (class). Primitive types + * and non-sip fields that are non null are matched for equality. + * Null in any field matches anything. Some book-keeping fields + * are ignored when making the comparison. + */ + + public boolean match(Object other) { + if (other == null) + return true; + if (!this.getClass().equals(other.getClass())) + return false; + GenericObject that = (GenericObject) other; + Class<?> myclass = this.getClass(); + Field[] fields = myclass.getDeclaredFields(); + Class<?> hisclass = other.getClass(); + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } + } else { + Object myObj = f.get(this); + Object hisObj = g.get(that); + if (hisObj != null && myObj == null) + return false; + else if (hisObj == null && myObj != null) + continue; + else if (hisObj == null && myObj == null) + continue; + else if ( + hisObj instanceof java.lang.String + && myObj instanceof java.lang.String) { + if ((((String) hisObj).trim()).equals("")) + continue; + if (((String) myObj) + .compareToIgnoreCase((String) hisObj) + != 0) + return false; + } else if ( + GenericObject.isMySubclass(myObj.getClass()) + && !((GenericObject) myObj).match(hisObj)) + return false; + else if ( + GenericObjectList.isMySubclass(myObj.getClass()) + && !((GenericObjectList) myObj).match(hisObj)) + return false; + + } + } catch (IllegalAccessException ex1) { + InternalErrorHandler.handleException(ex1); + } + } + return true; + } + + /** + * Generic print formatting function: + * Does depth-first descent of the structure and + * recursively prints all non-private objects pointed to + * by this object. + * <bf> + * Warning - the following generic string routine will + * bomb (go into infinite loop) if there are any circularly linked + * structures so if you have these, they had better be private! + * </bf> + * We dont have to worry about such things for our structures + *(we never use circular linked structures). + */ + + public String debugDump() { + stringRepresentation = ""; + Class<?> myclass = getClass(); + sprint(myclass.getName()); + sprint("{"); + Field[] fields = myclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + // avoid nasty recursions... + continue; + } + if (fieldName.compareTo("indentation") == 0) { + // formatting stuff - not relevant here. + continue; + } + sprint(fieldName + ":"); + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + sprint(fname + ":"); + if (fname.compareTo("int") == 0) { + int intfield = f.getInt(this); + sprint(intfield); + } else if (fname.compareTo("short") == 0) { + short shortField = f.getShort(this); + sprint(shortField); + } else if (fname.compareTo("char") == 0) { + char charField = f.getChar(this); + sprint(charField); + } else if (fname.compareTo("long") == 0) { + long longField = f.getLong(this); + sprint(longField); + } else if (fname.compareTo("boolean") == 0) { + boolean booleanField = f.getBoolean(this); + sprint(booleanField); + } else if (fname.compareTo("double") == 0) { + double doubleField = f.getDouble(this); + sprint(doubleField); + } else if (fname.compareTo("float") == 0) { + float floatField = f.getFloat(this); + sprint(floatField); + } + } else if (GenericObject.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObject) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else if ( + GenericObjectList.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObjectList) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else { + // Dont do recursion on things that are not + // of our header type... + if (f.get(this) != null) { + sprint(f.get(this).getClass().getName() + ":"); + } else { + sprint(fieldType.getName() + ":"); + } + + sprint("{"); + if (f.get(this) != null) { + sprint(f.get(this).toString()); + } else { + sprint("<null>"); + } + sprint("}"); + } + } catch (IllegalAccessException ex1) { + continue; // we are accessing a private field... + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + sprint("}"); + return stringRepresentation; + } + + /** + * Formatter with a given starting indentation. + */ + public String debugDump(int indent) { + indentation = indent; + String retval = this.debugDump(); + indentation = 0; + return retval; + } + + + /** + * Get the string encoded version of this object + * @since v1.0 + */ + public abstract String encode(); + + /** + * Put the encoded version of this object in the given StringBuffer. + */ + public StringBuffer encode(StringBuffer buffer) { + return buffer.append(encode()); + } +} diff --git a/java/gov/nist/core/GenericObjectList.java b/java/gov/nist/core/GenericObjectList.java new file mode 100644 index 0000000..30c12e2 --- /dev/null +++ b/java/gov/nist/core/GenericObjectList.java @@ -0,0 +1,473 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.core; + +import java.util.*; +import java.io.Serializable; + +/** + * Implements a homogenous consistent linked list. All the objects in the linked + * list must derive from the same root class. This is a useful constraint to + * place on our code as this property is invariant.The list is created with the + * superclass which can be specified as either a class name or a Class. + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + * + */ +public abstract class GenericObjectList extends LinkedList<GenericObject> implements + Serializable, Cloneable{ + // Useful constants. + protected static final String SEMICOLON = Separators.SEMICOLON; + + protected static final String COLON = Separators.COLON; + + protected static final String COMMA = Separators.COMMA; + + protected static final String SLASH = Separators.SLASH; + + protected static final String SP = Separators.SP; + + protected static final String EQUALS = Separators.EQUALS; + + protected static final String STAR = Separators.STAR; + + protected static final String NEWLINE = Separators.NEWLINE; + + protected static final String RETURN = Separators.RETURN; + + protected static final String LESS_THAN = Separators.LESS_THAN; + + protected static final String GREATER_THAN = Separators.GREATER_THAN; + + protected static final String AT = Separators.AT; + + protected static final String DOT = Separators.DOT; + + protected static final String QUESTION = Separators.QUESTION; + + protected static final String POUND = Separators.POUND; + + protected static final String AND = Separators.AND; + + protected static final String LPAREN = Separators.LPAREN; + + protected static final String RPAREN = Separators.RPAREN; + + protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE; + + protected static final String QUOTE = Separators.QUOTE; + + protected static final String HT = Separators.HT; + + protected static final String PERCENT = Separators.PERCENT; + + protected int indentation; + + protected String listName; // For debugging + + private ListIterator<? extends GenericObject> myListIterator; + + private String stringRep; + + protected Class<?> myClass; + + protected String separator; + + protected String getIndentation() { + char[] chars = new char[indentation]; + java.util.Arrays.fill(chars, ' '); + return new String(chars); + } + + /** + * Return true if this supports reflection based cloning. + */ + protected static boolean isCloneable(Object obj) { + return obj instanceof Cloneable; + } + + public static boolean isMySubclass(Class<?> other) { + return GenericObjectList.class.isAssignableFrom(other); + + } + + /** + * Makes a deep clone of this list. + */ + public Object clone() { + GenericObjectList retval = (GenericObjectList) super.clone(); + for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) { + GenericObject obj = (GenericObject) ((GenericObject) iter.next()) + .clone(); + iter.set(obj); + } + return retval; + } + + + + public void setMyClass(Class cl) { + myClass = cl; + } + + protected GenericObjectList() { + super(); + listName = null; + stringRep = ""; + separator = ";"; + } + + protected GenericObjectList(String lname) { + this(); + listName = lname; + } + + /** + * A Constructor which takes a list name and a class name (for assertion + * checking). + */ + + protected GenericObjectList(String lname, String classname) { + this(lname); + try { + myClass = Class.forName(classname); + } catch (ClassNotFoundException ex) { + InternalErrorHandler.handleException(ex); + } + + } + + /** + * A Constructor which takes a list name and a class (for assertion + * checking). + */ + + protected GenericObjectList(String lname, Class objclass) { + this(lname); + myClass = objclass; + } + + /** + * Traverse the list given a list iterator + */ + protected GenericObject next(ListIterator iterator) { + try { + return (GenericObject) iterator.next(); + } catch (NoSuchElementException ex) { + return null; + } + } + + /** + * This is the default list iterator.This will not handle nested list + * traversal. + */ + protected GenericObject first() { + myListIterator = this.listIterator(0); + try { + return (GenericObject) myListIterator.next(); + } catch (NoSuchElementException ex) { + return null; + } + } + + /** + * Fetch the next object from the list based on the default list iterator + */ + protected GenericObject next() { + if (myListIterator == null) { + myListIterator = this.listIterator(0); + } + try { + return (GenericObject) myListIterator.next(); + } catch (NoSuchElementException ex) { + myListIterator = null; + return null; + } + } + + /** + * Concatenate two compatible header lists, adding the argument to the tail + * end of this list. + * + * @param <var> + * topFlag </var> set to true to add items to top of list + */ + protected void concatenate(GenericObjectList objList) { + concatenate(objList, false); + } + + /** + * Concatenate two compatible header lists, adding the argument either to + * the beginning or the tail end of this list. A type check is done before + * concatenation. + * + * @param <var> + * topFlag </var> set to true to add items to top of list else + * add them to the tail end of the list. + */ + protected void concatenate(GenericObjectList objList, boolean topFlag) { + if (!topFlag) { + this.addAll(objList); + } else { + // add given items to the top end of the list. + this.addAll(0, objList); + } + } + + /** + * string formatting function. + */ + + private void sprint(String s) { + if (s == null) { + stringRep += getIndentation(); + stringRep += "<null>\n"; + return; + } + + if (s.compareTo("}") == 0 || s.compareTo("]") == 0) { + indentation--; + } + stringRep += getIndentation(); + stringRep += s; + stringRep += "\n"; + if (s.compareTo("{") == 0 || s.compareTo("[") == 0) { + indentation++; + } + } + + /** + * Convert this list of headers to a formatted string. + */ + + public String debugDump() { + stringRep = ""; + Object obj = this.first(); + if (obj == null) + return "<null>"; + sprint("listName:"); + sprint(listName); + sprint("{"); + while (obj != null) { + sprint("["); + sprint(((GenericObject) obj).debugDump(this.indentation)); + obj = next(); + sprint("]"); + } + sprint("}"); + return stringRep; + } + + /** + * Convert this list of headers to a string (for printing) with an + * indentation given. + */ + + public String debugDump(int indent) { + int save = indentation; + indentation = indent; + String retval = this.debugDump(); + indentation = save; + return retval; + } + + public void addFirst(GenericObject objToAdd) { + if (myClass == null) { + myClass = objToAdd.getClass(); + } else { + super.addFirst(objToAdd); + } + } + + /** + * Do a merge of the GenericObjects contained in this list with the + * GenericObjects in the mergeList. Note that this does an inplace + * modification of the given list. This does an object by object merge of + * the given objects. + * + * @param mergeList + * is the list of Generic objects that we want to do an object by + * object merge with. Note that no new objects are added to this + * list. + * + */ + + public void mergeObjects(GenericObjectList mergeList) { + + if (mergeList == null) + return; + Iterator it1 = this.listIterator(); + Iterator it2 = mergeList.listIterator(); + while (it1.hasNext()) { + GenericObject outerObj = (GenericObject) it1.next(); + while (it2.hasNext()) { + Object innerObj = it2.next(); + outerObj.merge(innerObj); + } + } + } + + /** + * Encode the list in semicolon separated form. + * + * @return an encoded string containing the objects in this list. + * @since v1.0 + */ + public String encode() { + if (this.isEmpty()) + return ""; + StringBuffer encoding = new StringBuffer(); + ListIterator iterator = this.listIterator(); + if (iterator.hasNext()) { + while (true) { + Object obj = iterator.next(); + if (obj instanceof GenericObject) { + GenericObject gobj = (GenericObject) obj; + encoding.append(gobj.encode()); + } else { + encoding.append(obj.toString()); + } + if (iterator.hasNext()) + encoding.append(separator); + else + break; + } + } + return encoding.toString(); + } + + /** + * Alias for the encode function above. + */ + public String toString() { + return this.encode(); + } + + /** + * Set the separator (for encoding the list) + * + * @since v1.0 + * @param sep + * is the new seperator (default is semicolon) + */ + public void setSeparator(String sep) { + separator = sep; + } + + /** + * Hash code. We never expect to put this in a hash table so return a constant. + */ + public int hashCode() { return 42; } + + /** + * Equality checking predicate. + * + * @param other + * is the object to compare ourselves to. + * @return true if the objects are equal. + */ + public boolean equals(Object other) { + if (other == null ) return false; + if (!this.getClass().equals(other.getClass())) + return false; + GenericObjectList that = (GenericObjectList) other; + if (this.size() != that.size()) + return false; + ListIterator myIterator = this.listIterator(); + while (myIterator.hasNext()) { + Object myobj = myIterator.next(); + ListIterator hisIterator = that.listIterator(); + try { + while (true) { + Object hisobj = hisIterator.next(); + if (myobj.equals(hisobj)) + break; + } + } catch (NoSuchElementException ex) { + return false; + } + } + ListIterator hisIterator = that.listIterator(); + while (hisIterator.hasNext()) { + Object hisobj = hisIterator.next(); + myIterator = this.listIterator(); + try { + while (true) { + Object myobj = myIterator.next(); + if (hisobj.equals(myobj)) + break; + } + } catch (NoSuchElementException ex) { + return false; + } + } + return true; + } + + /** + * Match with a template (return true if we have a superset of the given + * template. This can be used for partial match (template matching of SIP + * objects). Note -- this implementation is not unnecessarily efficient :-) + * + * @param other + * template object to compare against. + */ + + public boolean match(Object other) { + if (!this.getClass().equals(other.getClass())) + return false; + GenericObjectList that = (GenericObjectList) other; + ListIterator hisIterator = that.listIterator(); + outer: while (hisIterator.hasNext()) { + Object hisobj = hisIterator.next(); + Object myobj = null; + ListIterator myIterator = this.listIterator(); + while (myIterator.hasNext()) { + myobj = myIterator.next(); + if (myobj instanceof GenericObject) + System.out.println("Trying to match = " + + ((GenericObject) myobj).encode()); + if (GenericObject.isMySubclass(myobj.getClass()) + && ((GenericObject) myobj).match(hisobj)) + break outer; + else if (GenericObjectList.isMySubclass(myobj.getClass()) + && ((GenericObjectList) myobj).match(hisobj)) + break outer; + } + System.out.println(((GenericObject) hisobj).encode()); + return false; + } + return true; + } +} diff --git a/java/gov/nist/core/Host.java b/java/gov/nist/core/Host.java new file mode 100644 index 0000000..0e154ba --- /dev/null +++ b/java/gov/nist/core/Host.java @@ -0,0 +1,300 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/*************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division(ANTD). * + **************************************************************************/ +package gov.nist.core; + +import java.net.*; + +/* + * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/> + * Network Research Team (http://www-r2.u-strasbg.fr))<br/> + * Louis Pasteur University - Strasbourg - France<br/> + * + * Frank Feif reported a bug. + * + * + */ +/** + * Stores hostname. + * @version 1.2 + * + * @author M. Ranganathan + * @author Emil Ivov <emil_ivov@yahoo.com> IPV6 Support. <br/> + * + * + * + + * Marc Bednarek <bednarek@nist.gov> (Bugfixes).<br/> + * + */ +public class Host extends GenericObject { + + /** + * Determines whether or not we should tolerate and strip address scope + * zones from IPv6 addresses. Address scope zones are sometimes returned + * at the end of IPv6 addresses generated by InetAddress.getHostAddress(). + * They are however not part of the SIP semantics so basically this method + * determines whether or not the parser should be stripping them (as + * opposed simply being blunt and throwing an exception). + */ + private boolean stripAddressScopeZones = false; + + private static final long serialVersionUID = -7233564517978323344L; + protected static final int HOSTNAME = 1; + protected static final int IPV4ADDRESS = 2; + protected static final int IPV6ADDRESS = 3; + + /** hostName field + */ + protected String hostname; + + /** address field + */ + + protected int addressType; + + private InetAddress inetAddress; + + /** default constructor + */ + public Host() { + addressType = HOSTNAME; + + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + } + + /** Constructor given host name or IP address. + */ + public Host(String hostName) throws IllegalArgumentException { + if (hostName == null) + throw new IllegalArgumentException("null host name"); + + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + + setHost(hostName, IPV4ADDRESS); + } + + /** constructor + * @param name String to set + * @param addrType int to set + */ + public Host(String name, int addrType) { + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + + setHost(name, addrType); + } + + /** + * Return the host name in encoded form. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (addressType == IPV6ADDRESS && !isIPv6Reference(hostname)) { + buffer.append('[').append(hostname).append(']'); + } else { + buffer.append(hostname); + } + return buffer; + } + + /** + * Compare for equality of hosts. + * Host names are compared by textual equality. No dns lookup + * is performed. + * @param obj Object to set + * @return boolean + */ + public boolean equals(Object obj) { + if ( obj == null ) return false; + if (!this.getClass().equals(obj.getClass())) { + return false; + } + Host otherHost = (Host) obj; + return otherHost.hostname.equals(hostname); + + } + + /** get the HostName field + * @return String + */ + public String getHostname() { + return hostname; + } + + /** get the Address field + * @return String + */ + public String getAddress() { + return hostname; + } + + /** + * Convenience function to get the raw IP destination address + * of a SIP message as a String. + * @return String + */ + public String getIpAddress() { + String rawIpAddress = null; + if (hostname == null) + return null; + if (addressType == HOSTNAME) { + try { + if (inetAddress == null) + inetAddress = InetAddress.getByName(hostname); + rawIpAddress = inetAddress.getHostAddress(); + } catch (UnknownHostException ex) { + dbgPrint("Could not resolve hostname " + ex); + } + } else { + rawIpAddress = hostname; + } + return rawIpAddress; + } + + /** + * Set the hostname member. + * @param h String to set + */ + public void setHostname(String h) { + setHost(h, HOSTNAME); + } + + /** Set the IP Address. + *@param address is the address string to set. + */ + public void setHostAddress(String address) { + setHost(address, IPV4ADDRESS); + } + + /** + * Sets the host address or name of this object. + * + * @param host that host address/name value + * @param type determines whether host is an address or a host name + */ + private void setHost(String host, int type){ + //set inetAddress to null so that it would be reinited + //upon next call to getInetAddress() + inetAddress = null; + + if (isIPv6Address(host)) + addressType = IPV6ADDRESS; + else + addressType = type; + + // Null check bug fix sent in by jpaulo@ipb.pt + if (host != null){ + hostname = host.trim(); + + //if this is an FQDN, make it lowercase to simplify processing + if(addressType == HOSTNAME) + hostname = hostname.toLowerCase(); + + //remove address scope zones if this is an IPv6 address as they + //are not allowed by the RFC + int zoneStart = -1; + if(addressType == IPV6ADDRESS + && stripAddressScopeZones + && (zoneStart = hostname.indexOf('%'))!= -1){ + + hostname = hostname.substring(0, zoneStart); + } + } + } + + /** + * Set the address member + * @param address address String to set + */ + public void setAddress(String address) { + this.setHostAddress(address); + } + + /** Return true if the address is a DNS host name + * (and not an IPV4 address) + *@return true if the hostname is a DNS name + */ + public boolean isHostname() { + return addressType == HOSTNAME; + } + + /** Return true if the address is a DNS host name + * (and not an IPV4 address) + *@return true if the hostname is host address. + */ + public boolean isIPAddress() { + return addressType != HOSTNAME; + } + + /** Get the inet address from this host. + * Caches the inet address returned from dns lookup to avoid + * lookup delays. + * + *@throws UnkownHostexception when the host name cannot be resolved. + */ + public InetAddress getInetAddress() throws java.net.UnknownHostException { + if (hostname == null) + return null; + if (inetAddress != null) + return inetAddress; + inetAddress = InetAddress.getByName(hostname); + return inetAddress; + + } + + //----- IPv6 + /** + * Verifies whether the <code>address</code> could + * be an IPv6 address + */ + private boolean isIPv6Address(String address) { + return (address != null && address.indexOf(':') != -1); + } + + /** + * Verifies whether the ipv6reference, i.e. whether it enclosed in + * square brackets + */ + public static boolean isIPv6Reference(String address) { + return address.charAt(0) == '[' + && address.charAt(address.length() - 1) == ']'; + } + + @Override + public int hashCode() { + return this.getHostname().hashCode(); + + } +} diff --git a/java/gov/nist/core/HostNameParser.java b/java/gov/nist/core/HostNameParser.java new file mode 100644 index 0000000..5feddd1 --- /dev/null +++ b/java/gov/nist/core/HostNameParser.java @@ -0,0 +1,342 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * + * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/> + * Network Research Team (http://www-r2.u-strasbg.fr))<br/> + * Louis Pasteur University - Strasbourg - France<br/> + * + *Bug fixes for corner cases were contributed by Thomas Froment. + */ +package gov.nist.core; + +// BEGIN android-deleted +//import gov.nist.javax.sdp.parser.Lexer; +// END android-deleted + +import java.text.ParseException; + +/** + * Parser for host names. + * + *@version 1.2 + * + *@author M. Ranganathan + */ + +public class HostNameParser extends ParserCore { +// BEGIN android-added + private static LexerCore Lexer; +// END android-added + + /** + * Determines whether or not we should tolerate and strip address scope + * zones from IPv6 addresses. Address scope zones are sometimes returned + * at the end of IPv6 addresses generated by InetAddress.getHostAddress(). + * They are however not part of the SIP semantics so basically this method + * determines whether or not the parser should be stripping them (as + * opposed simply being blunt and throwing an exception). + */ + private boolean stripAddressScopeZones = false; + + public HostNameParser(String hname) { + this.lexer = new LexerCore("charLexer", hname); + + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + } + + /** + * The lexer is initialized with the buffer. + */ + public HostNameParser(LexerCore lexer) { + this.lexer = lexer; + lexer.selectLexer("charLexer"); + + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + } + + private static final char[] VALID_DOMAIN_LABEL_CHAR = + new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, '-', '.'}; + protected void consumeDomainLabel() throws ParseException { + if (debug) + dbg_enter("domainLabel"); + try { + lexer.consumeValidChars(VALID_DOMAIN_LABEL_CHAR); + } finally { + if (debug) + dbg_leave("domainLabel"); + } + } + + protected String ipv6Reference() throws ParseException { + StringBuffer retval = new StringBuffer(); + if (debug) + dbg_enter("ipv6Reference"); + + try { + + if(stripAddressScopeZones){ + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + //'%' is ipv6 address scope zone. see detail at + //java.sun.com/j2se/1.5.0/docs/api/java/net/Inet6Address.html + if (LexerCore.isHexDigit(la) || la == '.' || la == ':' + || la == '[' ) { + lexer.consume(1); + retval.append(la); + } else if (la == ']') { + lexer.consume(1); + retval.append(la); + return retval.toString(); + } else if (la == '%'){ + //we need to strip the address scope zone. + lexer.consume(1); + + String rest = lexer.getRest(); + + if(rest == null || rest.length() == 0){ + //head for the parse exception + break; + } + + //we strip everything until either the end of the string + //or a closing square bracket (]) + int stripLen = rest.indexOf(']'); + + if (stripLen == -1){ + //no square bracket -> not a valid ipv6 reference + break; + } + + lexer.consume(stripLen+1); + retval.append("]"); + return retval.toString(); + + } else + break; + } + } + else + { + while (lexer.hasMoreChars()) + { + char la = lexer.lookAhead(0); + if (LexerCore.isHexDigit(la) || la == '.' + || la == ':' || la == '[') { + lexer.consume(1); + retval.append(la); + } else if (la == ']') { + lexer.consume(1); + retval.append(la); + return retval.toString(); + } else + break; + } + } + + throw new ParseException( + lexer.getBuffer() + ": Illegal Host name ", + lexer.getPtr()); + } finally { + if (debug) + dbg_leave("ipv6Reference"); + } + } + + public Host host() throws ParseException { + if (debug) + dbg_enter("host"); + try { + String hostname; + + //IPv6 referene + if (lexer.lookAhead(0) == '[') { + hostname = ipv6Reference(); + } + //IPv6 address (i.e. missing square brackets) + else if( isIPv6Address(lexer.getRest()) ) + { + int startPtr = lexer.getPtr(); + lexer.consumeValidChars( + new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, ':'}); + hostname + = new StringBuffer("[").append( + lexer.getBuffer().substring(startPtr, lexer.getPtr())) + .append("]").toString(); + } + //IPv4 address or hostname + else { + int startPtr = lexer.getPtr(); + consumeDomainLabel(); + hostname = lexer.getBuffer().substring(startPtr, lexer.getPtr()); + } + + if (hostname.length() == 0) + throw new ParseException( + lexer.getBuffer() + ": Missing host name", + lexer.getPtr()); + else + return new Host(hostname); + } finally { + if (debug) + dbg_leave("host"); + } + } + + /** + * Tries to determine whether the address in <tt>uriHeader</tt> could be + * an IPv6 address by counting the number of colons that appear in it. + * + * @param uriHeader the string (supposedly the value of a URI header) that + * we have received for parsing. + * + * @return true if the host part of <tt>uriHeader</tt> could be an IPv6 + * address (i.e. contains at least two colons) and false otherwise. + */ + private boolean isIPv6Address(String uriHeader) + { + // approximately detect the end the host part. + //first check if we have an uri param + int hostEnd = uriHeader.indexOf(Lexer.QUESTION); + + //if not or if it appears after a semi-colon then the end of the + //address would be a header param. + int semiColonIndex = uriHeader.indexOf(Lexer.SEMICOLON); + if ( hostEnd == -1 + || (semiColonIndex!= -1 && hostEnd > semiColonIndex) ) + hostEnd = semiColonIndex; + + //if there was no header param either the address + //continues until the end of the string + if ( hostEnd == -1 ) + hostEnd = uriHeader.length(); + + //extract the address + String host = uriHeader.substring(0, hostEnd); + + int firstColonIndex = host.indexOf(Lexer.COLON); + + if(firstColonIndex == -1) + return false; + + int secondColonIndex = host.indexOf(Lexer.COLON, firstColonIndex + 1); + + if(secondColonIndex == -1) + return false; + + return true; + } + /** + * Parses a host:port string + * + * @param allowWS - whether whitespace is allowed around ':', only true for Via headers + * @return + * @throws ParseException + */ + public HostPort hostPort( boolean allowWS ) throws ParseException { + if (debug) + dbg_enter("hostPort"); + try { + Host host = this.host(); + HostPort hp = new HostPort(); + hp.setHost(host); + // Has a port? + if (allowWS) lexer.SPorHT(); // white space before ":port" should be accepted + if (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + switch (la) + { + case ':': + lexer.consume(1); + if (allowWS) lexer.SPorHT(); // white space before port number should be accepted + try { + String port = lexer.number(); + hp.setPort(Integer.parseInt(port)); + } catch (NumberFormatException nfe) { + throw new ParseException( + lexer.getBuffer() + " :Error parsing port ", + lexer.getPtr()); + } + break; + + case ',': // allowed in case of multi-headers, e.g. Route + // Could check that current header is a multi hdr + + case ';': // OK, can appear in URIs (parameters) + case '?': // same, header parameters + case '>': // OK, can appear in headers + case ' ': // OK, allow whitespace + case '\t': + case '\r': + case '\n': + case '/': // e.g. http://[::1]/xyz.html + break; + case '%': + if(stripAddressScopeZones){ + break;//OK,allow IPv6 address scope zone + } + + default: + if (!allowWS) { + throw new ParseException( lexer.getBuffer() + + " Illegal character in hostname:" + lexer.lookAhead(0), + lexer.getPtr() ); + } + } + } + return hp; + } finally { + if (debug) + dbg_leave("hostPort"); + } + } + + public static void main(String args[]) throws ParseException { + String hostNames[] = + { + "foo.bar.com:1234", + "proxima.chaplin.bt.co.uk", + "129.6.55.181:2345", + ":1234", + "foo.bar.com: 1234", + "foo.bar.com : 1234 ", + "MIK_S:1234" + }; + + for (int i = 0; i < hostNames.length; i++) { + try { + HostNameParser hnp = new HostNameParser(hostNames[i]); + HostPort hp = hnp.hostPort(true); + System.out.println("["+hp.encode()+"]"); + } catch (ParseException ex) { + System.out.println("exception text = " + ex.getMessage()); + } + } + + } +} diff --git a/java/gov/nist/core/HostPort.java b/java/gov/nist/core/HostPort.java new file mode 100644 index 0000000..b9be098 --- /dev/null +++ b/java/gov/nist/core/HostPort.java @@ -0,0 +1,171 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.core; +import java.net.*; + +/** +* Holds the hostname:port. +* +*@version 1.2 +* +*@author M. Ranganathan +* +* +* +*/ +public final class HostPort extends GenericObject { + + + private static final long serialVersionUID = -7103412227431884523L; + + // host / ipv4/ ipv6/ + /** host field + */ + protected Host host; + + /** port field + * + */ + protected int port; + + /** Default constructor + */ + public HostPort() { + + host = null; + port = -1; // marker for not set. + } + + /** + * Encode this hostport into its string representation. + * Note that this could be different from the string that has + * been parsed if something has been edited. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + host.encode(buffer); + if (port != -1) + buffer.append(COLON).append(port); + return buffer; + } + + /** returns true if the two objects are equals, false otherwise. + * @param other Object to set + * @return boolean + */ + public boolean equals(Object other) { + if (other == null) return false; + if (getClass () != other.getClass ()) { + return false; + } + HostPort that = (HostPort) other; + return port == that.port && host.equals(that.host); + } + + /** get the Host field + * @return host field + */ + public Host getHost() { + return host; + } + + /** get the port field + * @return int + */ + public int getPort() { + return port; + } + + /** + * Returns boolean value indicating if Header has port + * @return boolean value indicating if Header has port + */ + public boolean hasPort() { + return port != -1; + } + + /** remove port. + */ + public void removePort() { + port = -1; + } + + /** + * Set the host member + * @param h Host to set + */ + public void setHost(Host h) { + host = h; + } + + /** + * Set the port member + * @param p int to set + */ + public void setPort(int p) { + port = p; + } + + /** Return the internet address corresponding to the host. + *@throws java.net.UnkownHostException if host name cannot be resolved. + *@return the inet address for the host. + */ + public InetAddress getInetAddress() throws java.net.UnknownHostException { + if (host == null) + return null; + else + return host.getInetAddress(); + } + + public void merge(Object mergeObject) { + super.merge (mergeObject); + if (port == -1) + port = ((HostPort) mergeObject).port; + } + + public Object clone() { + HostPort retval = (HostPort) super.clone(); + if (this.host != null) + retval.host = (Host) this.host.clone(); + return retval; + } + + public String toString() { + return this.encode(); + } + + @Override + public int hashCode() { + return this.host.hashCode() + this.port; + } +} diff --git a/java/gov/nist/core/InternalErrorHandler.java b/java/gov/nist/core/InternalErrorHandler.java new file mode 100644 index 0000000..36f0a84 --- /dev/null +++ b/java/gov/nist/core/InternalErrorHandler.java @@ -0,0 +1,78 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.core; +/** +* Handle Internal error failures and print a stack trace (for debugging). +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public class InternalErrorHandler { + + public static void handleException(Exception ex) throws RuntimeException { + System.err.println ("Unexpected internal error FIXME!! " + ex.getMessage()); + ex.printStackTrace(); + throw new RuntimeException("Unexpected internal error FIXME!! " + ex.getMessage(), ex); + + } + /** + * Handle an unexpected exception. + */ + public static void handleException(Exception ex, StackLogger stackLogger) { + System.err.println ("Unexpected internal error FIXME!! " + ex.getMessage()); + stackLogger.logError("UNEXPECTED INTERNAL ERROR FIXME " + ex.getMessage()); + ex.printStackTrace(); + stackLogger.logException(ex); + throw new RuntimeException("Unexpected internal error FIXME!! " + ex.getMessage(), ex); + + } + /** + * Handle an unexpected condition (and print the error code). + */ + + public static void handleException(String emsg) { + new Exception().printStackTrace(); + System.err.println("Unexepcted INTERNAL ERROR FIXME!!"); + System.err.println(emsg); + throw new RuntimeException(emsg); + + } + + public static void handleException(String emsg, StackLogger stackLogger) { + stackLogger.logStackTrace(); + stackLogger.logError("Unexepcted INTERNAL ERROR FIXME!!"); + stackLogger.logFatalError(emsg); + throw new RuntimeException(emsg); + + } +} diff --git a/java/gov/nist/core/LexerCore.java b/java/gov/nist/core/LexerCore.java new file mode 100644 index 0000000..a05381f --- /dev/null +++ b/java/gov/nist/core/LexerCore.java @@ -0,0 +1,761 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +import java.text.ParseException; +import java.util.Hashtable; + +/** A lexical analyzer that is used by all parsers in our implementation. + * + *@version 1.2 + *@since 1.1 + * + *@author M. Ranganathan + */ +public class LexerCore extends StringTokenizer { + + // IMPORTANT - All keyword matches should be between START and END + public static final int START = 2048; + public static final int END = START + 2048; + // IMPORTANT -- This should be < END + public static final int ID = END - 1; + public static final int SAFE = END - 2; + // Individial token classes. + public static final int WHITESPACE = END + 1; + public static final int DIGIT = END + 2; + public static final int ALPHA = END + 3; + public static final int BACKSLASH = (int) '\\'; + public static final int QUOTE = (int) '\''; + public static final int AT = (int) '@'; + public static final int SP = (int) ' '; + public static final int HT = (int) '\t'; + public static final int COLON = (int) ':'; + public static final int STAR = (int) '*'; + public static final int DOLLAR = (int) '$'; + public static final int PLUS = (int) '+'; + public static final int POUND = (int) '#'; + public static final int MINUS = (int) '-'; + public static final int DOUBLEQUOTE = (int) '\"'; + public static final int TILDE = (int) '~'; + public static final int BACK_QUOTE = (int) '`'; + public static final int NULL = (int) '\0'; + public static final int EQUALS = (int) '='; + public static final int SEMICOLON = (int) ';'; + public static final int SLASH = (int) '/'; + public static final int L_SQUARE_BRACKET = (int) '['; + public static final int R_SQUARE_BRACKET = (int) ']'; + public static final int R_CURLY = (int) '}'; + public static final int L_CURLY = (int) '{'; + public static final int HAT = (int) '^'; + public static final int BAR = (int) '|'; + public static final int DOT = (int) '.'; + public static final int EXCLAMATION = (int) '!'; + public static final int LPAREN = (int) '('; + public static final int RPAREN = (int) ')'; + public static final int GREATER_THAN = (int) '>'; + public static final int LESS_THAN = (int) '<'; + public static final int PERCENT = (int) '%'; + public static final int QUESTION = (int) '?'; + public static final int AND = (int) '&'; + public static final int UNDERSCORE = (int) '_'; + + protected static final Hashtable globalSymbolTable; + protected static final Hashtable lexerTables; + protected Hashtable currentLexer; + protected String currentLexerName; + protected Token currentMatch; + + static { + globalSymbolTable = new Hashtable(); + lexerTables = new Hashtable(); + } + + protected void addKeyword(String name, int value) { + // System.out.println("addKeyword " + name + " value = " + value); + // new Exception().printStackTrace(); + Integer val = Integer.valueOf(value); + currentLexer.put(name, val); + if (!globalSymbolTable.containsKey(val)) + globalSymbolTable.put(val, name); + } + + public String lookupToken(int value) { + if (value > START) { + return (String) globalSymbolTable.get(Integer.valueOf(value)); + } else { + Character ch = Character.valueOf((char) value); + return ch.toString(); + } + } + + protected Hashtable addLexer(String lexerName) { + currentLexer = (Hashtable) lexerTables.get(lexerName); + if (currentLexer == null) { + currentLexer = new Hashtable(); + lexerTables.put(lexerName, currentLexer); + } + return currentLexer; + } + + //public abstract void selectLexer(String lexerName); + + public void selectLexer(String lexerName) { + this.currentLexerName = lexerName; + } + + protected LexerCore() { + this.currentLexer = new Hashtable(); + this.currentLexerName = "charLexer"; + } + + /** Initialize the lexer with a buffer. + */ + public LexerCore(String lexerName, String buffer) { + super(buffer); + this.currentLexerName = lexerName; + } + + /** Peek the next id but dont move the buffer pointer forward. + */ + + public String peekNextId() { + int oldPtr = ptr; + String retval = ttoken(); + savedPtr = ptr; + ptr = oldPtr; + return retval; + } + + /** Get the next id. + */ + public String getNextId() { + return ttoken(); + } + + // call this after you call match + public Token getNextToken() { + return this.currentMatch; + + } + + /** Look ahead for one token. + */ + public Token peekNextToken() throws ParseException { + return (Token) peekNextToken(1)[0]; + } + + public Token[] peekNextToken(int ntokens) throws ParseException { + int old = ptr; + Token[] retval = new Token[ntokens]; + for (int i = 0; i < ntokens; i++) { + Token tok = new Token(); + if (startsId()) { + String id = ttoken(); + tok.tokenValue = id; + String idUppercase = id.toUpperCase(); + if (currentLexer.containsKey(idUppercase)) { + Integer type = (Integer) currentLexer.get(idUppercase); + tok.tokenType = type.intValue(); + } else + tok.tokenType = ID; + } else { + char nextChar = getNextChar(); + tok.tokenValue = String.valueOf(nextChar); + if (isAlpha(nextChar)) { + tok.tokenType = ALPHA; + } else if (isDigit(nextChar)) { + tok.tokenType = DIGIT; + } else + tok.tokenType = (int) nextChar; + } + retval[i] = tok; + } + savedPtr = ptr; + ptr = old; + return retval; + } + + /** Match the given token or throw an exception if no such token + * can be matched. + */ + public Token match(int tok) throws ParseException { + if (Debug.parserDebug) { + Debug.println("match " + tok); + } + if (tok > START && tok < END) { + if (tok == ID) { + // Generic ID sought. + if (!startsId()) + throw new ParseException(buffer + "\nID expected", ptr); + String id = getNextId(); + this.currentMatch = new Token(); + this.currentMatch.tokenValue = id; + this.currentMatch.tokenType = ID; + } else if (tok == SAFE) { + if (!startsSafeToken()) + throw new ParseException(buffer + "\nID expected", ptr); + String id = ttokenSafe(); + this.currentMatch = new Token(); + this.currentMatch.tokenValue = id; + this.currentMatch.tokenType = SAFE; + } else { + String nexttok = getNextId(); + Integer cur = (Integer) currentLexer.get(nexttok.toUpperCase()); + + if (cur == null || cur.intValue() != tok) + throw new ParseException( + buffer + "\nUnexpected Token : " + nexttok, + ptr); + this.currentMatch = new Token(); + this.currentMatch.tokenValue = nexttok; + this.currentMatch.tokenType = tok; + } + } else if (tok > END) { + // Character classes. + char next = lookAhead(0); + if (tok == DIGIT) { + if (!isDigit(next)) + throw new ParseException(buffer + "\nExpecting DIGIT", ptr); + this.currentMatch = new Token(); + this.currentMatch.tokenValue = + String.valueOf(next); + this.currentMatch.tokenType = tok; + consume(1); + + } else if (tok == ALPHA) { + if (!isAlpha(next)) + throw new ParseException(buffer + "\nExpecting ALPHA", ptr); + this.currentMatch = new Token(); + this.currentMatch.tokenValue = + String.valueOf(next); + this.currentMatch.tokenType = tok; + consume(1); + + } + + } else { + // This is a direct character spec. + char ch = (char) tok; + char next = lookAhead(0); + if (next == ch) { + /*this.currentMatch = new Token(); + this.currentMatch.tokenValue = + String.valueOf(ch); + this.currentMatch.tokenType = tok;*/ + consume(1); + } else + throw new ParseException( + buffer + "\nExpecting >>>" + ch + "<<< got >>>" + + next + "<<<", ptr); + } + return this.currentMatch; + } + + public void SPorHT() { + try { + char c = lookAhead(0); + while (c == ' ' || c == '\t') { + consume(1); + c = lookAhead(0); + } + } catch (ParseException ex) { + // Ignore + } + } + + /** + * JvB: utility function added to validate tokens + * + * @see RFC3261 section 25.1: + * token = 1*(alphanum / "-" / "." / "!" / "%" / "*" + / "_" / "+" / "`" / "'" / "~" ) + + * @param c - character to check + * @return true iff character c is a valid token character as per RFC3261 + */ + public static final boolean isTokenChar( char c ) { + if ( isAlphaDigit(c) ) return true; + else switch (c) + { + case '-': + case '.': + case '!': + case '%': + case '*': + case '_': + case '+': + case '`': + case '\'': + case '~': + return true; + default: + return false; + } + } + + + public boolean startsId() { + try { + char nextChar = lookAhead(0); + return isTokenChar(nextChar); + } catch (ParseException ex) { + return false; + } + } + + public boolean startsSafeToken() { + try { + char nextChar = lookAhead(0); + if (isAlphaDigit(nextChar)) { + return true; + } + else { + switch (nextChar) { + case '_': + case '+': + case '-': + case '!': + case '`': + case '\'': + case '.': + case '/': + case '}': + case '{': + case ']': + case '[': + case '^': + case '|': + case '~': + case '%': // bug fix by Bruno Konik, JvB copied here + case '#': + case '@': + case '$': + case ':': + case ';': + case '?': + case '\"': + case '*': + case '=': // Issue 155 on java.net + return true; + default: + return false; + } + } + } catch (ParseException ex) { + return false; + } + } + + public String ttoken() { + int startIdx = ptr; + try { + while (hasMoreChars()) { + char nextChar = lookAhead(0); + if ( isTokenChar(nextChar) ) { + consume(1); + } else { + break; + } + } + return buffer.substring(startIdx, ptr); + } catch (ParseException ex) { + return null; + } + } + + /* JvB: unreferenced + public String ttokenAllowSpace() { + int startIdx = ptr; + try { + while (hasMoreChars()) { + char nextChar = lookAhead(0); + if (isAlphaDigit(nextChar)) { + consume(1); + } + else { + boolean isValidChar = false; + switch (nextChar) { + case '_': + case '+': + case '-': + case '!': + case '`': + case '\'': + case '~': + case '%': // bug fix by Bruno Konik, JvB copied here + case '.': + case ' ': + case '\t': + case '*': + isValidChar = true; + } + if (isValidChar) { + consume(1); + } + else { + break; + } + } + + } + return buffer.substring(startIdx, ptr); + } catch (ParseException ex) { + return null; + } + }*/ + + public String ttokenSafe() { + int startIdx = ptr; + try { + while (hasMoreChars()) { + char nextChar = lookAhead(0); + if (isAlphaDigit(nextChar)) { + consume(1); + } + else { + boolean isValidChar = false; + switch (nextChar) { + case '_': + case '+': + case '-': + case '!': + case '`': + case '\'': + case '.': + case '/': + case '}': + case '{': + case ']': + case '[': + case '^': + case '|': + case '~': + case '%': // bug fix by Bruno Konik, JvB copied here + case '#': + case '@': + case '$': + case ':': + case ';': + case '?': + case '\"': + case '*': + isValidChar = true; + } + if (isValidChar) { + consume(1); + } + else { + break; + } + } + } + return buffer.substring(startIdx, ptr); + } catch (ParseException ex) { + return null; + } + } + + static final char ALPHA_VALID_CHARS = Character.MAX_VALUE; + static final char DIGIT_VALID_CHARS = Character.MAX_VALUE - 1; + static final char ALPHADIGIT_VALID_CHARS = Character.MAX_VALUE - 2; + public void consumeValidChars(char[] validChars) { + int validCharsLength = validChars.length; + try { + while (hasMoreChars()) { + char nextChar = lookAhead(0); + boolean isValid = false; + for (int i = 0; i < validCharsLength; i++) { + char validChar = validChars[i]; + switch(validChar) { + case ALPHA_VALID_CHARS: + isValid = isAlpha(nextChar); + break; + case DIGIT_VALID_CHARS: + isValid = isDigit(nextChar); + break; + case ALPHADIGIT_VALID_CHARS: + isValid = isAlphaDigit(nextChar); + break; + default: + isValid = nextChar == validChar; + } + if (isValid) { + break; + } + } + if (isValid) { + consume(1); + } + else { + break; + } + } + } catch (ParseException ex) { + + } + } + + /** Parse a comment string cursor is at a ". Leave cursor at closing " + *@return the substring containing the quoted string excluding the + * closing quote. + */ + public String quotedString() throws ParseException { + int startIdx = ptr + 1; + if (lookAhead(0) != '\"') + return null; + consume(1); + while (true) { + char next = getNextChar(); + if (next == '\"') { + // Got to the terminating quote. + break; + } else if (next == '\0') { + throw new ParseException( + this.buffer + " :unexpected EOL", + this.ptr); + } else if (next == '\\') { + consume(1); + } + } + return buffer.substring(startIdx, ptr - 1); + } + + /** Parse a comment string cursor is at a "(". Leave cursor at ) + *@return the substring containing the comment excluding the + * closing brace. + */ + public String comment() throws ParseException { + StringBuffer retval = new StringBuffer(); + if (lookAhead(0) != '(') + return null; + consume(1); + while (true) { + char next = getNextChar(); + if (next == ')') { + break; + } else if (next == '\0') { + throw new ParseException( + this.buffer + " :unexpected EOL", + this.ptr); + } else if (next == '\\') { + retval.append(next); + next = getNextChar(); + if (next == '\0') + throw new ParseException( + this.buffer + " : unexpected EOL", + this.ptr); + retval.append(next); + } else { + retval.append(next); + } + } + return retval.toString(); + } + + /** Return a substring containing no semicolons. + *@return a substring containing no semicolons. + */ + public String byteStringNoSemicolon() { + StringBuffer retval = new StringBuffer(); + try { + while (true) { + char next = lookAhead(0); + // bug fix from Ben Evans. + if (next == '\0' || next == '\n' || next == ';' || next == ',' ) { + break; + } else { + consume(1); + retval.append(next); + } + } + } catch (ParseException ex) { + return retval.toString(); + } + return retval.toString(); + } + + /** + * Scan until you see a slash or an EOL. + * + * @return substring containing no slash. + */ + public String byteStringNoSlash() { + StringBuffer retval = new StringBuffer(); + try { + while (true) { + char next = lookAhead(0); + // bug fix from Ben Evans. + if (next == '\0' || next == '\n' || next == '/' ) { + break; + } else { + consume(1); + retval.append(next); + } + } + } catch (ParseException ex) { + return retval.toString(); + } + return retval.toString(); + } + + /** Return a substring containing no commas + *@return a substring containing no commas. + */ + + public String byteStringNoComma() { + StringBuffer retval = new StringBuffer(); + try { + while (true) { + char next = lookAhead(0); + if (next == '\n' || next == ',') { + break; + } else { + consume(1); + retval.append(next); + } + } + } catch (ParseException ex) { + } + return retval.toString(); + } + + public static String charAsString(char ch) { + return String.valueOf(ch); + } + + /** Lookahead in the inputBuffer for n chars and return as a string. + * Do not consume the input. + */ + public String charAsString(int nchars) { + return buffer.substring(ptr, ptr + nchars); + } + + /** Get and consume the next number. + *@return a substring corresponding to a number + *(i.e. sequence of digits). + */ + public String number() throws ParseException { + + int startIdx = ptr; + try { + if (!isDigit(lookAhead(0))) { + throw new ParseException( + buffer + ": Unexpected token at " + lookAhead(0), + ptr); + } + consume(1); + while (true) { + char next = lookAhead(0); + if (isDigit(next)) { + consume(1); + } else + break; + } + return buffer.substring(startIdx, ptr); + } catch (ParseException ex) { + return buffer.substring(startIdx, ptr); + } + } + + /** Mark the position for backtracking. + *@return the current location of the pointer. + */ + public int markInputPosition() { + return ptr; + } + + /** Rewind the input ptr to the marked position. + *@param position - the position to rewind the parser to. + */ + public void rewindInputPosition(int position) { + this.ptr = position; + } + + /** Get the rest of the String + * @return rest of the buffer. + */ + public String getRest() { + if (ptr >= buffer.length()) + return null; + else + return buffer.substring(ptr); + } + + /** Get the sub-String until the character is encountered + * @param c the character to match + * @return the substring that matches. + */ + public String getString(char c) throws ParseException { + StringBuffer retval = new StringBuffer(); + while (true) { + char next = lookAhead(0); + //System.out.println(" next = [" + next + ']' + "ptr = " + ptr); + //System.out.println(next == '\0'); + + if (next == '\0') { + throw new ParseException( + this.buffer + "unexpected EOL", + this.ptr); + } else if (next == c) { + consume(1); + break; + } else if (next == '\\') { + consume(1); + char nextchar = lookAhead(0); + if (nextchar == '\0') { + throw new ParseException( + this.buffer + "unexpected EOL", + this.ptr); + } else { + consume(1); + retval.append(nextchar); + } + } else { + consume(1); + retval.append(next); + } + } + return retval.toString(); + } + + /** Get the read pointer. + */ + public int getPtr() { + return this.ptr; + } + + /** Get the buffer. + */ + public String getBuffer() { + return this.buffer; + } + + /** Create a parse exception. + */ + public ParseException createParseException() { + return new ParseException(this.buffer, this.ptr); + } +} diff --git a/java/gov/nist/core/LogLevels.java b/java/gov/nist/core/LogLevels.java new file mode 100644 index 0000000..88beb7f --- /dev/null +++ b/java/gov/nist/core/LogLevels.java @@ -0,0 +1,18 @@ +package gov.nist.core; + +public interface LogLevels { + /* + * Each of these levels must be mapped internally to logically equivalent + * logging levels in your logger. + */ + public static final int TRACE_NONE = 0; + public static final int TRACE_FATAL = 2; + public static final int TRACE_ERROR = 4; + public static final int TRACE_WARN = 8; + public static final int TRACE_INFO = 16; + public static final int TRACE_DEBUG = 32; + public static final int TRACE_TRACE = 64; + public static final int TRACE_MESSAGES = TRACE_INFO; + public static final int TRACE_EXCEPTION = TRACE_ERROR; + +} diff --git a/java/gov/nist/core/LogWriter.java b/java/gov/nist/core/LogWriter.java new file mode 100644 index 0000000..2f7994a --- /dev/null +++ b/java/gov/nist/core/LogWriter.java @@ -0,0 +1,593 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +/*************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ***************************************************************************/ +package gov.nist.core; + +import java.io.*; +import java.util.Properties; + +// BEGIN ANDROID-added +// TODO: this class should be replaced by android logging mechanism. +public class LogWriter implements StackLogger { + private static final String TAG = "SIP_STACK"; + + private boolean mEnabled = true; + + public void logStackTrace() { + // TODO + } + + public void logStackTrace(int traceLevel) { + // TODO + } + + public int getLineCount() { + return 0; + } + + public void logException(Throwable ex) { + //Log.e(TAG, "", ex); + } + public void logDebug(String message) { + //Log.d(TAG, message); + } + public void logTrace(String message) { + //Log.d(TAG, message); + } + public void logFatalError(String message) { + //Log.e(TAG, message); + } + public void logError(String message) { + //Log.e(TAG, message); + } + public boolean isLoggingEnabled() { + return mEnabled; + } + public boolean isLoggingEnabled(int logLevel) { + // TODO + return mEnabled; + } + public void logError(String message, Exception ex) { + //Log.e(TAG, message, ex); + } + public void logWarning(String string) { + //Log.w(TAG, string); + } + public void logInfo(String string) { + //Log.i(TAG, string); + } + + public void disableLogging() { + mEnabled = false; + } + + public void enableLogging() { + mEnabled = true; + } + + public void setBuildTimeStamp(String buildTimeStamp) { + } + + public void setStackProperties(Properties stackProperties) { + } + + public String getLoggerName() { + return "Android SIP Logger"; + } +} +// END android-added + +// BEGIN android-deleted + +//import org.apache.log4j.Appender; +//import org.apache.log4j.FileAppender; +//import org.apache.log4j.Level; +//import org.apache.log4j.Logger; +//import org.apache.log4j.Priority; +//import org.apache.log4j.SimpleLayout; +// +///** +// * A wrapper around log4j that is used for logging debug and errors. You can +// * replace this file if you want to change the way in which messages are logged. +// * +// * @version 1.2 +// * +// * @author M. Ranganathan <br/> +// * @author M.Andrews +// * @author Jeroen van Bemmel +// * @author Jean Deruelle +// * +// */ +// +//public class LogWriter implements StackLogger { +// +// /** +// * The logger to which we will write our logging output. +// */ +// private Logger logger; +// +// /** +// * The stack name. +// */ +// private String stackName; +// +// /** +// * Name of the log file in which the trace is written out (default is +// * /tmp/sipserverlog.txt) +// */ +// private String logFileName = null; +// +// /** +// * Flag to indicate that logging is enabled. +// */ +// private volatile boolean needsLogging = false; +// +// private int lineCount; +// +// /** +// * trace level +// */ +// +// protected int traceLevel = TRACE_NONE; +// +// private String buildTimeStamp; +// +// private Properties configurationProperties; +// +// /** +// * log a stack trace. This helps to look at the stack frame. +// */ +// public void logStackTrace() { +// this.logStackTrace(TRACE_DEBUG); +// +// } +// +// public void logStackTrace(int traceLevel) { +// if (needsLogging) { +// StringWriter sw = new StringWriter(); +// PrintWriter pw = new PrintWriter(sw); +// StackTraceElement[] ste = new Exception().getStackTrace(); +// // Skip the log writer frame and log all the other stack frames. +// for (int i = 1; i < ste.length; i++) { +// String callFrame = "[" + ste[i].getFileName() + ":" +// + ste[i].getLineNumber() + "]"; +// pw.print(callFrame); +// } +// pw.close(); +// String stackTrace = sw.getBuffer().toString(); +// Level level = this.getLevel(traceLevel); +// Priority priority = this.getLogPriority(); +// if ( level.isGreaterOrEqual(priority)) { +// logger.log(level,stackTrace); +// } +// +// } +// } +// +// /** +// * Get the line count in the log stream. +// * +// * @return +// */ +// public int getLineCount() { +// return lineCount; +// } +// +// /** +// * Get the logger. +// * +// * @return +// */ +// public Logger getLogger() { +// return logger; +// } +// +// +// /** +// * This method allows you to add an external appender. +// * This is useful for the case when you want to log to +// * a different log stream than a file. +// * +// * @param appender +// */ +// public void addAppender(Appender appender) { +// +// this.logger.addAppender(appender); +// +// } +// +// /** +// * Log an exception. +// * +// * @param ex +// */ +// public void logException(Throwable ex) { +// +// if (needsLogging) { +// +// this.getLogger().error(ex.getMessage(), ex); +// } +// } +// +// +// +// +// /** +// * Counts the line number so that the debug log can be correlated to the +// * message trace. +// * +// * @param message -- +// * message to count the lines for. +// */ +// private void countLines(String message) { +// char[] chars = message.toCharArray(); +// for (int i = 0; i < chars.length; i++) { +// if (chars[i] == '\n') +// lineCount++; +// } +// +// } +// +// /** +// * Prepend the line and file where this message originated from +// * +// * @param message +// * @return re-written message. +// */ +// private String enhanceMessage(String message) { +// +// StackTraceElement[] stackTrace = new Exception().getStackTrace(); +// StackTraceElement elem = stackTrace[2]; +// String className = elem.getClassName(); +// String methodName = elem.getMethodName(); +// String fileName = elem.getFileName(); +// int lineNumber = elem.getLineNumber(); +// String newMessage = className + "." + methodName + "(" + fileName + ":" +// + lineNumber + ") [" + message + "]"; +// return newMessage; +// +// } +// +// /** +// * Log a message into the log file. +// * +// * @param message +// * message to log into the log file. +// */ +// public void logDebug(String message) { +// if (needsLogging) { +// String newMessage = this.enhanceMessage(message); +// if ( this.lineCount == 0) { +// getLogger().debug("BUILD TIMESTAMP = " + this.buildTimeStamp); +// getLogger().debug("Config Propeties = " + this.configurationProperties); +// } +// countLines(newMessage); +// getLogger().debug(newMessage); +// } +// +// } +// +// /** +// * Log a message into the log file. +// * +// * @param message +// * message to log into the log file. +// */ +// public void logTrace(String message) { +// if (needsLogging) { +// String newMessage = this.enhanceMessage(message); +// if ( this.lineCount == 0) { +// getLogger().debug("BUILD TIMESTAMP = " + this.buildTimeStamp); +// getLogger().debug("Config Propeties = " + this.configurationProperties); +// } +// countLines(newMessage); +// getLogger().trace(newMessage); +// } +// +// } +// +// /** +// * Set the trace level for the stack. +// */ +// private void setTraceLevel(int level) { +// traceLevel = level; +// } +// +// /** +// * Get the trace level for the stack. +// */ +// public int getTraceLevel() { +// return traceLevel; +// } +// +// /** +// * Log an error message. +// * +// * @param message -- +// * error message to log. +// */ +// public void logFatalError(String message) { +// Logger logger = this.getLogger(); +// String newMsg = this.enhanceMessage(message); +// countLines(newMsg); +// logger.fatal(newMsg); +// +// } +// +// /** +// * Log an error message. +// * +// * @param message -- +// * error message to log. +// * +// */ +// public void logError(String message) { +// Logger logger = this.getLogger(); +// String newMsg = this.enhanceMessage(message); +// countLines(newMsg); +// logger.error(newMsg); +// +// } +// +// public LogWriter() { +// } +// +// public void setStackProperties(Properties configurationProperties) { +// +// this.configurationProperties = configurationProperties; +// +// String logLevel = configurationProperties +// .getProperty("gov.nist.javax.sip.TRACE_LEVEL"); +// +// this.logFileName = configurationProperties +// .getProperty("gov.nist.javax.sip.DEBUG_LOG"); +// +// this.stackName = configurationProperties +// .getProperty("javax.sip.STACK_NAME"); +// +// //check whether a Log4j logger name has been +// //specified. if not, use the stack name as the default +// //logger name. +// String category = configurationProperties +// .getProperty("gov.nist.javax.sip.LOG4J_LOGGER_NAME", this.stackName); +// +// +// logger = Logger.getLogger(category); +// if (logLevel != null) { +// if (logLevel.equals("LOG4J")) { +// //if TRACE_LEVEL property is specified as +// //"LOG4J" then, set the traceLevel based on +// //the log4j effective log level. +// Level level = logger.getEffectiveLevel(); +// this.needsLogging = true; +// if (level == Level.OFF) +// this.needsLogging = false; +// this.traceLevel = TRACE_NONE; +// if (level.isGreaterOrEqual(Level.DEBUG)) { +// this.traceLevel = TRACE_DEBUG; +// } else if (level.isGreaterOrEqual(Level.INFO)) { +// this.traceLevel = TRACE_INFO; +// } else if (level.isGreaterOrEqual(Level.WARN)) { +// this.traceLevel = TRACE_ERROR; +// } +// } +// else { +// try { +// int ll = 0; +// if (logLevel.equals("TRACE")) { +// ll = TRACE_DEBUG; +// Debug.debug = true; +// Debug.setStackLogger(this); +// } else if (logLevel.equals("DEBUG")) { +// ll = TRACE_DEBUG; +// } else if ( logLevel.equals("INFO")) { +// ll = TRACE_INFO; +// } else if (logLevel.equals("ERROR")) { +// ll = TRACE_ERROR; +// } else if (logLevel.equals("NONE") || logLevel.equals("OFF")) { +// ll = TRACE_NONE; +// } else { +// ll = Integer.parseInt(logLevel); +// if ( ll > 32 ) { +// Debug.debug = true; +// Debug.setStackLogger(this); +// } +// } +// +// this.setTraceLevel(ll); +// this.needsLogging = true; +// if (traceLevel == TRACE_DEBUG) { +// logger.setLevel(Level.DEBUG); +// } else if (traceLevel == TRACE_INFO) { +// logger.setLevel(Level.INFO); +// } else if (traceLevel == TRACE_ERROR) { +// logger.setLevel(Level.ERROR); +// } else if (traceLevel == TRACE_NONE) { +// logger.setLevel(Level.OFF); +// this.needsLogging = false; +// } +// +// /* +// * If user specifies a logging file as part of the startup +// * properties then we try to create the appender. +// */ +// if (this.needsLogging && this.logFileName != null) { +// +// boolean overwrite = Boolean.valueOf( +// configurationProperties.getProperty( +// "gov.nist.javax.sip.DEBUG_LOG_OVERWRITE")); +// +// FileAppender fa = null; +// try { +// fa = new FileAppender(new SimpleLayout(), +// this.logFileName, !overwrite); +// } catch (FileNotFoundException fnf) { +// +// // Likely due to some directoy not existing. Create +// // them +// File logfile = new File(this.logFileName); +// logfile.getParentFile().mkdirs(); +// logfile.delete(); +// +// try { +// fa = new FileAppender(new SimpleLayout(), +// this.logFileName); +// } catch (IOException ioe) { +// ioe.printStackTrace(); // give up +// } +// } catch (IOException ex) { +// ex.printStackTrace(); +// } +// +// if (fa != null) +// logger.addAppender(fa); +// } +// +// } catch (NumberFormatException ex) { +// ex.printStackTrace(); +// System.err.println("LogWriter: Bad integer " + logLevel); +// System.err.println("logging dislabled "); +// needsLogging = false; +// } +// } +// } else { +// this.needsLogging = false; +// +// } +// +// +// } +// +// /** +// * @return flag to indicate if logging is enabled. +// */ +// public boolean isLoggingEnabled() { +// +// return this.needsLogging; +// } +// +// /** +// * Return true/false if loging is enabled at a given level. +// * +// * @param logLevel +// */ +// public boolean isLoggingEnabled(int logLevel) { +// return this.needsLogging && logLevel <= traceLevel; +// } +// +// +// /** +// * Log an error message. +// * +// * @param message +// * @param ex +// */ +// public void logError(String message, Exception ex) { +// Logger logger = this.getLogger(); +// logger.error(message, ex); +// +// } +// +// /** +// * Log a warning mesasge. +// * +// * @param string +// */ +// public void logWarning(String string) { +// getLogger().warn(string); +// +// } +// +// /** +// * Log an info message. +// * +// * @param string +// */ +// public void logInfo(String string) { +// getLogger().info(string); +// } +// +// /** +// * Disable logging altogether. +// * +// */ +// public void disableLogging() { +// this.needsLogging = false; +// } +// +// /** +// * Enable logging (globally). +// */ +// public void enableLogging() { +// this.needsLogging = true; +// +// } +// +// public void setBuildTimeStamp(String buildTimeStamp) { +// this.buildTimeStamp = buildTimeStamp; +// +// } +// +// public Priority getLogPriority() { +// if ( this.traceLevel == TRACE_INFO ) { +// return Priority.INFO; +// } else if ( this.traceLevel == TRACE_ERROR ) { +// return Priority.ERROR; +// } else if ( this.traceLevel == TRACE_DEBUG) { +// return Priority.DEBUG; +// } else if ( this.traceLevel == TRACE_TRACE) { +// return Priority.DEBUG; +// } else { +// return Priority.FATAL; +// } +// } +// +// public Level getLevel(int traceLevel) { +// if ( traceLevel == TRACE_INFO ) { +// return Level.INFO; +// } else if ( traceLevel == TRACE_ERROR ) { +// return Level.ERROR; +// } else if ( traceLevel == TRACE_DEBUG) { +// return Level.DEBUG; +// } else if (traceLevel == TRACE_TRACE) { +// return Level.ALL; +// } else { +// return Level.OFF; +// } +// } +// +// public String getLoggerName() { +// if ( this.logger != null ) { +// return logger.getName(); +// } else { +// return null; +// } +// } +// +// +//} + +// END android-deleted diff --git a/java/gov/nist/core/Match.java b/java/gov/nist/core/Match.java new file mode 100644 index 0000000..7e4dddc --- /dev/null +++ b/java/gov/nist/core/Match.java @@ -0,0 +1,46 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +/** Match template for pattern matching. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ + +public interface Match { + /** Return true if a match occurs for searchString. + * This is used for pattern matching in the find and replace and match + * functions of the sipheaders and sdpfields packages. We have avoided + * picking a specific regexp package to avoid code dependencies. + * Use a package such as the jakarta regexp package to implement this. + */ + public boolean match(String searchString); +} diff --git a/java/gov/nist/core/MultiMap.java b/java/gov/nist/core/MultiMap.java new file mode 100644 index 0000000..1bcf845 --- /dev/null +++ b/java/gov/nist/core/MultiMap.java @@ -0,0 +1,37 @@ +package gov.nist.core; + +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed 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. + */ + +import java.util.Map; + +/** + * This is simply a Map with slightly different semantics. + * Instead of returning an Object, it returns a Collection. + * So for example, you can put( key, new Integer(1) ); + * and then a Object get( key ); will return you a Collection + * instead of an Integer. + * Thus, this is simply a tag interface. + * + * @since 2.0 + * @author Christopher Berry + * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> + */ +public interface MultiMap extends Map { + + public Object remove( Object key, Object item ); + +} diff --git a/java/gov/nist/core/MultiValueMap.java b/java/gov/nist/core/MultiValueMap.java new file mode 100644 index 0000000..51b8174 --- /dev/null +++ b/java/gov/nist/core/MultiValueMap.java @@ -0,0 +1,9 @@ +package gov.nist.core; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +public interface MultiValueMap<K,V> extends Map<K,List<V>>, Serializable { + public Object remove( K key, V item ); +} diff --git a/java/gov/nist/core/MultiValueMapImpl.java b/java/gov/nist/core/MultiValueMapImpl.java new file mode 100644 index 0000000..04368e8 --- /dev/null +++ b/java/gov/nist/core/MultiValueMapImpl.java @@ -0,0 +1,154 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +package gov.nist.core; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class MultiValueMapImpl<V> implements MultiValueMap<String, V>, Cloneable { + private HashMap<String, ArrayList<V>> map = new HashMap<String, ArrayList<V>>(); + + private static final long serialVersionUID = 4275505380960964605L; + + public MultiValueMapImpl() { + super(); + + } + + public List<V> put(String key, V value) { + ArrayList<V> keyList = map.get(key); + if (keyList == null) { + keyList = new ArrayList<V>(10); + map.put(key, keyList); + } + + keyList.add(value); + return keyList; + } + + public boolean containsValue(Object value) { + Set pairs = map.entrySet(); + + if (pairs == null) + return false; + + Iterator pairsIterator = pairs.iterator(); + while (pairsIterator.hasNext()) { + Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next()); + ArrayList list = (ArrayList) (keyValuePair.getValue()); + if (list.contains(value)) + return true; + } + return false; + } + + public void clear() { + Set pairs = map.entrySet(); + Iterator pairsIterator = pairs.iterator(); + while (pairsIterator.hasNext()) { + Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next()); + ArrayList list = (ArrayList) (keyValuePair.getValue()); + list.clear(); + } + map.clear(); + } + + public Collection values() { + ArrayList returnList = new ArrayList(map.size()); + + Set pairs = map.entrySet(); + Iterator pairsIterator = pairs.iterator(); + while (pairsIterator.hasNext()) { + Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next()); + ArrayList list = (ArrayList) (keyValuePair.getValue()); + + Object[] values = list.toArray(); + for (int ii = 0; ii < values.length; ii++) { + returnList.add(values[ii]); + } + } + return returnList; + } + + public Object clone() { + MultiValueMapImpl obj = new MultiValueMapImpl<V>(); + obj.map = (HashMap<Object, ArrayList<V>>) this.map.clone(); + return obj; + } + + public int size() { + return this.map.size(); + } + + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + public Set entrySet() { + return map.entrySet(); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public Set<String> keySet() { + return this.map.keySet(); + } + + public Object remove(String key, V item) { + ArrayList<V> list = this.map.get(key); + if (list == null) { + return null; + } else { + return list.remove(item); + } + } + + public List<V> get(Object key) { + return map.get(key); + } + + public List<V> put(String key, List<V> value) { + return this.map.put(key,(ArrayList<V>) value); + } + + public List<V> remove(Object key) { + return map.remove(key); + } + + public void putAll(Map< ? extends String, ? extends List<V>> mapToPut) { + for (String k : mapToPut.keySet()) { + ArrayList<V> al = new ArrayList<V>(); + al.addAll(mapToPut.get(k)); + this.map.put(k, al); + } + } + +} diff --git a/java/gov/nist/core/NameValue.java b/java/gov/nist/core/NameValue.java new file mode 100644 index 0000000..74a43b2 --- /dev/null +++ b/java/gov/nist/core/NameValue.java @@ -0,0 +1,285 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.core; + +import java.util.Map.Entry; + +/* + * Bug reports and fixes: Kirby Kiem, Jeroen van Bemmel. + */ + +/** + * Generic structure for storing name-value pairs. + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class NameValue extends GenericObject implements Entry<String,String> { + + private static final long serialVersionUID = -1857729012596437950L; + + protected boolean isQuotedString; + + protected final boolean isFlagParameter; + + private String separator; + + private String quotes; + + private String name; + + private Object value; + + public NameValue() { + name = null; + value = ""; + separator = Separators.EQUALS; + this.quotes = ""; + this.isFlagParameter = false; + } + + /** + * New constructor, taking a boolean which is set if the NV pair is a flag + * + * @param n + * @param v + * @param isFlag + */ + public NameValue(String n, Object v, boolean isFlag) { + + // assert (v != null ); // I dont think this assertion is correct mranga + + name = n; + value = v; + separator = Separators.EQUALS; + quotes = ""; + this.isFlagParameter = isFlag; + } + + /** + * Original constructor, sets isFlagParameter to 'false' + * + * @param n + * @param v + */ + public NameValue(String n, Object v) { + this(n, v, false); + } + + /** + * Set the separator for the encoding method below. + */ + public void setSeparator(String sep) { + separator = sep; + } + + /** + * A flag that indicates that doublequotes should be put around the value + * when encoded (for example name=value when value is doublequoted). + */ + public void setQuotedValue() { + isQuotedString = true; + this.quotes = Separators.DOUBLE_QUOTE; + } + + /** + * Return true if the value is quoted in doublequotes. + */ + public boolean isValueQuoted() { + return isQuotedString; + } + + public String getName() { + return name; + } + + public Object getValueAsObject() { + return isFlagParameter ? "" : value; // never return null for flag + // params + } + + /** + * Set the name member + */ + public void setName(String n) { + name = n; + } + + /** + * Set the value member + */ + public void setValueAsObject(Object v) { + value = v; + } + + /** + * Get the encoded representation of this namevalue object. Added + * doublequote for encoding doublequoted values. + * + * Bug: RFC3261 stipulates that an opaque parameter in authenticate header + * has to be: + * opaque = "opaque" EQUAL quoted-string + * so returning just the name is not acceptable. (e.g. LinkSys phones + * are picky about this) + * + * @since 1.0 + * @return an encoded name value (eg. name=value) string. + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (name != null && value != null && !isFlagParameter) { + if (GenericObject.isMySubclass(value.getClass())) { + GenericObject gv = (GenericObject) value; + buffer.append(name).append(separator).append(quotes); + gv.encode(buffer); + buffer.append(quotes); + return buffer; + } else if (GenericObjectList.isMySubclass(value.getClass())) { + GenericObjectList gvlist = (GenericObjectList) value; + buffer.append(name).append(separator).append(gvlist.encode()); + return buffer; + } else if ( value.toString().length() == 0) { + // opaque="" bug fix - pmusgrave + /*if (name.toString().equals(gov.nist.javax.sip.header.ParameterNames.OPAQUE)) + return name + separator + quotes + quotes; + else + return name;*/ + if ( this.isQuotedString ) { + buffer.append(name).append(separator).append(quotes).append(quotes); + return buffer; + } else { + buffer.append(name).append(separator); // JvB: fix, case: "sip:host?subject=" + return buffer; + } + } else { + buffer.append(name).append(separator).append(quotes).append(value.toString()).append(quotes); + return buffer; + } + } else if (name == null && value != null) { + if (GenericObject.isMySubclass(value.getClass())) { + GenericObject gv = (GenericObject) value; + gv.encode(buffer); + return buffer; + } else if (GenericObjectList.isMySubclass(value.getClass())) { + GenericObjectList gvlist = (GenericObjectList) value; + buffer.append(gvlist.encode()); + return buffer; + } else { + buffer.append(quotes).append(value.toString()).append(quotes); + return buffer; + } + } else if (name != null && (value == null || isFlagParameter)) { + buffer.append(name); + return buffer; + } else { + return buffer; + } + } + + public Object clone() { + NameValue retval = (NameValue) super.clone(); + if (value != null) + retval.value = makeClone(value); + return retval; + } + + /** + * Equality comparison predicate. + */ + public boolean equals(Object other) { + if (other == null ) return false; + if (!other.getClass().equals(this.getClass())) + return false; + NameValue that = (NameValue) other; + if (this == that) + return true; + if (this.name == null && that.name != null || this.name != null + && that.name == null) + return false; + if (this.name != null && that.name != null + && this.name.compareToIgnoreCase(that.name) != 0) + return false; + if (this.value != null && that.value == null || this.value == null + && that.value != null) + return false; + if (this.value == that.value) + return true; + if (value instanceof String) { + // Quoted string comparisions are case sensitive. + if (isQuotedString) + return this.value.equals(that.value); + String val = (String) this.value; + String val1 = (String) that.value; + return val.compareToIgnoreCase(val1) == 0; + } else + return this.value.equals(that.value); + } + + /* + * (non-Javadoc) + * @see java.util.Map$Entry#getKey() + */ + public String getKey() { + + return this.name; + } + + /* + * (non-Javadoc) + * @see java.util.Map$Entry#getValue() + */ + public String getValue() { + + return value == null ? null : this.value.toString(); + } + + /* + * (non-Javadoc) + * @see java.util.Map$Entry#setValue(java.lang.Object) + */ + public String setValue(String value) { + String retval = this.value == null ? null : value; + this.value = value; + return retval; + + } + + @Override + public int hashCode() { + return this.encode().toLowerCase().hashCode(); + } + +} diff --git a/java/gov/nist/core/NameValueList.java b/java/gov/nist/core/NameValueList.java new file mode 100644 index 0000000..b30f694 --- /dev/null +++ b/java/gov/nist/core/NameValueList.java @@ -0,0 +1,354 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.core; + +import java.util.concurrent.*; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * Implements a simple NameValue association with a quick lookup function (via a + * hash map) the default behavior for this class is not thread safe. + * specify a constructor with boolean true to make this thread safe. + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + * + */ + +public class NameValueList implements Serializable, Cloneable, Map<String,NameValue> { + + + private static final long serialVersionUID = -6998271876574260243L; + + private Map<String,NameValue> hmap; + + private String separator; + + /** + * default constructor. + */ + public NameValueList() { + this.separator = ";"; + this.hmap = new LinkedHashMap<String,NameValue>(); + } + + public NameValueList(boolean sync) { + this.separator = ";"; + if (sync) + this.hmap = new ConcurrentHashMap<String,NameValue>(); + else + this.hmap = new LinkedHashMap<String,NameValue>(); + } + + public void setSeparator(String separator) { + this.separator = separator; + } + + /** + * Encode the list in semicolon separated form. + * + * @return an encoded string containing the objects in this list. + * @since v1.0 + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (!hmap.isEmpty()) { + Iterator<NameValue> iterator = hmap.values().iterator(); + if (iterator.hasNext()) { + while (true) { + Object obj = iterator.next(); + if (obj instanceof GenericObject) { + GenericObject gobj = (GenericObject) obj; + gobj.encode(buffer); + } else { + buffer.append(obj.toString()); + } + if (iterator.hasNext()) + buffer.append(separator); + else + break; + } + } + } + return buffer; + } + + public String toString() { + return this.encode(); + } + + /** + * Set a namevalue object in this list. + */ + + public void set(NameValue nv) { + this.hmap.put(nv.getName().toLowerCase(), nv); + } + + /** + * Set a namevalue object in this list. + */ + public void set(String name, Object value) { + NameValue nameValue = new NameValue(name, value); + hmap.put(name.toLowerCase(), nameValue); + + } + + /** + * Compare if two NameValue lists are equal. + * + * @param otherObject + * is the object to compare to. + * @return true if the two objects compare for equality. + */ + public boolean equals(Object otherObject) { + if ( otherObject == null ) { + return false; + } + if (!otherObject.getClass().equals(this.getClass())) { + return false; + } + NameValueList other = (NameValueList) otherObject; + + if (hmap.size() != other.hmap.size()) { + return false; + } + Iterator<String> li = this.hmap.keySet().iterator(); + + while (li.hasNext()) { + String key = (String) li.next(); + NameValue nv1 = this.getNameValue(key); + NameValue nv2 = (NameValue) other.hmap.get(key); + if (nv2 == null) + return false; + else if (!nv2.equals(nv1)) + return false; + } + return true; + } + + /** + * Do a lookup on a given name and return value associated with it. + */ + public Object getValue(String name) { + NameValue nv = this.getNameValue(name.toLowerCase()); + if (nv != null) + return nv.getValueAsObject(); + else + return null; + } + + /** + * Get the NameValue record given a name. + * + * @since 1.0 + */ + public NameValue getNameValue(String name) { + return (NameValue) this.hmap.get(name.toLowerCase()); + } + + /** + * Returns a boolean telling if this NameValueList has a record with this + * name + * + * @since 1.0 + */ + public boolean hasNameValue(String name) { + return hmap.containsKey(name.toLowerCase()); + } + + /** + * Remove the element corresponding to this name. + * + * @since 1.0 + */ + public boolean delete(String name) { + String lcName = name.toLowerCase(); + if (this.hmap.containsKey(lcName)) { + this.hmap.remove(lcName); + return true; + } else { + return false; + } + + } + + public Object clone() { + NameValueList retval = new NameValueList(); + retval.setSeparator(this.separator); + Iterator<NameValue> it = this.hmap.values().iterator(); + while (it.hasNext()) { + retval.set((NameValue) ((NameValue) it.next()).clone()); + } + return retval; + } + + /** + * Return the size of the embedded map + */ + public int size() { + return this.hmap.size(); + } + + /** + * Return true if empty. + */ + public boolean isEmpty() { + return hmap.isEmpty(); + } + + /** + * Return an iterator for the name-value pairs of this list. + * + * @return the iterator. + */ + public Iterator<NameValue> iterator() { + return this.hmap.values().iterator(); + } + + /** + * Get a list of parameter names. + * + * @return a list iterator that has the names of the parameters. + */ + public Iterator<String> getNames() { + return this.hmap.keySet().iterator(); + + } + + /** + * Get the parameter as a String. + * + * @return the parameter as a string. + */ + public String getParameter(String name) { + Object val = this.getValue(name); + if (val == null) + return null; + if (val instanceof GenericObject) + return ((GenericObject) val).encode(); + else + return val.toString(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#clear() + */ + + public void clear() { + this.hmap.clear(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(Object key) { + return this.hmap.containsKey(key.toString().toLowerCase()); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsValue(java.lang.Object) + */ + public boolean containsValue(Object value) { + return this.hmap.containsValue(value); + } + + /* + * (non-Javadoc) + * @see java.util.Map#entrySet() + */ + public Set<java.util.Map.Entry<String, NameValue>> entrySet() { + return this.hmap.entrySet(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#get(java.lang.Object) + */ + public NameValue get(Object key) { + return this.hmap.get(key.toString().toLowerCase()); + } + + /* + * (non-Javadoc) + * @see java.util.Map#keySet() + */ + public Set<String> keySet() { + return this.hmap.keySet(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public NameValue put(String name, NameValue nameValue) { + return this.hmap.put(name, nameValue); + } + + public void putAll(Map<? extends String, ? extends NameValue> map) { + this.hmap.putAll(map); + } + + /* + * (non-Javadoc) + * @see java.util.Map#remove(java.lang.Object) + */ + public NameValue remove(Object key) { + return this.hmap.remove(key.toString().toLowerCase()); + } + + /* + * (non-Javadoc) + * @see java.util.Map#values() + */ + public Collection<NameValue> values() { + return this.hmap.values(); + } + + @Override + public int hashCode() { + return this.hmap.keySet().hashCode(); + } +} diff --git a/java/gov/nist/core/PackageNames.java b/java/gov/nist/core/PackageNames.java new file mode 100644 index 0000000..49e25ad --- /dev/null +++ b/java/gov/nist/core/PackageNames.java @@ -0,0 +1,59 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.core; +/** +* Names for the packages that are referenced herein. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ + +public interface PackageNames { + public static final String JAIN_HEADER_PACKAGE = "javax.sip.header"; + public static final String JAIN_PACKAGE = "javax.sip"; + public static final String SIPHEADERS_PACKAGE = "gov.nist.javax.sip.header"; + public static final String PARSER_PACKAGE = "gov.nist.javax.sip.parser"; + public static final String NET_PACKAGE = "gov.nist.javax.sip.address"; + public static final String SIP_PACKAGE = "gov.nist.javax.sip"; + public static final String STACK_PACKAGE = "gov.nist.javax.sip.stack"; + public static final String CORE_PACKAGE = "gov.nist.core"; + public static final String MESSAGE_PACKAGE = "gov.nist.javax.sip.message"; + + // SDP packages + public static final String SDP_PACKAGE = "gov.nist.javax.sdp"; + public static final String SDP_PARSER_PACKAGE = SDP_PACKAGE + ".parser"; + + + + +} diff --git a/java/gov/nist/core/ParserCore.java b/java/gov/nist/core/ParserCore.java new file mode 100644 index 0000000..956221d --- /dev/null +++ b/java/gov/nist/core/ParserCore.java @@ -0,0 +1,142 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +import java.text.ParseException; + +/** Generic parser class. +* All parsers inherit this class. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public abstract class ParserCore { + public static final boolean debug = Debug.parserDebug; + + static int nesting_level; + + protected LexerCore lexer; + + + protected NameValue nameValue(char separator) throws ParseException { + if (debug) dbg_enter("nameValue"); + try { + + lexer.match(LexerCore.ID); + Token name = lexer.getNextToken(); + // eat white space. + lexer.SPorHT(); + try { + + + boolean quoted = false; + + char la = lexer.lookAhead(0); + + if (la == separator ) { + lexer.consume(1); + lexer.SPorHT(); + String str = null; + boolean isFlag = false; + if (lexer.lookAhead(0) == '\"') { + str = lexer.quotedString(); + quoted = true; + } else { + lexer.match(LexerCore.ID); + Token value = lexer.getNextToken(); + str = value.tokenValue; + + // JvB: flag parameters must be empty string! + if (str==null) { + str = ""; + isFlag = true; + } + } + NameValue nv = new NameValue(name.tokenValue,str,isFlag); + if (quoted) nv.setQuotedValue(); + return nv; + } else { + // JvB: flag parameters must be empty string! + return new NameValue(name.tokenValue,"",true); + } + } catch (ParseException ex) { + return new NameValue(name.tokenValue,null,false); + } + + } finally { + if (debug) dbg_leave("nameValue"); + } + + + } + + protected void dbg_enter(String rule) { + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < nesting_level ; i++) + stringBuffer.append(">"); + + if (debug) { + System.out.println( + stringBuffer + rule + + "\nlexer buffer = \n" + + lexer.getRest()); + } + nesting_level++; + } + + protected void dbg_leave(String rule) { + StringBuffer stringBuffer = new StringBuffer(); + for (int i = 0; i < nesting_level ; i++) + stringBuffer.append("<"); + + if (debug) { + System.out.println( + stringBuffer + + rule + + "\nlexer buffer = \n" + + lexer.getRest()); + } + nesting_level --; + } + + protected NameValue nameValue() throws ParseException { + return nameValue('='); + } + + + + protected void peekLine(String rule) { + if (debug) { + Debug.println(rule +" " + lexer.peekLine()); + } + } +} + + diff --git a/java/gov/nist/core/Separators.java b/java/gov/nist/core/Separators.java new file mode 100644 index 0000000..22c4a6f --- /dev/null +++ b/java/gov/nist/core/Separators.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +/** Separators. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public interface Separators { + public static final String SEMICOLON = ";"; + public static final String COLON = ":"; + public static final String COMMA = ","; + public static final String SLASH = "/"; + public static final String SP = " "; + public static final String EQUALS = "="; + public static final String STAR = "*"; + public static final String NEWLINE = "\r\n"; + public static final String RETURN = "\n"; + public static final String LESS_THAN = "<"; + public static final String GREATER_THAN = ">"; + public static final String AT = "@"; + public static final String DOT = "."; + public static final String QUESTION = "?"; + public static final String POUND = "#"; + public static final String AND = "&"; + public static final String LPAREN = "("; + public static final String RPAREN = ")"; + public static final String DOUBLE_QUOTE = "\""; + public static final String QUOTE = "\'"; + public static final String HT = "\t"; + public static final String PERCENT = "%"; +} diff --git a/java/gov/nist/core/ServerLogger.java b/java/gov/nist/core/ServerLogger.java new file mode 100644 index 0000000..1a31fde --- /dev/null +++ b/java/gov/nist/core/ServerLogger.java @@ -0,0 +1,49 @@ +/* + * JBoss, Home of Professional Open Source. + * + * This code has been contributed to the public domain. + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.core; + +import java.util.Properties; + +import javax.sip.SipStack; + +import gov.nist.javax.sip.message.SIPMessage; + +/** + * @author jean.deruelle@gmail.com + * + */ +public interface ServerLogger extends LogLevels { + + + void closeLogFile(); + + void logMessage(SIPMessage message, String from, String to, boolean sender, long time); + + void logMessage(SIPMessage message, String from, String to, String status, + boolean sender, long time); + + void logMessage(SIPMessage message, String from, String to, String status, + boolean sender); + + void logException(Exception ex); + + public void setStackProperties(Properties stackProperties); + + public void setSipStack(SipStack sipStack); + + +} diff --git a/java/gov/nist/core/StackLogger.java b/java/gov/nist/core/StackLogger.java new file mode 100644 index 0000000..a765b8c --- /dev/null +++ b/java/gov/nist/core/StackLogger.java @@ -0,0 +1,130 @@ +package gov.nist.core; + +import java.util.Properties; + + +/** + * interface that loggers should implement so that the stack can log to various + * loggers impl such as log4j, commons logging, sl4j, ... + * @author jean.deruelle@gmail.com + * + */ +public interface StackLogger extends LogLevels { + + /** + * log a stack trace. This helps to look at the stack frame. + */ + public void logStackTrace(); + + /** + * Log a stack trace if the current logging level exceeds + * given trace level. + * @param traceLevel + */ + public void logStackTrace(int traceLevel); + + /** + * Get the line count in the log stream. + * + * @return + */ + public int getLineCount(); + + /** + * Log an exception. + * + * @param ex + */ + public void logException(Throwable ex); + /** + * Log a message into the log file. + * + * @param message + * message to log into the log file. + */ + public void logDebug(String message); + /** + * Log a message into the log file. + * + * @param message + * message to log into the log file. + */ + public void logTrace(String message); + /** + * Log an error message. + * + * @param message -- + * error message to log. + */ + public void logFatalError(String message); + /** + * Log an error message. + * + * @param message -- + * error message to log. + * + */ + public void logError(String message); + /** + * @return flag to indicate if logging is enabled. + */ + public boolean isLoggingEnabled(); + /** + * Return true/false if loging is enabled at a given level. + * + * @param logLevel + */ + public boolean isLoggingEnabled(int logLevel); + /** + * Log an error message. + * + * @param message + * @param ex + */ + public void logError(String message, Exception ex); + /** + * Log a warning mesasge. + * + * @param string + */ + public void logWarning(String string); + /** + * Log an info message. + * + * @param string + */ + public void logInfo(String string); + + + /** + * Disable logging altogether. + * + */ + public void disableLogging(); + + /** + * Enable logging (globally). + */ + public void enableLogging(); + + /** + * Set the build time stamp. This is logged into the logging stream. + */ + public void setBuildTimeStamp(String buildTimeStamp); + + /** + * Stack creation properties. + * @param stackProperties + */ + + public void setStackProperties(Properties stackProperties); + + /** + * The category for the logger. + * @return + */ + public String getLoggerName(); + + + +} diff --git a/java/gov/nist/core/StringTokenizer.java b/java/gov/nist/core/StringTokenizer.java new file mode 100644 index 0000000..ea779f5 --- /dev/null +++ b/java/gov/nist/core/StringTokenizer.java @@ -0,0 +1,204 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +import java.util.*; +import java.text.ParseException; + +/** Base string token splitter. +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +* +* +* +*/ + +public class StringTokenizer { + + protected String buffer; + protected int bufferLen; + protected int ptr; + protected int savedPtr; + + protected StringTokenizer() { + } + + public StringTokenizer(String buffer) { + this.buffer = buffer; + bufferLen = buffer.length(); + ptr = 0; + } + + public String nextToken() { + int startIdx = ptr; + + while (ptr < bufferLen) { + char c = buffer.charAt(ptr); + ptr++; + if (c == '\n') { + break; + } + } + + return buffer.substring(startIdx, ptr); + } + + public boolean hasMoreChars() { + return ptr < bufferLen; + } + + public static boolean isHexDigit(char ch) { + return (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f') || + isDigit(ch); + } + + public static boolean isAlpha(char ch) { + if (ch <= 127) { + return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')); + } + else { + return Character.isLowerCase(ch) || Character.isUpperCase(ch); + } + } + + public static boolean isDigit(char ch) { + if (ch <= 127) { + return (ch <= '9' && ch >= '0'); + } + else { + return Character.isDigit(ch); + } + } + + public static boolean isAlphaDigit(char ch) { + if (ch <= 127) { + return (ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch <= '9' && ch >= '0'); + } + else { + return Character.isLowerCase(ch) || + Character.isUpperCase(ch) || + Character.isDigit(ch); + } + } + + public String getLine() { + int startIdx = ptr; + while (ptr < bufferLen && buffer.charAt(ptr) != '\n') { + ptr++; + } + if (ptr < bufferLen && buffer.charAt(ptr) == '\n') { + ptr++; + } + return buffer.substring(startIdx, ptr); + } + + public String peekLine() { + int curPos = ptr; + String retval = this.getLine(); + ptr = curPos; + return retval; + } + + public char lookAhead() throws ParseException { + return lookAhead(0); + } + + public char lookAhead(int k) throws ParseException { + // Debug.out.println("ptr = " + ptr); + try { + return buffer.charAt(ptr + k); + } + catch (IndexOutOfBoundsException e) { + return '\0'; + } + } + + public char getNextChar() throws ParseException { + if (ptr >= bufferLen) + throw new ParseException( + buffer + " getNextChar: End of buffer", + ptr); + else + return buffer.charAt(ptr++); + } + + public void consume() { + ptr = savedPtr; + } + + public void consume(int k) { + ptr += k; + } + + /** Get a Vector of the buffer tokenized by lines + */ + public Vector<String> getLines() { + Vector<String> result = new Vector<String>(); + while (hasMoreChars()) { + String line = getLine(); + result.addElement(line); + } + return result; + } + + /** Get the next token from the buffer. + */ + public String getNextToken(char delim) throws ParseException { + int startIdx = ptr; + while (true) { + char la = lookAhead(0); + if (la == delim) + break; + else if (la == '\0') + throw new ParseException("EOL reached", 0); + consume(1); + } + return buffer.substring(startIdx, ptr); + } + + /** get the SDP field name of the line + * @return String + */ + public static String getSDPFieldName(String line) { + if (line == null) + return null; + String fieldName = null; + try { + int begin = line.indexOf("="); + fieldName = line.substring(0, begin); + } catch (IndexOutOfBoundsException e) { + return null; + } + return fieldName; + } + +} + diff --git a/java/gov/nist/core/ThreadAuditor.java b/java/gov/nist/core/ThreadAuditor.java new file mode 100644 index 0000000..830e5ff --- /dev/null +++ b/java/gov/nist/core/ThreadAuditor.java @@ -0,0 +1,193 @@ +package gov.nist.core; + +import java.util.*; + +/** + * Thread Auditor class: + * - Provides a mechanism for applications to check the health of internal threads + * - The mechanism is fairly simple: + * - Threads register with the auditor at startup and "ping" the auditor every so often. + * - The application queries the auditor about the health of the system periodically. The + * auditor reports if the threads are healthy or if any of them failed to ping and are + * considered dead or stuck. + * - The main implication for the monitored threads is that they can no longer block + * waiting for an event forever. Any wait() must be implemented with a timeout so that + * the thread can periodically ping the auditor. + * + * This code is in the public domain. + * + * @author R. Borba (Natural Convergence) <br/> + * @version 1.2 + */ + +public class ThreadAuditor { + /// Threads being monitored + private Map<Thread,ThreadHandle> threadHandles = new HashMap<Thread,ThreadHandle>(); + + /// How often are threads supposed to ping + private long pingIntervalInMillisecs = 0; + + /// Internal class, used as a handle by the monitored threads + public class ThreadHandle { + /// Set to true when the thread pings, periodically reset to false by the auditor + private boolean isThreadActive; + + /// Thread being monitored + private Thread thread; + + /// Thread auditor monitoring this thread + private ThreadAuditor threadAuditor; + + /// Constructor + public ThreadHandle(ThreadAuditor aThreadAuditor) { + isThreadActive = false; + thread = Thread.currentThread(); + threadAuditor = aThreadAuditor; + } + + /// Called by the auditor thread to check the ping status of the thread + public boolean isThreadActive() { + return isThreadActive; + } + + /// Called by the auditor thread to reset the ping status of the thread + protected void setThreadActive(boolean value) { + isThreadActive = value; + } + + /// Return the thread being monitored + public Thread getThread() { + return thread; + } + + // Helper function to allow threads to ping using this handle + public void ping() { + threadAuditor.ping(this); + } + + // Helper function to allow threads to get the ping interval directly from this handle + public long getPingIntervalInMillisecs() { + return threadAuditor.getPingIntervalInMillisecs(); + } + + /** + * Returns a string representation of the object + * + * @return a string representation of the object + */ + public String toString() { + StringBuffer toString = new StringBuffer() + .append("Thread Name: ").append(thread.getName()) + .append(", Alive: ").append(thread.isAlive()); + return toString.toString(); + } + } + + /// Indicates how often monitored threads are supposed to ping (0 = no thread monitoring) + public long getPingIntervalInMillisecs() { + return pingIntervalInMillisecs; + } + + /// Defines how often monitored threads are supposed to ping + public void setPingIntervalInMillisecs(long value) { + pingIntervalInMillisecs = value; + } + + /// Indicates if the auditing of threads is enabled + public boolean isEnabled() { + return (pingIntervalInMillisecs > 0); + } + + /// Called by a thread that wants to be monitored + public synchronized ThreadHandle addCurrentThread() { + // Create and return a thread handle but only add it + // to the list of monitored threads if the auditor is enabled + ThreadHandle threadHandle = new ThreadHandle(this); + if (isEnabled()) { + threadHandles.put(Thread.currentThread(), threadHandle); + } + return threadHandle; + } + + /// Stops monitoring a given thread + public synchronized void removeThread(Thread thread) { + threadHandles.remove(thread); + } + + /// Called by a monitored thread reporting that it's alive and well + public synchronized void ping(ThreadHandle threadHandle) { + threadHandle.setThreadActive(true); + } + + /// Resets the auditor + public synchronized void reset() { + threadHandles.clear(); + } + + /** + * Audits the sanity of all threads + * + * @return An audit report string (multiple lines), or null if all is well + */ + public synchronized String auditThreads() { + String auditReport = null; + // Map stackTraces = null; + + // Scan all monitored threads looking for non-responsive ones + Iterator<ThreadHandle> it = threadHandles.values().iterator(); + while (it.hasNext()) { + ThreadHandle threadHandle = (ThreadHandle) it.next(); + if (!threadHandle.isThreadActive()) { + // Get the non-responsive thread + Thread thread = threadHandle.getThread(); + + // Update the audit report + if (auditReport == null) { + auditReport = "Thread Auditor Report:\n"; + } + auditReport += " Thread [" + thread.getName() + "] has failed to respond to an audit request.\n"; + + /* + * Stack traces are not available with JDK 1.4. + * Feel free to uncomment this block to get a better report if you're using JDK 1.5. + */ + // // Get stack traces for all live threads (do this only once per audit) + // if (stackTraces == null) { + // stackTraces = Thread.getAllStackTraces(); + // } + // + // // Get the stack trace for the non-responsive thread + // StackTraceElement[] stackTraceElements = (StackTraceElement[])stackTraces.get(thread); + // if (stackTraceElements != null && stackTraceElements.length > 0) { + // auditReport += " Stack trace:\n"; + // + // for (int i = 0; i < stackTraceElements.length ; i ++ ) { + // StackTraceElement stackTraceElement = stackTraceElements[i]; + // auditReport += " " + stackTraceElement.toString() + "\n"; + // } + // } else { + // auditReport += " Stack trace is not available.\n"; + // } + } + + // Reset the ping status of the thread + threadHandle.setThreadActive(false); + } + return auditReport; + } + + /** + * Returns a string representation of the object + * + * @return a string representation of the object + */ + public synchronized String toString() { + String toString = "Thread Auditor - List of monitored threads:\n"; + Iterator<ThreadHandle> it = threadHandles.values().iterator(); + while ( it.hasNext()) { + ThreadHandle threadHandle = (ThreadHandle)it.next(); + toString += " " + threadHandle.toString() + "\n"; + } + return toString; + } +} diff --git a/java/gov/nist/core/Token.java b/java/gov/nist/core/Token.java new file mode 100644 index 0000000..a7396ae --- /dev/null +++ b/java/gov/nist/core/Token.java @@ -0,0 +1,49 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core; + +/** + * Base token class. + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + */ + +public class Token { + protected String tokenValue; + protected int tokenType; + public String getTokenValue() { + return this.tokenValue; + } + public int getTokenType() { + return this.tokenType; + } + public String toString() { + return "tokenValue = " + tokenValue + "/tokenType = " + tokenType; + } +} diff --git a/java/gov/nist/core/net/AddressResolver.java b/java/gov/nist/core/net/AddressResolver.java new file mode 100644 index 0000000..300d12a --- /dev/null +++ b/java/gov/nist/core/net/AddressResolver.java @@ -0,0 +1,67 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core.net; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.sip.address.Hop; + +/** + * An interface that allows you to customize address lookup. + * The user can implement this interface to do DNS lookups or other lookup + * schemes and register it with the stack. + * The default implementation of the address resolver does nothing more than just return back + * the Hop that it was passed (fixing up the port if necessary). + * However, this behavior can be overriden. To override + * implement this interface and register it with the stack using + * {@link gov.nist.javax.sip.SipStackExt#setAddressResolver(AddressResolver)}. + * This interface will be incorporated into version 2.0 of the JAIN-SIP Specification. + * + * @since 2.0 + * + * + * @author M. Ranganathan + * + */ +public interface AddressResolver { + + /** + * Do a name lookup and resolve the given IP address. + * The default implementation is just an identity mapping + * (returns the argument). + * + * @param hop - an incoming Hop containing a potenitally unresolved address. + * @return a new hop ( if the address is recomputed ) or the original hop + * if this is just an identity mapping ( the default behavior ). + */ + public Hop resolveAddress( Hop hop); + + + + + +} diff --git a/java/gov/nist/core/net/DefaultNetworkLayer.java b/java/gov/nist/core/net/DefaultNetworkLayer.java new file mode 100644 index 0000000..e06a4cf --- /dev/null +++ b/java/gov/nist/core/net/DefaultNetworkLayer.java @@ -0,0 +1,159 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core.net; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +/* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */ +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +/** + * default implementation which passes straight through to java platform + * + * @author m.andrews + * @version 1.2 + * @since 1.1 + * + */ +public class DefaultNetworkLayer implements NetworkLayer { + + private SSLSocketFactory sslSocketFactory; + + private SSLServerSocketFactory sslServerSocketFactory; + + /** + * single default network layer; for flexibility, it may be better not to + * make it a singleton, but singleton seems to make sense currently. + */ + public static final DefaultNetworkLayer SINGLETON = new DefaultNetworkLayer(); + + private DefaultNetworkLayer() { + sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory + .getDefault(); + sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + } + + public ServerSocket createServerSocket(int port, int backlog, + InetAddress bindAddress) throws IOException { + return new ServerSocket(port, backlog, bindAddress); + } + + public Socket createSocket(InetAddress address, int port) + throws IOException { + return new Socket(address, port); + } + + public DatagramSocket createDatagramSocket() throws SocketException { + return new DatagramSocket(); + } + + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException { + + if ( laddr.isMulticastAddress() ) { + try { + MulticastSocket ds = new MulticastSocket( port ); + ds.joinGroup( laddr ); + return ds; + } catch (IOException e) { + throw new SocketException( e.getLocalizedMessage() ); + } + } else return new DatagramSocket(port, laddr); + } + + /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */ + public SSLServerSocket createSSLServerSocket(int port, int backlog, + InetAddress bindAddress) throws IOException { + return (SSLServerSocket) sslServerSocketFactory.createServerSocket( + port, backlog, bindAddress); + } + + /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */ + public SSLSocket createSSLSocket(InetAddress address, int port) + throws IOException { + return (SSLSocket) sslSocketFactory.createSocket(address, port); + } + + /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */ + public SSLSocket createSSLSocket(InetAddress address, int port, + InetAddress myAddress) throws IOException { + return (SSLSocket) sslSocketFactory.createSocket(address, port, + myAddress, 0); + } + + public Socket createSocket(InetAddress address, int port, + InetAddress myAddress) throws IOException { + if (myAddress != null) + return new Socket(address, port, myAddress, 0); + else + return new Socket(address, port); + } + + /** + * Creates a new Socket, binds it to myAddress:myPort and connects it to + * address:port. + * + * @param address the InetAddress that we'd like to connect to. + * @param port the port that we'd like to connect to + * @param myAddress the address that we are supposed to bind on or null + * for the "any" address. + * @param myPort the port that we are supposed to bind on or 0 for a random + * one. + * + * @return a new Socket, bound on myAddress:myPort and connected to + * address:port. + * @throws IOException if binding or connecting the socket fail for a reason + * (exception relayed from the correspoonding Socket methods) + */ + public Socket createSocket(InetAddress address, int port, + InetAddress myAddress, int myPort) + throws IOException + { + if (myAddress != null) + return new Socket(address, port, myAddress, myPort); + else if (port != 0) + { + //myAddress is null (i.e. any) but we have a port number + Socket sock = new Socket(); + sock.bind(new InetSocketAddress(port)); + sock.connect(new InetSocketAddress(address, port)); + return sock; + } + else + return new Socket(address, port); + } + +} diff --git a/java/gov/nist/core/net/NetworkLayer.java b/java/gov/nist/core/net/NetworkLayer.java new file mode 100644 index 0000000..ca95053 --- /dev/null +++ b/java/gov/nist/core/net/NetworkLayer.java @@ -0,0 +1,153 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.core.net; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +// Added by Daniel J. Martinez Manzano <dani@dif.um.es> +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; + + +/** + * basic interface to the network layer + * + * @author m.andrews + * + */ +public interface NetworkLayer { + + /** + * Creates a server with the specified port, listen backlog, and local IP address to bind to. + * comparable to "new java.net.ServerSocket(port,backlog,bindAddress);" + * + * @param port + * @param backlog + * @param bindAddress + * @return the server socket + */ + public ServerSocket createServerSocket(int port, int backlog, + InetAddress bindAddress) throws IOException; + + /** + * Creates an SSL server with the specified port, listen backlog, and local IP address to bind to. + * Added by Daniel J. Martinez Manzano <dani@dif.um.es> + * + * @param port + * @param backlog + * @param bindAddress + * @return the server socket + */ + public SSLServerSocket createSSLServerSocket(int port, int backlog, + InetAddress bindAddress) throws IOException; + + /** + * Creates a stream socket and connects it to the specified port number at the specified IP address. + * comparable to "new java.net.Socket(address, port);" + * + * @param address + * @param port + * @return the socket + */ + public Socket createSocket(InetAddress address, int port) throws IOException; + + /** + * Creates a stream socket and connects it to the specified port number at the specified IP address. + * comparable to "new java.net.Socket(address, port,localaddress);" + * + * @param address + * @param port + * @param localAddress + * @return the socket + */ + public Socket createSocket(InetAddress address, int port, InetAddress localAddress) throws IOException; + + /** + * Creates a new Socket, binds it to myAddress:myPort and connects it to + * address:port. + * + * @param address the InetAddress that we'd like to connect to. + * @param port the port that we'd like to connect to + * @param myAddress the address that we are supposed to bind on or null + * for the "any" address. + * @param myPort the port that we are supposed to bind on or 0 for a random + * one. + * + * @return a new Socket, bound on myAddress:myPort and connected to + * address:port. + * @throws IOException if binding or connecting the socket fail for a reason + * (exception relayed from the correspoonding Socket methods) + */ + public Socket createSocket(InetAddress address, int port, + InetAddress myAddress, int myPort) + throws IOException; + + /** + * Creates a stream SSL socket and connects it to the specified port number at the specified IP address. + * Added by Daniel J. Martinez Manzano <dani@dif.um.es> + * + * @param address + * @param port + * @return the socket + */ + public SSLSocket createSSLSocket(InetAddress address, int port) throws IOException; + + /** + * Creates a stream SSL socket and connects it to the specified port number at the specified IP address. + * Added by Daniel J. Martinez Manzano <dani@dif.um.es> + * + * @param address + * @param port + * @param localAddress -- my address. + * @return the socket + */ + public SSLSocket createSSLSocket(InetAddress address, int port, InetAddress localAddress) throws IOException; + + /** + * Constructs a datagram socket and binds it to any available port on the local host machine. + * comparable to "new java.net.DatagramSocket();" + * + * @return the datagram socket + */ + public DatagramSocket createDatagramSocket() throws SocketException; + + /** + * Creates a datagram socket, bound to the specified local address. + * comparable to "new java.net.DatagramSocket(port,laddr);" + * + * @param port + * @param laddr + * @return the datagram socket + */ + public DatagramSocket createDatagramSocket(int port, InetAddress laddr) + throws SocketException; + +} diff --git a/java/gov/nist/core/net/SslNetworkLayer.java b/java/gov/nist/core/net/SslNetworkLayer.java new file mode 100644 index 0000000..3543191 --- /dev/null +++ b/java/gov/nist/core/net/SslNetworkLayer.java @@ -0,0 +1,168 @@ +/*
+* Conditions Of Use
+*
+* This software was developed by employees of the National Institute of
+* Standards and Technology (NIST), an agency of the Federal Government.
+* Pursuant to title 15 Untied States Code Section 105, works of NIST
+* employees are not subject to copyright protection in the United States
+* and are considered to be in the public domain. As a result, a formal
+* license is not needed to use the software.
+*
+* This software is provided by NIST as a service and is expressly
+* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
+* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
+* AND DATA ACCURACY. NIST does not warrant or make any representations
+* regarding the use of the software or the results thereof, including but
+* not limited to the correctness, accuracy, reliability or usefulness of
+* the software.
+*
+* Permission to use this software is contingent upon your acceptance
+* of the terms of this agreement
+*
+* .
+*
+*/
+package gov.nist.core.net;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+/**
+ * extended implementation of a network layer that allows to define a private java
+ * keystores/truststores
+ *
+ * @author f.reif
+ * @version 1.2
+ * @since 1.2
+ *
+ */
+public class SslNetworkLayer implements NetworkLayer {
+
+ private SSLSocketFactory sslSocketFactory;
+
+ private SSLServerSocketFactory sslServerSocketFactory;
+
+ public SslNetworkLayer(
+ String trustStoreFile,
+ String keyStoreFile,
+ char[] keyStorePassword,
+ String keyStoreType) throws GeneralSecurityException, FileNotFoundException, IOException
+ {
+ SSLContext sslContext;
+ sslContext = SSLContext.getInstance("TLS");
+ String algorithm = KeyManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(algorithm);
+ KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(algorithm);
+ SecureRandom secureRandom = new SecureRandom();
+ secureRandom.nextInt();
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ KeyStore trustStore = KeyStore.getInstance(keyStoreType);
+ keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword);
+ trustStore.load(new FileInputStream(trustStoreFile), keyStorePassword);
+ tmFactory.init(trustStore);
+ kmFactory.init(keyStore, keyStorePassword);
+ sslContext.init(kmFactory.getKeyManagers(), tmFactory.getTrustManagers(), secureRandom);
+ sslServerSocketFactory = sslContext.getServerSocketFactory();
+ sslSocketFactory = sslContext.getSocketFactory();
+ }
+
+ public ServerSocket createServerSocket(int port, int backlog,
+ InetAddress bindAddress) throws IOException {
+ return new ServerSocket(port, backlog, bindAddress);
+ }
+
+ public Socket createSocket(InetAddress address, int port)
+ throws IOException {
+ return new Socket(address, port);
+ }
+
+ public DatagramSocket createDatagramSocket() throws SocketException {
+ return new DatagramSocket();
+ }
+
+ public DatagramSocket createDatagramSocket(int port, InetAddress laddr)
+ throws SocketException {
+ return new DatagramSocket(port, laddr);
+ }
+
+ /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */
+ public SSLServerSocket createSSLServerSocket(int port, int backlog,
+ InetAddress bindAddress) throws IOException {
+ return (SSLServerSocket) sslServerSocketFactory.createServerSocket(
+ port, backlog, bindAddress);
+ }
+
+ /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */
+ public SSLSocket createSSLSocket(InetAddress address, int port)
+ throws IOException {
+ return (SSLSocket) sslSocketFactory.createSocket(address, port);
+ }
+
+ /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */
+ public SSLSocket createSSLSocket(InetAddress address, int port,
+ InetAddress myAddress) throws IOException {
+ return (SSLSocket) sslSocketFactory.createSocket(address, port,
+ myAddress, 0);
+ }
+
+ public Socket createSocket(InetAddress address, int port,
+ InetAddress myAddress) throws IOException {
+ if (myAddress != null)
+ return new Socket(address, port, myAddress, 0);
+ else
+ return new Socket(address, port);
+ }
+
+ /**
+ * Creates a new Socket, binds it to myAddress:myPort and connects it to
+ * address:port.
+ *
+ * @param address the InetAddress that we'd like to connect to.
+ * @param port the port that we'd like to connect to
+ * @param myAddress the address that we are supposed to bind on or null
+ * for the "any" address.
+ * @param myPort the port that we are supposed to bind on or 0 for a random
+ * one.
+ *
+ * @return a new Socket, bound on myAddress:myPort and connected to
+ * address:port.
+ * @throws IOException if binding or connecting the socket fail for a reason
+ * (exception relayed from the correspoonding Socket methods)
+ */
+ public Socket createSocket(InetAddress address, int port,
+ InetAddress myAddress, int myPort)
+ throws IOException
+ {
+ if (myAddress != null)
+ return new Socket(address, port, myAddress, myPort);
+ else if (port != 0)
+ {
+ //myAddress is null (i.e. any) but we have a port number
+ Socket sock = new Socket();
+ sock.bind(new InetSocketAddress(port));
+ sock.connect(new InetSocketAddress(address, port));
+ return sock;
+ }
+ else
+ return new Socket(address, port);
+ }
+}
diff --git a/java/gov/nist/core/net/package.html b/java/gov/nist/core/net/package.html new file mode 100644 index 0000000..e7f96d5 --- /dev/null +++ b/java/gov/nist/core/net/package.html @@ -0,0 +1,6 @@ +<body> +Contains the Network layer classes and interfaces. The network layer +wraps the java.net. Socket classes and allows users low level monitoring +and control over these objects. This feature was proposed by Mike Andrews +<xoba@dev.java.net>. +</body> diff --git a/java/gov/nist/core/package.html b/java/gov/nist/core/package.html new file mode 100644 index 0000000..b3dc994 --- /dev/null +++ b/java/gov/nist/core/package.html @@ -0,0 +1,6 @@ + +<body> +Contains core classes that the rest of the implementation depends upon. These +include classes for basic parser and lexer functionality and logging +functionality. +</body> diff --git a/java/gov/nist/javax/sip/ClientTransactionExt.java b/java/gov/nist/javax/sip/ClientTransactionExt.java new file mode 100644 index 0000000..b96489e --- /dev/null +++ b/java/gov/nist/javax/sip/ClientTransactionExt.java @@ -0,0 +1,55 @@ +package gov.nist.javax.sip; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.sip.ClientTransaction; +import javax.sip.Timeout; +import javax.sip.address.Hop; + +public interface ClientTransactionExt extends ClientTransaction, TransactionExt { + + /** + * Notify on retransmission from the client transaction side. The listener will get a + * notification on retransmission when this flag is set. When set the client transaction + * listener will get a Timeout.RETRANSMIT event on each retransmission. + * + * @param flag -- the flag that indicates whether or not notification is desired. + * + * @since 2.0 + */ + public void setNotifyOnRetransmit(boolean flag); + + /** + * Send a transaction timeout event to the application if Tx is still in Calling state in the + * given time period ( in base timer interval count ) after sending request. The stack will + * start a timer and alert the application if the client transaction does not transition out + * of the Trying state by the given interval. This is a "one shot" alert. + * + * @param count -- the number of base timer intervals after which an alert is issued. + * + * + * @since 2.0 + */ + public void alertIfStillInCallingStateBy(int count); + + /** + * Get the next hop that was computed by the routing layer. + * when it sent out the request. This allows you to route requests + * to the SAME destination if required ( for example if you get + * an authentication challenge ). + */ + public Hop getNextHop(); + + /** + * Return true if this Ctx is a secure transport. + * + */ + public boolean isSecure(); + + + + + +} diff --git a/java/gov/nist/javax/sip/DefaultAddressResolver.java b/java/gov/nist/javax/sip/DefaultAddressResolver.java new file mode 100644 index 0000000..b546536 --- /dev/null +++ b/java/gov/nist/javax/sip/DefaultAddressResolver.java @@ -0,0 +1,74 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.sip.address.Hop; + +import gov.nist.core.net.AddressResolver; +import gov.nist.javax.sip.stack.HopImpl; +import gov.nist.javax.sip.stack.MessageProcessor; + +/** + * This is the default implementation of the AddressResolver. The AddressResolver is a NIST-SIP specific + * feature. The address resolover is consulted to convert a Hop into a meaningful address. The default + * implementation is a passthrough. It only gets involved in setting the default port. However, you + * can register your own AddressResolver implementation + * Note that + * The RI checks incoming via headers for resolving the sentBy field. If you want to set it to + * some address that cannot be resolved you should register an AddressResolver with the stack. + * This feature is also useful for DNS SRV lookup which is not implemented by the RI at present. + * + * @version 1.2 + * @since 1.2 + * @see gov.nist.javax.sip.SipStackImpl#setAddressResolver(AddressResolver) + * + * @author M. Ranganathan + * + */ +public class DefaultAddressResolver implements AddressResolver { + + public DefaultAddressResolver() { + + } + /* + * (non-Javadoc) + * @see gov.nist.core.net.AddressResolver#resolveAddress(javax.sip.address.Hop) + */ + public Hop resolveAddress(Hop inputAddress) { + if (inputAddress.getPort() != -1) + return inputAddress; + else { + return new HopImpl(inputAddress.getHost(), + MessageProcessor.getDefaultPort(inputAddress.getTransport()),inputAddress.getTransport()); + } + } + + + +} diff --git a/java/gov/nist/javax/sip/DialogExt.java b/java/gov/nist/javax/sip/DialogExt.java new file mode 100644 index 0000000..ede39cd --- /dev/null +++ b/java/gov/nist/javax/sip/DialogExt.java @@ -0,0 +1,55 @@ +package gov.nist.javax.sip; + +import javax.sip.Dialog; +import javax.sip.SipProvider; + +/** + * Extensions for Next specification revision. These interfaces will remain unchanged and be + * merged with the next revision of the spec. + * + * + * @author mranga + * + */ +public interface DialogExt extends Dialog { + + /** + * Returns the SipProvider that was used for the first transaction in this Dialog + * + * @return SipProvider + * + * @since 2.0 + */ + public SipProvider getSipProvider(); + + /** + * Sets a flag that indicates that this Dialog is part of a BackToBackUserAgent. If this flag + * is set, INVITEs are not allowed to interleave and timed out ACK transmission results in a + * BYE being sent to the other side. Setting this flag instructs the stack to automatically + * handle dialog errors. Once this flag is set for a dialog, it cannot be changed. + * This flag can be set on a stack-wide basis, on a per-provider basis or on a per Dialog basis. + * This flag must only be set at the time of Dialog creation. If the flag is set after the first + * request or response is seen by the Dialog, the behavior of this flag is undefined. + * + * @since 2.0 + */ + public void setBackToBackUserAgent(); + + + /** + * Turn off sequence number validation for this dialog. This passes all requests to the + * application layer including those that arrive out of order. This is good for testing + * purposes. Validation is delegated to the application and the stack will not attempt to + * block requests arriving out of sequence from reaching the application. In particular, the + * validation of CSeq and the ACK retransmission recognition are delegated to the application. + * Your application will be responsible for error handling of these cases. + * + * @since 2.0 + */ + public void disableSequenceNumberValidation(); + + + + + +} diff --git a/java/gov/nist/javax/sip/DialogFilter.java b/java/gov/nist/javax/sip/DialogFilter.java new file mode 100644 index 0000000..bb78f04 --- /dev/null +++ b/java/gov/nist/javax/sip/DialogFilter.java @@ -0,0 +1,1437 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.Event; +import gov.nist.javax.sip.header.ReferTo; +import gov.nist.javax.sip.header.RetryAfter; +import gov.nist.javax.sip.header.Route; +import gov.nist.javax.sip.header.RouteList; +import gov.nist.javax.sip.header.Server; +import gov.nist.javax.sip.message.MessageFactoryImpl; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; +import gov.nist.javax.sip.stack.MessageChannel; +import gov.nist.javax.sip.stack.SIPClientTransaction; +import gov.nist.javax.sip.stack.SIPDialog; +import gov.nist.javax.sip.stack.SIPServerTransaction; +import gov.nist.javax.sip.stack.SIPTransaction; +import gov.nist.javax.sip.stack.ServerRequestInterface; +import gov.nist.javax.sip.stack.ServerResponseInterface; + +import java.io.IOException; +import java.util.TimerTask; + +import javax.sip.ClientTransaction; +import javax.sip.DialogState; +import javax.sip.InvalidArgumentException; +import javax.sip.ObjectInUseException; +import javax.sip.RequestEvent; +import javax.sip.ResponseEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.SipProvider; +import javax.sip.TransactionState; +import javax.sip.header.CSeqHeader; +import javax.sip.header.EventHeader; +import javax.sip.header.ReferToHeader; +import javax.sip.header.ServerHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Bug fix Contributions by Lamine Brahimi, Andreas Bystrom, Bill Roome, John Martin, Daniel + * Machin Vasquez-Illa, Antonis Karydas, Joe Provino, Bruce Evangelder, Jeroen van Bemmel, Robert + * S. Rosen. + */ +/** + * An adapter class from the JAIN implementation objects to the NIST-SIP stack. The primary + * purpose of this class is to do early rejection of bad messages and deliver meaningful messages + * to the application. This class is essentially a Dialog filter. It is a helper for the UAC Core. + * It checks for and rejects requests and responses which may be filtered out because of sequence + * number, Dialog not found, etc. Note that this is not part of the JAIN-SIP spec (it does not + * implement a JAIN-SIP interface). This is part of the glue that ties together the NIST-SIP stack + * and event model with the JAIN-SIP stack. This is strictly an implementation class. + * + * @version 1.2 $Revision: 1.64 $ $Date: 2010/01/14 18:58:30 $ + * + * @author M. Ranganathan + */ +class DialogFilter implements ServerRequestInterface, ServerResponseInterface { + + protected SIPTransaction transactionChannel; + + protected ListeningPointImpl listeningPoint; + + private SipStackImpl sipStack; + + public DialogFilter(SipStackImpl sipStack) { + this.sipStack = sipStack; + + } + + /** + * Send back a Request Pending response. + * + * @param sipRequest + * @param transaction + */ + private void sendRequestPendingResponse(SIPRequest sipRequest, + SIPServerTransaction transaction) { + SIPResponse sipResponse = sipRequest.createResponse(Response.REQUEST_PENDING); + ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader(); + if (serverHeader != null) { + sipResponse.setHeader(serverHeader); + } + try { + RetryAfter retryAfter = new RetryAfter(); + retryAfter.setRetryAfter(1); + sipResponse.setHeader(retryAfter); + if (sipRequest.getMethod().equals(Request.INVITE)) { + sipStack.addTransactionPendingAck(transaction); + } + transaction.sendResponse(sipResponse); + transaction.releaseSem(); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Problem sending error response", ex); + transaction.releaseSem(); + sipStack.removeTransaction(transaction); + } + } + + /** + * Send a BAD REQUEST response. + * + * @param sipRequest + * @param transaction + * @param reasonPhrase + */ + + private void sendBadRequestResponse(SIPRequest sipRequest, SIPServerTransaction transaction, + String reasonPhrase) { + SIPResponse sipResponse = sipRequest.createResponse(Response.BAD_REQUEST); + if (reasonPhrase != null) + sipResponse.setReasonPhrase(reasonPhrase); + ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader(); + if (serverHeader != null) { + sipResponse.setHeader(serverHeader); + } + try { + if (sipRequest.getMethod().equals(Request.INVITE)) { + sipStack.addTransactionPendingAck(transaction); + } + transaction.sendResponse(sipResponse); + transaction.releaseSem(); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Problem sending error response", ex); + transaction.releaseSem(); + sipStack.removeTransaction(transaction); + + } + } + + /** + * Send a CALL OR TRANSACTION DOES NOT EXIST response. + * + * @param sipRequest + * @param transaction + */ + + private void sendCallOrTransactionDoesNotExistResponse(SIPRequest sipRequest, + SIPServerTransaction transaction) { + + SIPResponse sipResponse = sipRequest + .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); + + ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader(); + if (serverHeader != null) { + sipResponse.setHeader(serverHeader); + } + try { + if (sipRequest.getMethod().equals(Request.INVITE)) { + sipStack.addTransactionPendingAck(transaction); + } + transaction.sendResponse(sipResponse); + transaction.releaseSem(); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Problem sending error response", ex); + transaction.releaseSem(); + sipStack.removeTransaction(transaction); + + } + + } + + /** + * Send back a LOOP Detected Response. + * + * @param sipRequest + * @param transaction + * + */ + private void sendLoopDetectedResponse(SIPRequest sipRequest, SIPServerTransaction transaction) { + SIPResponse sipResponse = sipRequest.createResponse(Response.LOOP_DETECTED); + + ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader(); + if (serverHeader != null) { + sipResponse.setHeader(serverHeader); + } + try { + sipStack.addTransactionPendingAck(transaction); + transaction.sendResponse(sipResponse); + transaction.releaseSem(); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Problem sending error response", ex); + transaction.releaseSem(); + sipStack.removeTransaction(transaction); + + } + + } + + /** + * Send back an error Response. + * + * @param sipRequest + * @param transaction + */ + + private void sendServerInternalErrorResponse(SIPRequest sipRequest, + SIPServerTransaction transaction) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("Sending 500 response for out of sequence message"); + SIPResponse sipResponse = sipRequest.createResponse(Response.SERVER_INTERNAL_ERROR); + sipResponse.setReasonPhrase("Request out of order"); + if (MessageFactoryImpl.getDefaultServerHeader() != null) { + ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader(); + sipResponse.setHeader(serverHeader); + } + + try { + RetryAfter retryAfter = new RetryAfter(); + retryAfter.setRetryAfter(10); + sipResponse.setHeader(retryAfter); + sipStack.addTransactionPendingAck(transaction); + transaction.sendResponse(sipResponse); + transaction.releaseSem(); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Problem sending response", ex); + transaction.releaseSem(); + sipStack.removeTransaction(transaction); + } + } + + /** + * Process a request. Check for various conditions in the dialog that can result in the + * message being dropped. Possibly return errors for these conditions. + * + * @exception SIPServerException is thrown when there is an error processing the request. + */ + public void processRequest(SIPRequest sipRequest, MessageChannel incomingMessageChannel) { + // Generate the wrapper JAIN-SIP object. + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "PROCESSING INCOMING REQUEST " + sipRequest + " transactionChannel = " + + transactionChannel + " listening point = " + + listeningPoint.getIPAddress() + ":" + listeningPoint.getPort()); + if (listeningPoint == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping message: No listening point registered!"); + return; + } + + SipStackImpl sipStack = (SipStackImpl) transactionChannel.getSIPStack(); + + SipProviderImpl sipProvider = listeningPoint.getProvider(); + if (sipProvider == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("No provider - dropping !!"); + return; + } + + if (sipStack == null) + InternalErrorHandler.handleException("Egads! no sip stack!"); + + // Look for the registered SIPListener for the message channel. + + SIPServerTransaction transaction = (SIPServerTransaction) this.transactionChannel; + if (transaction != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "transaction state = " + transaction.getState()); + } + String dialogId = sipRequest.getDialogId(true); + SIPDialog dialog = sipStack.getDialog(dialogId); + /* + * Check if we got this request on the contact address of the dialog If not the dialog + * does not belong to this request. We check this condition if a contact address has been + * assigned to the dialog. Forgive the sins of B2BUA's that like to record route ACK's + */ + if (dialog != null && sipProvider != dialog.getSipProvider()) { + Contact contact = dialog.getMyContactHeader(); + if (contact != null) { + SipUri contactUri = (SipUri) (contact.getAddress().getURI()); + String ipAddress = contactUri.getHost(); + int contactPort = contactUri.getPort(); + String contactTransport = contactUri.getTransportParam(); + if (contactTransport == null) + contactTransport = "udp"; + if (contactPort == -1) { + if (contactTransport.equals("udp") || contactTransport.equals("tcp")) + contactPort = 5060; + else + contactPort = 5061; + } + // Check if the dialog contact is the same as the provider on + // which we got the request. Otherwise, dont assign this + // dialog to the request. + if (ipAddress != null + && (!ipAddress.equals(listeningPoint.getIPAddress()) || contactPort != listeningPoint + .getPort())) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "nulling dialog -- listening point mismatch! " + contactPort + + " lp port = " + listeningPoint.getPort()); + + } + dialog = null; + } + + } + } + + /* + * RFC 3261 8.2.2.2 Merged requests: If the request has no tag in the To header field, the + * UAS core MUST check the request against ongoing transactions. If the From tag, Call-ID, + * and CSeq exactly match those associated with an ongoing transaction, but the request + * does not match that transaction (based on the matching rules in Section 17.2.3), the + * UAS core SHOULD generate a 482 (Loop Detected) response and pass it to the server + * transaction. This support is only enabled when the stack has been instructed to + * function with Automatic Dialog Support. + */ + if (sipProvider.isAutomaticDialogSupportEnabled() + && sipProvider.isDialogErrorsAutomaticallyHandled() + && sipRequest.getToTag() == null) { + SIPServerTransaction sipServerTransaction = sipStack + .findMergedTransaction(sipRequest); + if (sipServerTransaction != null) { + this.sendLoopDetectedResponse(sipRequest, transaction); + return; + } + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("dialogId = " + dialogId); + sipStack.getStackLogger().logDebug("dialog = " + dialog); + } + + /* + * RFC 3261 Section 16.4 If the first value in the Route header field indicates this + * proxy,the proxy MUST remove that value from the request . + */ + + // If the message is being processed + // by a Proxy, then the proxy will take care of stripping the + // Route header. If the request is being processed by an + // endpoint, then the stack strips off the route header. + if (sipRequest.getHeader(Route.NAME) != null && transaction.getDialog() != null) { + RouteList routes = sipRequest.getRouteHeaders(); + Route route = (Route) routes.getFirst(); + SipUri uri = (SipUri) route.getAddress().getURI(); + int port; + if (uri.getHostPort().hasPort()) { + port = uri.getHostPort().getPort(); + } else { + if (listeningPoint.getTransport().equalsIgnoreCase("TLS")) + port = 5061; + else + port = 5060; + } + String host = uri.getHost(); + if ((host.equals(listeningPoint.getIPAddress()) || host + .equalsIgnoreCase(listeningPoint.getSentBy())) + && port == listeningPoint.getPort()) { + if (routes.size() == 1) + sipRequest.removeHeader(Route.NAME); + else + routes.removeFirst(); + } + } + + if (sipRequest.getMethod().equals(Request.REFER) && dialog != null + && sipProvider.isDialogErrorsAutomaticallyHandled()) { + /* + * An agent responding to a REFER method MUST return a 400 (Bad Request) if the + * request contained zero or more than one Refer-To header field values. + */ + ReferToHeader sipHeader = (ReferToHeader) sipRequest.getHeader(ReferTo.NAME); + if (sipHeader == null) { + this + .sendBadRequestResponse(sipRequest, transaction, + "Refer-To header is missing"); + return; + + } + + /* + * A refer cannot be processed until we have either sent or received an ACK. + */ + SIPTransaction lastTransaction = ((SIPDialog) dialog).getLastTransaction(); + if (lastTransaction != null && sipProvider.isDialogErrorsAutomaticallyHandled()) { + SIPRequest lastRequest = (SIPRequest) lastTransaction.getRequest(); + if (lastTransaction instanceof SIPServerTransaction) { + if (!((SIPDialog) dialog).isAckSeen() + && lastRequest.getMethod().equals(Request.INVITE)) { + this.sendRequestPendingResponse(sipRequest, transaction); + return; + } + } else if (lastTransaction instanceof SIPClientTransaction) { + long cseqno = lastRequest.getCSeqHeader().getSeqNumber(); + String method = lastRequest.getMethod(); + if (method.equals(Request.INVITE) && !dialog.isAckSent(cseqno)) { + this.sendRequestPendingResponse(sipRequest, transaction); + return; + } + } + } + + } else if (sipRequest.getMethod().equals(Request.UPDATE)) { + /* + * Got an UPDATE method and the user dialog does not exist and the user wants to be a + * User agent. + * + */ + if (sipProvider.isAutomaticDialogSupportEnabled() && dialog == null) { + this.sendCallOrTransactionDoesNotExistResponse(sipRequest, transaction); + return; + } + } else if (sipRequest.getMethod().equals(Request.ACK)) { + + if (transaction != null && transaction.isInviteTransaction()) { + // This is an ack for a 3xx-6xx response. Just let the tx laer + // take care of it. + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Processing ACK for INVITE Tx "); + + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Processing ACK for dialog " + dialog); + + if (dialog == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog does not exist " + sipRequest.getFirstLine() + + " isServerTransaction = " + true); + + } + SIPServerTransaction st = sipStack + .getRetransmissionAlertTransaction(dialogId); + if (st != null && st.isRetransmissionAlertEnabled()) { + st.disableRetransmissionAlerts(); + + } + /* + * JvB: must never drop ACKs that dont match a transaction! One cannot be sure + * if it isn't an ACK for a 2xx response + * + */ + SIPServerTransaction ackTransaction = sipStack + .findTransactionPendingAck(sipRequest); + /* + * Found a transaction ( that we generated ) which is waiting for ACK. So ACK + * it and return. + */ + if (ackTransaction != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Found Tx pending ACK"); + try { + ackTransaction.setAckSeen(); + sipStack.removeTransaction(ackTransaction); + sipStack.removeTransactionPendingAck(ackTransaction); + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError( + "Problem terminating transaction", ex); + } + } + return; + } + + } else { + if (!dialog.handleAck(transaction)) { + if (!dialog.isSequnceNumberValidation()) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog exists with loose dialog validation " + + sipRequest.getFirstLine() + + " isServerTransaction = " + true + " dialog = " + + dialog.getDialogId()); + + } + SIPServerTransaction st = sipStack + .getRetransmissionAlertTransaction(dialogId); + if (st != null && st.isRetransmissionAlertEnabled()) { + st.disableRetransmissionAlerts(); + + } + } else { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dropping ACK - cannot find a transaction or dialog"); + } + SIPServerTransaction ackTransaction = sipStack + .findTransactionPendingAck(sipRequest); + if (ackTransaction != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Found Tx pending ACK"); + try { + ackTransaction.setAckSeen(); + sipStack.removeTransaction(ackTransaction); + sipStack.removeTransactionPendingAck(ackTransaction); + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError( + "Problem terminating transaction", ex); + } + } + } + return; + } + } else { + transaction.passToListener(); + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, dialogId); + if (sipRequest.getMethod().equals(Request.INVITE) + && sipProvider.isDialogErrorsAutomaticallyHandled()) { + sipStack.putInMergeTable(transaction, sipRequest); + } + /* + * Note that ACK is a pseudo transaction. It is never added to the stack + * and you do not get transaction terminated events on ACK. + */ + + if (sipStack.deliverTerminatedEventForAck) { + try { + sipStack.addTransaction(transaction); + transaction.scheduleAckRemoval(); + } catch (IOException ex) { + + } + } else { + transaction.setMapped(true); + } + + } + } + } + } else if (sipRequest.getMethod().equals(Request.PRACK)) { + + /* + * RFC 3262: A matching PRACK is defined as one within the same dialog as the + * response, and whose method, CSeq-num, and response-num in the RAck header field + * match, respectively, the method from the CSeq, the sequence number from the CSeq, + * and the sequence number from the RSeq of the reliable provisional response. + */ + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Processing PRACK for dialog " + dialog); + + if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog does not exist " + sipRequest.getFirstLine() + + " isServerTransaction = " + true); + + } + if (sipStack.isLoggingEnabled()) { + sipStack + .getStackLogger() + .logDebug( + "Sending 481 for PRACK - automatic dialog support is enabled -- cant find dialog!"); + } + SIPResponse notExist = sipRequest + .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); + + try { + sipProvider.sendResponse(notExist); + } catch (SipException e) { + sipStack.getStackLogger().logError("error sending response", e); + } + if (transaction != null) { + sipStack.removeTransaction(transaction); + transaction.releaseSem(); + } + return; + + } else if (dialog != null) { + if (!dialog.handlePrack(sipRequest)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Dropping out of sequence PRACK "); + if (transaction != null) { + sipStack.removeTransaction(transaction); + transaction.releaseSem(); + } + return; + } else { + try { + sipStack.addTransaction(transaction); + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, dialogId); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Processing PRACK without a DIALOG -- this must be a proxy element"); + } + + } else if (sipRequest.getMethod().equals(Request.BYE)) { + // Check for correct sequence numbering of the BYE + if (dialog != null && !dialog.isRequestConsumable(sipRequest)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping out of sequence BYE " + dialog.getRemoteSeqNumber() + " " + + sipRequest.getCSeq().getSeqNumber()); + + if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber() + && transaction.getState() == TransactionState.TRYING) { + + this.sendServerInternalErrorResponse(sipRequest, transaction); + + } + // If the stack knows about the tx, then remove it. + if (transaction != null) + sipStack.removeTransaction(transaction); + return; + + } else if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) { + // Drop bye's with 481 if dialog does not exist. + // If dialog support is enabled then + // there must be a dialog associated with the bye + // No dialog could be found and requests on this + // provider. Must act like a user agent -- so drop the request. + // NOTE: if Automatic dialog support is not enabled, + // then it is the application's responsibility to + // take care of this error condition possibly. + + SIPResponse response = sipRequest + .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); + response.setReasonPhrase("Dialog Not Found"); + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "dropping request -- automatic dialog " + + "support enabled and dialog does not exist!"); + try { + transaction.sendResponse(response); + } catch (SipException ex) { + sipStack.getStackLogger().logError("Error in sending response", ex); + } + // If the stack knows about the tx, then remove it. + if (transaction != null) { + sipStack.removeTransaction(transaction); + transaction.releaseSem(); + transaction = null; + } + return; + + } + + // note that the transaction may be null (which + // happens when no dialog for the bye was found. + // and automatic dialog support is disabled (i.e. the app wants + // to manage its own dialog layer. + if (transaction != null && dialog != null) { + try { + if (sipProvider == dialog.getSipProvider()) { + sipStack.addTransaction(transaction); + dialog.addTransaction(transaction); + transaction.setDialog(dialog, dialogId); + } + + } catch (IOException ex) { + InternalErrorHandler.handleException(ex); + } + } + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "BYE Tx = " + transaction + " isMapped =" + + transaction.isTransactionMapped()); + } + + } else if (sipRequest.getMethod().equals(Request.CANCEL)) { + + SIPServerTransaction st = (SIPServerTransaction) sipStack.findCancelTransaction( + sipRequest, true); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Got a CANCEL, InviteServerTx = " + st + " cancel Server Tx ID = " + + transaction + " isMapped = " + + transaction.isTransactionMapped()); + + } + // Processing incoming CANCEL. + // Check if we can process the CANCEL request. + if (sipRequest.getMethod().equals(Request.CANCEL)) { + // If the CANCEL comes in too late, there's not + // much that the Listener can do so just do the + // default action and avoid bothering the listener. + if (st != null && st.getState() == SIPTransaction.TERMINATED_STATE) { + // If transaction already exists but it is + // too late to cancel the transaction then + // just respond OK to the CANCEL and bail. + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Too late to cancel Transaction"); + // send OK and just ignore the CANCEL. + try { + + transaction.sendResponse(sipRequest.createResponse(Response.OK)); + } catch (Exception ex) { + if (ex.getCause() != null && ex.getCause() instanceof IOException) { + st.raiseIOExceptionEvent(); + } + } + return; + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Cancel transaction = " + st); + + } + if (transaction != null && st != null && st.getDialog() != null) { + // Found an invite tx corresponding to the CANCEL. + // Set up the client tx and pass up to listener. + transaction.setDialog((SIPDialog) st.getDialog(), dialogId); + dialog = (SIPDialog) st.getDialog(); + } else if (st == null && sipProvider.isAutomaticDialogSupportEnabled() + && transaction != null) { + // Could not find a invite tx corresponding to the CANCEL. + // Automatic dialog support is enabled so I must behave like + // an endpoint on this provider. + // Send the error response for the cancel. + + SIPResponse response = sipRequest + .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "dropping request -- automatic dialog support " + + "enabled and INVITE ST does not exist!"); + } + try { + sipProvider.sendResponse(response); + } catch (SipException ex) { + InternalErrorHandler.handleException(ex); + } + if (transaction != null) { + sipStack.removeTransaction(transaction); + transaction.releaseSem(); + } + return; + + } + + // INVITE was handled statefully so the CANCEL must also be + // statefully handled. + if (st != null) { + try { + if (transaction != null) { + sipStack.addTransaction(transaction); + transaction.setPassToListener(); + transaction.setInviteTransaction(st); + // Dont let the INVITE and CANCEL be concurrently + // processed. + st.acquireSem(); + + } + + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + } else if (sipRequest.getMethod().equals(Request.INVITE)) { + SIPTransaction lastTransaction = dialog == null ? null : dialog + .getInviteTransaction(); + + /* + * RFC 3261 Chapter 14. A UAS that receives a second INVITE before it sends the final + * response to a first INVITE with a lower CSeq sequence number on the same dialog + * MUST return a 500 (Server Internal Error) response to the second INVITE and MUST + * include a Retry-After header field with a randomly chosen value of between 0 and 10 + * seconds. + */ + + if (dialog != null && transaction != null && lastTransaction != null + && sipRequest.getCSeq().getSeqNumber() > dialog.getRemoteSeqNumber() + && lastTransaction instanceof SIPServerTransaction + && sipProvider.isDialogErrorsAutomaticallyHandled() + && dialog.isSequnceNumberValidation() + && lastTransaction.isInviteTransaction() + && lastTransaction.getState() != TransactionState.COMPLETED + && lastTransaction.getState() != TransactionState.TERMINATED + && lastTransaction.getState() != TransactionState.CONFIRMED) { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Sending 500 response for out of sequence message"); + } + this.sendServerInternalErrorResponse(sipRequest, transaction); + return; + + } + + /* + * Saw an interleaved invite before ACK was sent. RFC 3261 Chapter 14. A UAS that + * receives an INVITE on a dialog while an INVITE it had sent on that dialog is in + * progress MUST return a 491 (Request Pending) response to the received INVITE. + */ + lastTransaction = (dialog == null ? null : dialog.getLastTransaction()); + + if (dialog != null + && sipProvider.isDialogErrorsAutomaticallyHandled() + && lastTransaction != null + && lastTransaction.isInviteTransaction() + && lastTransaction instanceof ClientTransaction + && lastTransaction.getLastResponse() != null + && lastTransaction.getLastResponse().getStatusCode() == 200 + && !dialog.isAckSent(lastTransaction.getLastResponse().getCSeq() + .getSeqNumber())) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Sending 491 response for client Dialog ACK not sent."); + } + this.sendRequestPendingResponse(sipRequest, transaction); + return; + } + + if (dialog != null && lastTransaction != null + && sipProvider.isDialogErrorsAutomaticallyHandled() + && lastTransaction.isInviteTransaction() + && lastTransaction instanceof ServerTransaction && !dialog.isAckSeen()) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Sending 491 response for server Dialog ACK not seen."); + } + this.sendRequestPendingResponse(sipRequest, transaction); + return; + + } + } + + // Sequence numbers are supposed to be incremented + // sequentially within a dialog for RFC 3261 + // Note BYE, CANCEL and ACK is handled above - so no check here. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "CHECK FOR OUT OF SEQ MESSAGE " + dialog + " transaction " + transaction); + } + + if (dialog != null && transaction != null && !sipRequest.getMethod().equals(Request.BYE) + && !sipRequest.getMethod().equals(Request.CANCEL) + && !sipRequest.getMethod().equals(Request.ACK) + && !sipRequest.getMethod().equals(Request.PRACK)) { + + if (!dialog.isRequestConsumable(sipRequest)) { + + /* + * RFC 3261: "UAS Behavior" section (12.2.2): If the remote sequence number was + * not empty, but the sequence number of the request is lower than the remote + * sequence number, the request is out of order and MUST be rejected with a 500 + * (Server Internal Error) response. + */ + + // Drop the request + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dropping out of sequence message " + dialog.getRemoteSeqNumber() + + " " + sipRequest.getCSeq()); + } + + // send error when stricly higher, ignore when == + // (likely still processing, error would interrupt that) + + if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber() + && sipProvider.isDialogErrorsAutomaticallyHandled() + && (transaction.getState() == TransactionState.TRYING || transaction + .getState() == TransactionState.PROCEEDING)) { + this.sendServerInternalErrorResponse(sipRequest, transaction); + + } + return; + } + + try { + if (sipProvider == dialog.getSipProvider()) { + sipStack.addTransaction(transaction); + // This will set the remote sequence number. + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, dialogId); + + } + } catch (IOException ex) { + transaction.raiseIOExceptionEvent(); + sipStack.removeTransaction(transaction); + return; + } + + } + + RequestEvent sipEvent; + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + sipRequest.getMethod() + " transaction.isMapped = " + + transaction.isTransactionMapped()); + } + + /* + * RFC 3265: Each event package MUST specify whether forked SUBSCRIBE requests are allowed + * to install multiple subscriptions. If such behavior is not allowed, the first potential + * dialog- establishing message will create a dialog. All subsequent NOTIFY messages which + * correspond to the SUBSCRIBE message (i.e., match "To", "From", "From" header "tag" + * parameter, "Call-ID", "CSeq", "Event", and "Event" header "id" parameter) but which do + * not match the dialog would be rejected with a 481 response. Note that the 200-class + * response to the SUBSCRIBE can arrive after a matching NOTIFY has been received; such + * responses might not correlate to the same dialog established by the NOTIFY. Except as + * required to complete the SUBSCRIBE transaction, such non-matching 200-class responses + * are ignored. + */ + + if (dialog == null && sipRequest.getMethod().equals(Request.NOTIFY)) { + + SIPClientTransaction pendingSubscribeClientTx = sipStack.findSubscribeTransaction( + sipRequest, listeningPoint); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "PROCESSING NOTIFY DIALOG == null " + pendingSubscribeClientTx); + } + + /* + * RFC 3265: Upon receiving a NOTIFY request, the subscriber should check that it + * matches at least one of its outstanding subscriptions; if not, it MUST return a + * "481 Subscription does not exist" response unless another 400- or -class response + * is more appropriate. + */ + if (sipProvider.isAutomaticDialogSupportEnabled() && pendingSubscribeClientTx == null + && !sipStack.deliverUnsolicitedNotify) { + /* + * This is the case of the UAC receiving a Stray NOTIFY for which it has not + * previously sent out a SUBSCRIBE and for which it does not have an established + * dialog. + */ + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Could not find Subscription for Notify Tx."); + } + Response errorResponse = sipRequest + .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); + errorResponse.setReasonPhrase("Subscription does not exist"); + sipProvider.sendResponse(errorResponse); + return; + + } catch (Exception ex) { + sipStack.getStackLogger().logError( + "Exception while sending error response statelessly", ex); + return; + } + + } + + // If the server transaction cannot be found or if it + // aleady has a dialog attached to it then just assign the + // notify to this dialog and pass it up. + if (pendingSubscribeClientTx != null) { + // The response to the pending subscribe tx can try to create + // a dialog at the same time that the notify is trying to + // create a dialog. Thus we cannot process both at the + // same time. + + transaction.setPendingSubscribe(pendingSubscribeClientTx); + // The transaction gets assigned to the dialog from the + // outgoing subscribe. First see if anybody claimed the + // default Dialog for the outgoing Subscribe request. + SIPDialog subscriptionDialog = (SIPDialog) pendingSubscribeClientTx + .getDefaultDialog(); + + // TODO -- refactor this. Can probably be written far cleaner. + if (subscriptionDialog == null || subscriptionDialog.getDialogId() == null + || !subscriptionDialog.getDialogId().equals(dialogId)) { + // Notify came in before you could assign a response to + // the subscribe. + // grab the default dialog and assign it to the tags in + // the notify. + if (subscriptionDialog != null && subscriptionDialog.getDialogId() == null) { + subscriptionDialog.setDialogId(dialogId); + + } else { + subscriptionDialog = pendingSubscribeClientTx.getDialog(dialogId); + } + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "PROCESSING NOTIFY Subscribe DIALOG " + subscriptionDialog); + } + + // The user could have createed a dialog before sending out + // the SUBSCRIBE on the subscribe tx. + if (subscriptionDialog == null + && (sipProvider.isAutomaticDialogSupportEnabled() || pendingSubscribeClientTx + .getDefaultDialog() != null)) { + Event event = (Event) sipRequest.getHeader(EventHeader.NAME); + if (sipStack.isEventForked(event.getEventType())) { + + subscriptionDialog = SIPDialog.createFromNOTIFY( + pendingSubscribeClientTx, transaction); + + } + + } + if (subscriptionDialog != null) { + transaction.setDialog(subscriptionDialog, dialogId); + subscriptionDialog.setState(DialogState.CONFIRMED.getValue()); + sipStack.putDialog(subscriptionDialog); + pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId); + if (!transaction.isTransactionMapped()) { + this.sipStack.mapTransaction(transaction); + // Let the listener see it if it just got + // created. + // otherwise, we have already processed the tx + // so + // we dont want the listener to see it. + transaction.setPassToListener(); + try { + this.sipStack.addTransaction(transaction); + } catch (Exception ex) { + } + } + } + } else { + // The subscription default dialog is our dialog. + // Found a subscrbe dialog for the NOTIFY + // So map the tx. + transaction.setDialog(subscriptionDialog, dialogId); + dialog = subscriptionDialog; + if (!transaction.isTransactionMapped()) { + this.sipStack.mapTransaction(transaction); + // Let the listener see it if it just got created. + // otherwise, we have already processed the tx so + // we dont want the listener to see it. + transaction.setPassToListener(); + try { + this.sipStack.addTransaction(transaction); + } catch (Exception ex) { + } + } + sipStack.putDialog(subscriptionDialog); + if (pendingSubscribeClientTx != null) { + subscriptionDialog.addTransaction(pendingSubscribeClientTx); + pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId); + + } + } + if (transaction != null + && ((SIPServerTransaction) transaction).isTransactionMapped()) { + // Shadow transaction has been created and the stack + // knows + // about it. + sipEvent = new RequestEvent((SipProvider) sipProvider, + (ServerTransaction) transaction, subscriptionDialog, + (Request) sipRequest); + } else { + // Shadow transaction has been created but the stack + // does + // not know + // about it. + sipEvent = new RequestEvent((SipProvider) sipProvider, null, + subscriptionDialog, (Request) sipRequest); + } + + } else { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("could not find subscribe tx"); + } + + // Got a notify out of the blue - just pass it up + // for stateless handling by the application. + sipEvent = new RequestEvent(sipProvider, null, null, (Request) sipRequest); + } + + } else { + + // For a dialog creating event - set the transaction to null. + // The listener can create the dialog if needed. + if (transaction != null + && (((SIPServerTransaction) transaction).isTransactionMapped())) { + sipEvent = new RequestEvent(sipProvider, (ServerTransaction) transaction, dialog, + (Request) sipRequest); + } else { + sipEvent = new RequestEvent(sipProvider, null, dialog, (Request) sipRequest); + } + } + sipProvider.handleEvent(sipEvent, transaction); + + } + + /** + * Process the response. + * + * @exception SIPServerException is thrown when there is an error processing the response + * @param incomingMessageChannel -- message channel on which the response is received. + */ + public void processResponse(SIPResponse response, MessageChannel incomingMessageChannel, + SIPDialog dialog) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "PROCESSING INCOMING RESPONSE" + response.encodeMessage()); + } + if (listeningPoint == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError( + "Dropping message: No listening point" + " registered!"); + return; + } + + if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(response)) { + if (sipStack.isLoggingEnabled()) { + sipStack + .getStackLogger() + .logError( + "Dropping response - topmost VIA header does not originate from this stack"); + } + return; + } + + SipProviderImpl sipProvider = listeningPoint.getProvider(); + if (sipProvider == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("Dropping message: no provider"); + } + return; + } + if (sipProvider.getSipListener() == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("No listener -- dropping response!"); + } + return; + } + + SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel; + SipStackImpl sipStackImpl = sipProvider.sipStack; + + if (sipStack.isLoggingEnabled()) { + sipStackImpl.getStackLogger().logDebug("Transaction = " + transaction); + } + + if (transaction == null) { + // Transaction is null but the dialog is not null. This means that + // the transaction has been removed by the stack. + // If the dialog exists, then it may need to retransmit ACK so + // we cannot drop the response. + if (dialog != null) { + if (response.getStatusCode() / 100 != 2) { + if (sipStack.isLoggingEnabled()) { + sipStack + .getStackLogger() + .logDebug( + "Response is not a final response and dialog is found for response -- dropping response!"); + } + return; + } else if (dialog.getState() == DialogState.TERMINATED) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog is terminated -- dropping response!"); + } + return; + } else { + boolean ackAlreadySent = false; + if (dialog.isAckSeen() && dialog.getLastAckSent() != null) { + if (dialog.getLastAckSent().getCSeq().getSeqNumber() == response + .getCSeq().getSeqNumber()) { + // the last ack sent corresponded to this 200 + ackAlreadySent = true; + } + } + // 200 retransmission for the final response. + if (ackAlreadySent + && response.getCSeq().getMethod().equals(dialog.getMethod())) { + try { + // Found the dialog - resend the ACK and + // dont pass up the null transaction + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Retransmission of OK detected: Resending last ACK"); + } + dialog.resendAck(); + return; + } catch (SipException ex) { + // What to do here ?? kill the dialog? + sipStack.getStackLogger().logError("could not resend ack", ex); + } + } + } + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "could not find tx, handling statelessly Dialog = " + dialog); + } + // Pass the response up to the application layer to handle + // statelessly. + + ResponseEventExt sipEvent = new ResponseEventExt(sipProvider, transaction, dialog, + (Response) response); + + if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) { + SIPClientTransaction forked = this.sipStack.getForkedTransaction(response + .getTransactionId()); + sipEvent.setOriginalTransaction(forked); + } + + sipProvider.handleEvent(sipEvent, transaction); + return; + } + + ResponseEventExt responseEvent = null; + + // Here if there is an assigned dialog + responseEvent = new ResponseEventExt(sipProvider, (ClientTransactionExt) transaction, + dialog, (Response) response); + if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) { + SIPClientTransaction forked = this.sipStack.getForkedTransaction(response + .getTransactionId()); + responseEvent.setOriginalTransaction(forked); + } + + // Set the Dialog for the response. + if (dialog != null && response.getStatusCode() != 100) { + // set the last response for the dialog. + dialog.setLastResponse(transaction, response); + transaction.setDialog(dialog, dialog.getDialogId()); + } + + sipProvider.handleEvent(responseEvent, transaction); + + } + + /** + * Just a placeholder. This is called from the stack for message logging. Auxiliary processing + * information can be passed back to be written into the log file. + * + * @return auxiliary information that we may have generated during the message processing + * which is retrieved by the message logger. + */ + public String getProcessingInfo() { + return null; + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.ServerResponseInterface#processResponse(gov.nist.javax.sip.message.SIPResponse, + * gov.nist.javax.sip.stack.MessageChannel) + */ + public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) { + String dialogID = sipResponse.getDialogId(false); + SIPDialog sipDialog = this.sipStack.getDialog(dialogID); + + String method = sipResponse.getCSeq().getMethod(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "PROCESSING INCOMING RESPONSE: " + sipResponse.encodeMessage()); + } + + if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(sipResponse)) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("Detected stray response -- dropping"); + } + return; + } + + if (listeningPoint == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping message: No listening point" + " registered!"); + return; + } + + SipProviderImpl sipProvider = listeningPoint.getProvider(); + if (sipProvider == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Dropping message: no provider"); + } + return; + } + + if (sipProvider.getSipListener() == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dropping message: no sipListener registered!"); + } + return; + } + + SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel; + // This may be a dialog creating method for which the ACK has not yet + // been sent + // but the dialog has already been assigned ( happens this way for + // 3PCC). + if (sipDialog == null && transaction != null) { + sipDialog = transaction.getDialog(dialogID); + if (sipDialog != null && sipDialog.getState() == DialogState.TERMINATED) + sipDialog = null; + } + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Transaction = " + transaction + " sipDialog = " + sipDialog); + + if (this.transactionChannel != null) { + String originalFrom = ((SIPRequest) this.transactionChannel.getRequest()) + .getFromTag(); + if (originalFrom == null ^ sipResponse.getFrom().getTag() == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); + return; + } + if (originalFrom != null + && !originalFrom.equalsIgnoreCase(sipResponse.getFrom().getTag())) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); + return; + } + + } + if (sipStack.isDialogCreated(method) && sipResponse.getStatusCode() != 100 + && sipResponse.getFrom().getTag() != null && sipResponse.getTo().getTag() != null + && sipDialog == null) { + if (sipProvider.isAutomaticDialogSupportEnabled()) { + if (this.transactionChannel != null) { + if (sipDialog == null) { + // There could be an existing dialog for this response. + sipDialog = sipStack.createDialog( + (SIPClientTransaction) this.transactionChannel, sipResponse); + + this.transactionChannel.setDialog(sipDialog, sipResponse + .getDialogId(false)); + } + } else { + sipDialog = this.sipStack.createDialog(sipProvider, sipResponse); + } + } + + } else { + // Have a dialog but could not find transaction. + if (sipDialog != null && transaction == null + && sipDialog.getState() != DialogState.TERMINATED) { + if (sipResponse.getStatusCode() / 100 != 2) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "status code != 200 ; statusCode = " + + sipResponse.getStatusCode()); + } else if (sipDialog.getState() == DialogState.TERMINATED) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog is terminated -- dropping response!"); + } + // Dialog exists but was terminated - just create and send an ACK for the OK. + // It could be late arriving. + if (sipResponse.getStatusCode() / 100 == 2 + && sipResponse.getCSeq().getMethod().equals(Request.INVITE)) { + try { + Request ackRequest = sipDialog.createAck(sipResponse.getCSeq() + .getSeqNumber()); + sipDialog.sendAck(ackRequest); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Error creating ack", ex); + } + } + return; + } else { + boolean ackAlreadySent = false; + if (sipDialog.isAckSeen() && sipDialog.getLastAckSent() != null) { + if (sipDialog.getLastAckSent().getCSeq().getSeqNumber() == sipResponse + .getCSeq().getSeqNumber() + && sipResponse.getDialogId(false).equals( + sipDialog.getLastAckSent().getDialogId(false))) { + // the last ack sent corresponded to this 200 + ackAlreadySent = true; + } + } + // 200 retransmission for the final response. + if (ackAlreadySent + && sipResponse.getCSeq().getMethod().equals(sipDialog.getMethod())) { + try { + // Found the dialog - resend the ACK and + // dont pass up the null transaction + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("resending ACK"); + + sipDialog.resendAck(); + return; + } catch (SipException ex) { + // What to do here ?? kill the dialog? + } + } + } + } + // Pass the response up to the application layer to handle + // statelessly. + + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("sending response to TU for processing "); + + if (sipDialog != null && sipResponse.getStatusCode() != 100 + && sipResponse.getTo().getTag() != null) { + sipDialog.setLastResponse(transaction, sipResponse); + } + + ResponseEventExt responseEvent = new ResponseEventExt(sipProvider, + (ClientTransactionExt) transaction, sipDialog, (Response) sipResponse); + + if (sipResponse.getCSeq().getMethod().equals(Request.INVITE)) { + ClientTransactionExt originalTx = this.sipStack.getForkedTransaction(sipResponse + .getTransactionId()); + responseEvent.setOriginalTransaction(originalTx); + } + + sipProvider.handleEvent(responseEvent, transaction); + + } +} diff --git a/java/gov/nist/javax/sip/DialogTimeoutEvent.java b/java/gov/nist/javax/sip/DialogTimeoutEvent.java new file mode 100644 index 0000000..53378f0 --- /dev/null +++ b/java/gov/nist/javax/sip/DialogTimeoutEvent.java @@ -0,0 +1,74 @@ +/* + * This source code has been contributed to the public domain by Mobicents + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip; + +import java.util.EventObject; + +import javax.sip.Dialog; + +/** + * + * DialogAckTimeoutEvent is delivered to the Listener when the + * dialog does not receive or send an ACK. + * + * + * @author jean deruelle + * @since v2.0 + * + */ +public class DialogTimeoutEvent extends EventObject { + private static final long serialVersionUID = -2514000059989311925L; + public enum Reason {AckNotReceived, AckNotSent,ReInviteTimeout}; + /** + * Constructs a DialogTerminatedEvent to indicate a dialog + * timeout. + * + * @param source - the source of TimeoutEvent. + * @param dialog - the dialog that timed out. + */ + public DialogTimeoutEvent(Object source, Dialog dialog, Reason reason) { + super(source); + m_dialog = dialog; + m_reason = reason; + + } + + /** + * Gets the Dialog associated with the event. This + * enables application developers to access the dialog associated to this + * event. + * + * @return the dialog associated with the response event or null if there is no dialog. + * @since v1.2 + */ + public Dialog getDialog() { + return m_dialog; + } + + /** + * The reason for the Dialog Timeout Event being delivered to the application. + * + * @return the reason for the timeout event. + */ + public Reason getReason() { + return m_reason; + } + + // internal variables + private Dialog m_dialog = null; + private Reason m_reason = null; +} + diff --git a/java/gov/nist/javax/sip/EventScanner.java b/java/gov/nist/javax/sip/EventScanner.java new file mode 100644 index 0000000..3e0b439 --- /dev/null +++ b/java/gov/nist/javax/sip/EventScanner.java @@ -0,0 +1,529 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip; + +import java.util.*; +import gov.nist.javax.sip.stack.*; +import gov.nist.javax.sip.message.*; +import javax.sip.message.*; +import javax.sip.*; +import gov.nist.core.ThreadAuditor; + +/* bug fixes SIPQuest communications and Shu-Lin Chen. */ + +/** + * Event Scanner to deliver events to the Listener. + * + * @version 1.2 $Revision: 1.41 $ $Date: 2009/11/18 02:35:17 $ + * + * @author M. Ranganathan <br/> + * + * + */ +class EventScanner implements Runnable { + + private boolean isStopped; + + private int refCount; + + // SIPquest: Fix for deadlocks + private LinkedList pendingEvents = new LinkedList(); + + private int[] eventMutex = { 0 }; + + private SipStackImpl sipStack; + + public void incrementRefcount() { + synchronized (eventMutex) { + this.refCount++; + } + } + + public EventScanner(SipStackImpl sipStackImpl) { + this.pendingEvents = new LinkedList(); + Thread myThread = new Thread(this); + // This needs to be set to false else the + // main thread mysteriously exits. + myThread.setDaemon(false); + + this.sipStack = sipStackImpl; + + myThread.setName("EventScannerThread"); + + myThread.start(); + + } + + public void addEvent(EventWrapper eventWrapper) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("addEvent " + eventWrapper); + synchronized (this.eventMutex) { + + pendingEvents.add(eventWrapper); + + // Add the event into the pending events list + + eventMutex.notify(); + } + + } + + /** + * Stop the event scanner. Decrement the reference count and exit the + * scanner thread if the ref count goes to 0. + */ + + public void stop() { + synchronized (eventMutex) { + + if (this.refCount > 0) + this.refCount--; + + if (this.refCount == 0) { + isStopped = true; + eventMutex.notify(); + + } + } + } + + /** + * Brutally stop the event scanner. This does not wait for the refcount to + * go to 0. + * + */ + public void forceStop() { + synchronized (this.eventMutex) { + this.isStopped = true; + this.refCount = 0; + this.eventMutex.notify(); + } + + } + + public void deliverEvent(EventWrapper eventWrapper) { + EventObject sipEvent = eventWrapper.sipEvent; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "sipEvent = " + sipEvent + "source = " + + sipEvent.getSource()); + SipListener sipListener = null; + + if (!(sipEvent instanceof IOExceptionEvent)) { + sipListener = ((SipProviderImpl) sipEvent.getSource()).getSipListener(); + } else { + sipListener = sipStack.getSipListener(); + } + + if (sipEvent instanceof RequestEvent) { + try { + // Check if this request has already created a + // transaction + SIPRequest sipRequest = (SIPRequest) ((RequestEvent) sipEvent) + .getRequest(); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "deliverEvent : " + + sipRequest.getFirstLine() + + " transaction " + + eventWrapper.transaction + + " sipEvent.serverTx = " + + ((RequestEvent) sipEvent) + .getServerTransaction()); + } + + // Discard the duplicate request if a + // transaction already exists. If the listener chose + // to handle the request statelessly, then the listener + // will see the retransmission. + // Note that in both of these two cases, JAIN SIP will allow + // you to handle the request statefully or statelessly. + // An example of the latter case is REGISTER and an example + // of the former case is INVITE. + + SIPServerTransaction tx = (SIPServerTransaction) sipStack + .findTransaction(sipRequest, true); + + if (tx != null && !tx.passToListener()) { + + // JvB: make an exception for a very rare case: some + // (broken) UACs use + // the same branch parameter for an ACK. Such an ACK should + // be passed + // to the listener (tx == INVITE ST, terminated upon sending + // 2xx but + // lingering to catch retransmitted INVITEs) + if (sipRequest.getMethod().equals(Request.ACK) + && tx.isInviteTransaction() && + ( tx.getLastResponse().getStatusCode()/100 == 2 || + sipStack.isNon2XXAckPassedToListener())) { + + if (sipStack.isLoggingEnabled()) + sipStack + .getStackLogger() + .logDebug( + "Detected broken client sending ACK with same branch! Passing..."); + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "transaction already exists! " + tx); + return; + } + } else if (sipStack.findPendingTransaction(sipRequest) != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "transaction already exists!!"); + + return; + } else { + // Put it in the pending list so that if a repeat + // request comes along it will not get assigned a + // new transaction + SIPServerTransaction st = (SIPServerTransaction) eventWrapper.transaction; + sipStack.putPendingTransaction(st); + } + + // Set up a pointer to the transaction. + sipRequest.setTransaction(eventWrapper.transaction); + // Change made by SIPquest + try { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger() + .logDebug( + "Calling listener " + + sipRequest.getFirstLine()); + sipStack.getStackLogger().logDebug( + "Calling listener " + eventWrapper.transaction); + } + if (sipListener != null) + sipListener.processRequest((RequestEvent) sipEvent); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Done processing Message " + + sipRequest.getFirstLine()); + } + if (eventWrapper.transaction != null) { + + SIPDialog dialog = (SIPDialog) eventWrapper.transaction + .getDialog(); + if (dialog != null) + dialog.requestConsumed(); + + } + } catch (Exception ex) { + // We cannot let this thread die under any + // circumstances. Protect ourselves by logging + // errors to the console but continue. + sipStack.getStackLogger().logException(ex); + } + } finally { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Done processing Message " + + ((SIPRequest) (((RequestEvent) sipEvent) + .getRequest())).getFirstLine()); + } + if (eventWrapper.transaction != null + && ((SIPServerTransaction) eventWrapper.transaction) + .passToListener()) { + ((SIPServerTransaction) eventWrapper.transaction) + .releaseSem(); + } + + if (eventWrapper.transaction != null) + sipStack + .removePendingTransaction((SIPServerTransaction) eventWrapper.transaction); + if (eventWrapper.transaction.getOriginalRequest().getMethod() + .equals(Request.ACK)) { + // Set the tx state to terminated so it is removed from the + // stack + // if the user configured to get notification on ACK + // termination + eventWrapper.transaction + .setState(TransactionState.TERMINATED); + } + } + + } else if (sipEvent instanceof ResponseEvent) { + try { + ResponseEvent responseEvent = (ResponseEvent) sipEvent; + SIPResponse sipResponse = (SIPResponse) responseEvent + .getResponse(); + SIPDialog sipDialog = ((SIPDialog) responseEvent.getDialog()); + try { + if (sipStack.isLoggingEnabled()) { + + sipStack.getStackLogger().logDebug( + "Calling listener for " + + sipResponse.getFirstLine()); + } + if (sipListener != null) { + SIPTransaction tx = eventWrapper.transaction; + if (tx != null) { + tx.setPassToListener(); + } + sipListener.processResponse((ResponseEvent) sipEvent); + } + + /* + * If the response for a request within a dialog is a 481 + * (Call/Transaction Does Not Exist) or a 408 (Request + * Timeout), the UAC SHOULD terminate the dialog. + */ + if ((sipDialog != null && (sipDialog.getState() == null || !sipDialog + .getState().equals(DialogState.TERMINATED))) + && (sipResponse.getStatusCode() == Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST || sipResponse + .getStatusCode() == Response.REQUEST_TIMEOUT)) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Removing dialog on 408 or 481 response"); + } + sipDialog.doDeferredDelete(); + } + + /* + * The Client tx disappears after the first 2xx response + * However, additional 2xx responses may arrive later for + * example in the following scenario: + * + * Multiple 2xx responses may arrive at the UAC for a single + * INVITE request due to a forking proxy. Each response is + * distinguished by the tag parameter in the To header + * field, and each represents a distinct dialog, with a + * distinct dialog identifier. + * + * If the Listener does not ACK the 200 then we assume he + * does not care about the dialog and gc the dialog after + * some time. However, this is really an application bug. + * This garbage collects unacknowledged dialogs. + * + */ + if (sipResponse.getCSeq().getMethod() + .equals(Request.INVITE) + && sipDialog != null + && sipResponse.getStatusCode() == 200) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Warning! unacknowledged dialog. " + sipDialog.getState()); + } + /* + * If we dont see an ACK in 32 seconds, we want to tear down the dialog. + */ + sipDialog.doDeferredDeleteIfNoAckSent(sipResponse.getCSeq().getSeqNumber()); + } + } catch (Exception ex) { + // We cannot let this thread die under any + // circumstances. Protect ourselves by logging + // errors to the console but continue. + sipStack.getStackLogger().logException(ex); + } + // The original request is not needed except for INVITE + // transactions -- null the pointers to the transactions so + // that state may be released. + SIPClientTransaction ct = (SIPClientTransaction) eventWrapper.transaction; + if (ct != null + && TransactionState.COMPLETED == ct.getState() + && ct.getOriginalRequest() != null + && !ct.getOriginalRequest().getMethod().equals( + Request.INVITE)) { + // reduce the state to minimum + // This assumes that the application will not need + // to access the request once the transaction is + // completed. + ct.clearState(); + } + // mark no longer in the event queue. + } finally { + if (eventWrapper.transaction != null + && eventWrapper.transaction.passToListener()) { + eventWrapper.transaction.releaseSem(); + } + } + + } else if (sipEvent instanceof TimeoutEvent) { + // Change made by SIPquest + try { + // Check for null as listener could be removed. + if (sipListener != null) + sipListener.processTimeout((TimeoutEvent) sipEvent); + } catch (Exception ex) { + // We cannot let this thread die under any + // circumstances. Protect ourselves by logging + // errors to the console but continue. + sipStack.getStackLogger().logException(ex); + } + + } else if (sipEvent instanceof DialogTimeoutEvent) { + try { + // Check for null as listener could be removed. + if (sipListener != null && sipListener instanceof SipListenerExt) { + ((SipListenerExt)sipListener).processDialogTimeout((DialogTimeoutEvent) sipEvent); + } + } catch (Exception ex) { + // We cannot let this thread die under any + // circumstances. Protect ourselves by logging + // errors to the console but continue. + sipStack.getStackLogger().logException(ex); + } + + } else if (sipEvent instanceof IOExceptionEvent) { + try { + if (sipListener != null) + sipListener.processIOException((IOExceptionEvent) sipEvent); + } catch (Exception ex) { + sipStack.getStackLogger().logException(ex); + } + } else if (sipEvent instanceof TransactionTerminatedEvent) { + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "About to deliver transactionTerminatedEvent"); + sipStack.getStackLogger().logDebug( + "tx = " + + ((TransactionTerminatedEvent) sipEvent) + .getClientTransaction()); + sipStack.getStackLogger().logDebug( + "tx = " + + ((TransactionTerminatedEvent) sipEvent) + .getServerTransaction()); + + } + if (sipListener != null) + sipListener + .processTransactionTerminated((TransactionTerminatedEvent) sipEvent); + } catch (AbstractMethodError ame) { + // JvB: for backwards compatibility, accept this + if (sipStack.isLoggingEnabled()) + sipStack + .getStackLogger() + .logWarning( + "Unable to call sipListener.processTransactionTerminated"); + } catch (Exception ex) { + sipStack.getStackLogger().logException(ex); + } + } else if (sipEvent instanceof DialogTerminatedEvent) { + try { + if (sipListener != null) + sipListener + .processDialogTerminated((DialogTerminatedEvent) sipEvent); + } catch (AbstractMethodError ame) { + // JvB: for backwards compatibility, accept this + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning( + "Unable to call sipListener.processDialogTerminated"); + } catch (Exception ex) { + sipStack.getStackLogger().logException(ex); + } + } else { + + sipStack.getStackLogger().logFatalError("bad event" + sipEvent); + } + + } + + /** + * For the non-re-entrant listener this delivers the events to the listener + * from a single queue. If the listener is re-entrant, then the stack just + * calls the deliverEvent method above. + */ + + public void run() { + try { + // Ask the auditor to monitor this thread + ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread(); + + while (true) { + EventWrapper eventWrapper = null; + + LinkedList eventsToDeliver; + synchronized (this.eventMutex) { + // First, wait for some events to become available. + while (pendingEvents.isEmpty()) { + // There's nothing in the list, check to make sure we + // haven't + // been stopped. If we have, then let the thread die. + if (this.isStopped) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Stopped event scanner!!"); + return; + } + + // We haven't been stopped, and the event list is indeed + // rather empty. Wait for some events to come along. + try { + // Send a heartbeat to the thread auditor + threadHandle.ping(); + + // Wait for events (with a timeout) + eventMutex.wait(threadHandle.getPingIntervalInMillisecs()); + } catch (InterruptedException ex) { + // Let the thread die a normal death + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Interrupted!"); + return; + } + } + + // There are events in the 'pending events list' that need + // processing. Hold onto the old 'pending Events' list, but + // make a new one for the other methods to operate on. This + // tap-dancing is to avoid deadlocks and also to ensure that + // the list is not modified while we are iterating over it. + eventsToDeliver = pendingEvents; + pendingEvents = new LinkedList(); + } + ListIterator iterator = eventsToDeliver.listIterator(); + while (iterator.hasNext()) { + eventWrapper = (EventWrapper) iterator.next(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Processing " + eventWrapper + "nevents " + + eventsToDeliver.size()); + } + try { + deliverEvent(eventWrapper); + } catch (Exception e) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError( + "Unexpected exception caught while delivering event -- carrying on bravely", e); + } + } + } + } // end While + } finally { + if (sipStack.isLoggingEnabled()) { + if (!this.isStopped) { + sipStack.getStackLogger().logFatalError("Event scanner exited abnormally"); + } + } + } + } + +} diff --git a/java/gov/nist/javax/sip/EventWrapper.java b/java/gov/nist/javax/sip/EventWrapper.java new file mode 100644 index 0000000..fb583dc --- /dev/null +++ b/java/gov/nist/javax/sip/EventWrapper.java @@ -0,0 +1,44 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip; + +import gov.nist.javax.sip.stack.*; +import java.util.*; + +/** + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:19 $ + */ +class EventWrapper { + + protected EventObject sipEvent; + protected SIPTransaction transaction; + + EventWrapper(EventObject sipEvent, SIPTransaction transaction) { + this.sipEvent = sipEvent; + this.transaction = transaction; + } +} + diff --git a/java/gov/nist/javax/sip/ListeningPointExt.java b/java/gov/nist/javax/sip/ListeningPointExt.java new file mode 100644 index 0000000..a14d1d9 --- /dev/null +++ b/java/gov/nist/javax/sip/ListeningPointExt.java @@ -0,0 +1,41 @@ +package gov.nist.javax.sip; + +import java.io.IOException; + +import javax.sip.ListeningPoint; +import javax.sip.header.ContactHeader; +import javax.sip.header.ViaHeader; + +public interface ListeningPointExt extends ListeningPoint { + + /** + * Create a contact for this listening point. + * + * @return a contact header corresponding to this listening point. + * + * @since 2.0 + * + */ + + ContactHeader createContactHeader() ; + + /** + * Send a heartbeat to the specified Ip address and port + * via this listening point. This method can be used to send out a period + * CR-LF for NAT keepalive. + * + * @since 2.0 + */ + public void sendHeartbeat(String ipAddress, int port) throws IOException ; + + /** + * Create a Via header for this listening point. + * + * @return a via header corresponding to this listening point. Branch ID is set to NULL. + * + * @since 2.0 + */ + public ViaHeader createViaHeader(); + + +} diff --git a/java/gov/nist/javax/sip/ListeningPointImpl.java b/java/gov/nist/javax/sip/ListeningPointImpl.java new file mode 100644 index 0000000..8d203c6 --- /dev/null +++ b/java/gov/nist/javax/sip/ListeningPointImpl.java @@ -0,0 +1,263 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.ParseException; + +import javax.sip.*; +import javax.sip.address.SipURI; +import javax.sip.header.ContactHeader; +import javax.sip.header.ViaHeader; + +import gov.nist.core.Host; +import gov.nist.core.HostPort; +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.stack.*; + +/** + * Implementation of the ListeningPoint interface + * + * @version 1.2 $Revision: 1.15 $ $Date: 2009/11/19 05:26:58 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ListeningPointImpl implements javax.sip.ListeningPoint, gov.nist.javax.sip.ListeningPointExt { + + + protected String transport; + + /** My port. (same thing as in the message processor) */ + + int port; + + /** + * Pointer to the imbedded mesage processor. + */ + protected MessageProcessor messageProcessor; + + /** + * Provider back pointer + */ + protected SipProviderImpl sipProvider; + + /** + * Our stack + */ + protected SipStackImpl sipStack; + + + + + /** + * Construct a key to refer to this structure from the SIP stack + * @param host host string + * @param port port + * @param transport transport + * @return a string that is used as a key + */ + public static String makeKey(String host, int port, String transport) { + return new StringBuffer(host) + .append(":") + .append(port) + .append("/") + .append(transport) + .toString() + .toLowerCase(); + } + + /** + * Get the key for this strucut + * @return get the host + */ + protected String getKey() { + return makeKey(this.getIPAddress(), port, transport); + } + + /** + * Set the sip provider for this structure. + * @param sipProvider provider to set + */ + protected void setSipProvider(SipProviderImpl sipProviderImpl) { + this.sipProvider = sipProviderImpl; + } + + /** + * Remove the sip provider from this listening point. + */ + protected void removeSipProvider() { + this.sipProvider = null; + } + + /** + * Constructor + * @param sipStack Our sip stack + */ + protected ListeningPointImpl( + SipStack sipStack, + int port, + String transport) { + this.sipStack = (SipStackImpl) sipStack; + + this.port = port; + this.transport = transport; + + } + + /** + * Clone this listening point. Note that a message Processor is not + * started. The transport is set to null. + * @return cloned listening point. + */ + public Object clone() { + ListeningPointImpl lip = + new ListeningPointImpl(this.sipStack, this.port, null); + lip.sipStack = this.sipStack; + return lip; + } + + + + /** + * Gets the port of the ListeningPoint. The default port of a ListeningPoint + * is dependent on the scheme and transport. For example: + * <ul> + * <li>The default port is 5060 if the transport UDP the scheme is <i>sip:</i>. + * <li>The default port is 5060 if the transport is TCP the scheme is <i>sip:</i>. + * <li>The default port is 5060 if the transport is SCTP the scheme is <i>sip:</i>. + * <li>The default port is 5061 if the transport is TLS over TCP the scheme is <i>sip:</i>. + * <li>The default port is 5061 if the transport is TCP the scheme is <i>sips:</i>. + * </ul> + * + * @return port of ListeningPoint + */ + public int getPort() { + return messageProcessor.getPort(); + } + + /** + * Gets transport of the ListeningPoint. + * + * @return transport of ListeningPoint + */ + public String getTransport() { + return messageProcessor.getTransport(); + } + + /** + * Get the provider. + * + * @return the provider. + */ + public SipProviderImpl getProvider() { + return this.sipProvider; + } + + /* (non-Javadoc) + * @see javax.sip.ListeningPoint#getIPAddress() + */ + public String getIPAddress() { + + return this.messageProcessor.getIpAddress().getHostAddress(); + } + + + + /* (non-Javadoc) + * @see javax.sip.ListeningPoint#setSentBy(java.lang.String) + */ + public void setSentBy(String sentBy) throws ParseException { + this.messageProcessor.setSentBy(sentBy); + + } + + /* (non-Javadoc) + * @see javax.sip.ListeningPoint#getSentBy() + */ + public String getSentBy() { + + return this.messageProcessor.getSentBy(); + } + + public boolean isSentBySet() { + return this.messageProcessor.isSentBySet(); + } + public Via getViaHeader() { + return this.messageProcessor.getViaHeader(); + } + + public MessageProcessor getMessageProcessor() { + return this.messageProcessor; + } + + public ContactHeader createContactHeader() { + try { + String ipAddress = this.getIPAddress(); + int port = this.getPort(); + SipURI sipURI = new SipUri(); + sipURI.setHost(ipAddress); + sipURI.setPort(port); + sipURI.setTransportParam(this.transport); + Contact contact = new Contact(); + AddressImpl address = new AddressImpl(); + address.setURI(sipURI); + contact.setAddress(address); + + return contact; + } catch (Exception ex) { + InternalErrorHandler.handleException("Unexpected exception",sipStack.getStackLogger()); + return null; + } + } + + + public void sendHeartbeat(String ipAddress, int port) throws IOException { + + HostPort targetHostPort = new HostPort(); + targetHostPort.setHost(new Host( ipAddress)); + targetHostPort.setPort(port); + MessageChannel messageChannel = this.messageProcessor.createMessageChannel(targetHostPort); + SIPRequest siprequest = new SIPRequest(); + siprequest.setNullRequest(); + messageChannel.sendMessage(siprequest); + + } + + + public ViaHeader createViaHeader() { + return this.getViaHeader(); + } + +} diff --git a/java/gov/nist/javax/sip/LogRecord.java b/java/gov/nist/javax/sip/LogRecord.java new file mode 100644 index 0000000..e55cc50 --- /dev/null +++ b/java/gov/nist/javax/sip/LogRecord.java @@ -0,0 +1,20 @@ +package gov.nist.javax.sip; + +/** + * The interface for a log record. The log records are generated by calling the + * LogReocrdFactory instance that is registered with the stack. + * + * @author M. Ranganathan + * + */ +public interface LogRecord { + + public abstract boolean equals(Object other); + + /** + * Get an XML String for this message + */ + + public abstract String toString(); + +} diff --git a/java/gov/nist/javax/sip/LogRecordFactory.java b/java/gov/nist/javax/sip/LogRecordFactory.java new file mode 100644 index 0000000..992ab83 --- /dev/null +++ b/java/gov/nist/javax/sip/LogRecordFactory.java @@ -0,0 +1,37 @@ +package gov.nist.javax.sip; + + +/** + * The stack calls the message log factory to create logging records. The default implementatation + * of this interface can be replaced using the gov.nist.javax.sip.LOG_RECORD_FACTORY property. + * This override is provided to allow applications to log axuiliary information (such as environment + * conditions etc) when messages are logged in the stack. + * + * @author M. Ranganathan + * + */ +public interface LogRecordFactory { + + /** + * Create a log record. + * + * @param message -- the message to be logged. + * @param source -- host:port of the source of the message. + * @param destination -- host:port of the destination of the message. + * @param timeStamp -- The time at which this message was seen by the stack or sent out by + * the stack. + * @param isSender -- true if we are sending the message false otherwise. + * @param firstLine -- the first line of the message to be logged. + * @param tid -- the transaction id + * @param callId -- the call id + * @param timestampVal -- the timestamp header value of the incoming message. + * + * @return -- a log record with the appropriate fields set. + */ + + + public LogRecord createLogRecord(String message, String source, + String destination, long timeStamp, boolean isSender, + String firstLine, String tid, String callId, long timestampVal); + +} diff --git a/java/gov/nist/javax/sip/NistSipMessageFactoryImpl.java b/java/gov/nist/javax/sip/NistSipMessageFactoryImpl.java new file mode 100644 index 0000000..be85863 --- /dev/null +++ b/java/gov/nist/javax/sip/NistSipMessageFactoryImpl.java @@ -0,0 +1,147 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ + +package gov.nist.javax.sip; + +import gov.nist.javax.sip.stack.*; +import gov.nist.javax.sip.message.*; +import javax.sip.*; + +/** + * Implements all the support classes that are necessary for the nist-sip stack + * on which the jain-sip stack has been based. This is a mapping class to map + * from the NIST-SIP abstractions to the JAIN abstractions. (i.e. It is the glue + * code that ties the NIST-SIP event model and the JAIN-SIP event model + * together. When a SIP Request or SIP Response is read from the corresponding + * messageChannel, the NIST-SIP stack calls the SIPStackMessageFactory + * implementation that has been registered with it to process the request.) + * + * @version 1.2 $Revision: 1.14 $ $Date: 2009/07/29 20:38:17 $ + * + * @author M. Ranganathan <br/> + * + * + */ +class NistSipMessageFactoryImpl implements StackMessageFactory { + + private SipStackImpl sipStack; + + /** + * Construct a new SIP Server Request. + * + * @param sipRequest + * is the SIPRequest from which the SIPServerRequest is to be + * constructed. + * @param messageChannel + * is the MessageChannel abstraction for this SIPServerRequest. + */ + public ServerRequestInterface newSIPServerRequest(SIPRequest sipRequest, + MessageChannel messageChannel) { + + if (messageChannel == null || sipRequest == null) { + throw new IllegalArgumentException("Null Arg!"); + } + + SipStackImpl theStack = (SipStackImpl) messageChannel.getSIPStack(); + DialogFilter retval = new DialogFilter( + theStack); + if (messageChannel instanceof SIPTransaction) { + // If the transaction has already been created + // then set the transaction channel. + retval.transactionChannel = (SIPTransaction) messageChannel; + } + retval.listeningPoint = messageChannel.getMessageProcessor() + .getListeningPoint(); + if (retval.listeningPoint == null) + return null; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Returning request interface for " + + sipRequest.getFirstLine() + " " + retval + + " messageChannel = " + messageChannel); + return retval; + } + + /** + * Generate a new server response for the stack. + * + * @param sipResponse + * is the SIPRequest from which the SIPServerRequest is to be + * constructed. + * @param messageChannel + * is the MessageChannel abstraction for this SIPServerResponse + */ + public ServerResponseInterface newSIPServerResponse( + SIPResponse sipResponse, MessageChannel messageChannel) { + SIPTransactionStack theStack = (SIPTransactionStack) messageChannel + .getSIPStack(); + // Tr is null if a transaction is not mapped. + SIPTransaction tr = (SIPTransaction) ((SIPTransactionStack) theStack) + .findTransaction(sipResponse, false); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Found Transaction " + tr + " for " + sipResponse); + + if (tr != null) { + // Prune unhealthy responses early if handling statefully. + // If the state has not yet been assigned then this is a + // spurious response. This was moved up from the transaction + // layer for efficiency. + if (tr.getState() == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping response - null transaction state"); + return null; + // Ignore 1xx + } else if (TransactionState.COMPLETED == tr.getState() + && sipResponse.getStatusCode() / 100 == 1) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping response - late arriving " + + sipResponse.getStatusCode()); + return null; + } + } + + DialogFilter retval = new DialogFilter( + sipStack); + + retval.transactionChannel = tr; + + retval.listeningPoint = messageChannel.getMessageProcessor() + .getListeningPoint(); + return retval; + } + + public NistSipMessageFactoryImpl(SipStackImpl sipStackImpl) { + this.sipStack = sipStackImpl; + + } + +}
\ No newline at end of file diff --git a/java/gov/nist/javax/sip/ResponseEventExt.java b/java/gov/nist/javax/sip/ResponseEventExt.java new file mode 100644 index 0000000..1b175c6 --- /dev/null +++ b/java/gov/nist/javax/sip/ResponseEventExt.java @@ -0,0 +1,50 @@ +package gov.nist.javax.sip; + +import javax.sip.ClientTransaction; +import javax.sip.Dialog; +import javax.sip.ResponseEvent; +import javax.sip.message.Response; + +/** + * Extension for ResponseEvent. + * + * @since v2.0 + */ +public class ResponseEventExt extends ResponseEvent { + private ClientTransactionExt m_originalTransaction; + public ResponseEventExt(Object source, ClientTransactionExt clientTransaction, + Dialog dialog, Response response) { + super(source,clientTransaction,dialog,response); + m_originalTransaction = clientTransaction; + } + + /** + * Return true if this is a forked response. + * + * @return true if the response event is for a forked response. + */ + public boolean isForkedResponse() { + return super.getClientTransaction() == null && m_originalTransaction != null; + } + + /** + * Set the original transaction for a forked response. + * + * @param originalTransaction - the original transaction for which this response event is a fork. + */ + public void setOriginalTransaction(ClientTransactionExt originalTransaction ) { + m_originalTransaction = originalTransaction; + } + + /** + * Get the original transaction for which this is a forked response. + * Note that this transaction can be in a TERMINATED state. + * + * @return the original clientTx for which this is a forked response. + */ + public ClientTransactionExt getOriginalTransaction() { + return this.m_originalTransaction; + } + + +} diff --git a/java/gov/nist/javax/sip/SIPConstants.java b/java/gov/nist/javax/sip/SIPConstants.java new file mode 100644 index 0000000..3de9431 --- /dev/null +++ b/java/gov/nist/javax/sip/SIPConstants.java @@ -0,0 +1,63 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.javax.sip; + +import gov.nist.javax.sip.header.*; + +/** + * Default constants for SIP. + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:20 $ + */ +public interface SIPConstants + extends + SIPHeaderNames, + gov.nist.javax.sip.address.ParameterNames, + gov.nist.javax.sip.header.ParameterNames { + public static final int DEFAULT_PORT = 5060; + + // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + public static final int DEFAULT_TLS_PORT = 5061; + + /** + * Prefix for the branch parameter that identifies + * BIS 09 compatible branch strings. This indicates + * that the branch may be as a global identifier for + * identifying transactions. + */ + public static final String BRANCH_MAGIC_COOKIE = "z9hG4bK"; + + public static final String BRANCH_MAGIC_COOKIE_LOWER_CASE = "z9hg4bk"; + + public static final String BRANCH_MAGIC_COOKIE_UPPER_CASE = "Z9HG4BK"; + + /** + * constant SIP_VERSION_STRING + */ + public static final String SIP_VERSION_STRING = "SIP/2.0"; +} diff --git a/java/gov/nist/javax/sip/ServerTransactionExt.java b/java/gov/nist/javax/sip/ServerTransactionExt.java new file mode 100644 index 0000000..2871e31 --- /dev/null +++ b/java/gov/nist/javax/sip/ServerTransactionExt.java @@ -0,0 +1,15 @@ +package gov.nist.javax.sip; + +import javax.sip.ServerTransaction; + + +public interface ServerTransactionExt extends ServerTransaction, TransactionExt { + /** + * Return the canceled Invite transaction corresponding to an + * incoming CANCEL server transaction. + * + * @return -- the canceled Invite transaction. + * + */ + public ServerTransaction getCanceledInviteTransaction(); +} diff --git a/java/gov/nist/javax/sip/SipListenerExt.java b/java/gov/nist/javax/sip/SipListenerExt.java new file mode 100644 index 0000000..09fc45f --- /dev/null +++ b/java/gov/nist/javax/sip/SipListenerExt.java @@ -0,0 +1,49 @@ +/* + * This source code has been contributed to the public domain by Mobicents + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip; + +import javax.sip.Dialog; +import javax.sip.SipListener; + +/** + * This interface extends the {@link SipListener} interface and adds the following events to it : + * <ul> + * <li>{@link DialogTimeoutEvent}- these are timeout notifications emitted as events by the + * SipProvider. Timeout events represent timers expiring in the underlying SipProvider dialog + * state machine. These timeout's events notify the application that a dialog has timed out.</li> + * </ul> + * + * @author jean.deruelle@gmail.com + * + */ +public interface SipListenerExt extends SipListener { + + /** + * Processes an expiration Timeout of an underlying {@link Dialog} handled by this + * SipListener. This Event notifies the application that a dialog Timer expired in the + * Dialog's state machine. Such a condition can occur when the application fails to send an + * ACK after receiving an OK response or if an ACK is not received after an OK is sent. The + * DialogTimeoutEvent encapsulates the specific timeout type and the dialog identifier. The + * type of Timeout can by determined by: + * <code>timeoutType = timeoutEvent.getTimeout().getValue();</code> + * + * Applications implementing this method should take care of sending the BYE or terminating + * the dialog to avoid any dialog leaks. + * + * @param timeoutEvent - the timeoutEvent received indicating the dialog timed out. + */ + public void processDialogTimeout(DialogTimeoutEvent timeoutEvent); +} diff --git a/java/gov/nist/javax/sip/SipProviderExt.java b/java/gov/nist/javax/sip/SipProviderExt.java new file mode 100644 index 0000000..d955aca --- /dev/null +++ b/java/gov/nist/javax/sip/SipProviderExt.java @@ -0,0 +1,40 @@ +package gov.nist.javax.sip; + +import javax.sip.SipProvider; + +/** + * Extensions to SipProvider under consideration for Version 2.0. + * + * @since 2.0 + */ + +public interface SipProviderExt extends SipProvider { + /** + * Sets a flag that indicates that automatic error handling is enabled for this dialog (the + * default when automatic dialog support is enabled). This flag is set by default to TRUE when + * the Dialog is automatically created by the provider ( automatic dialog support is true) and + * set to FALSE by default when the Dialog is created under program control ( automatic dialog + * support is false). When this flag is set to true, the stack will automatically send the + * following errors : + * + * <ul> + * <li> <b>500 Request Out of Order </b> for in-dialog requests that arrive out of order. + * <li> <b>482 Loop Detected </b> When a loop is detected for merged INVITE requests. + * <li> <b>400 Bad request </b> when a REFER is sent without a matching refer-to dialog. + * </ul> + * If this flag is set to false, the stack will not drop out of sequence ACKs but will pass + * these up to the application for handling. + * + * This flag is automatically set to true if any of the the following conditions is true: + * <ul> + * <li>The Back To Back User Agent flag is enabled for the Dialog.</li> + * <li>The Automatic Dialog Support flag is enabled for the Dialog </li> + * </ul> + * + * This flag should only be set at the time of Dialog creation ( before the Dialog has seen its first + * request or response). If set subsequently, the behavior of the flag is undefined. + * + * @since 2.0 + */ + public void setDialogErrorsAutomaticallyHandled(); +} diff --git a/java/gov/nist/javax/sip/SipProviderImpl.java b/java/gov/nist/javax/sip/SipProviderImpl.java new file mode 100644 index 0000000..84c4c3d --- /dev/null +++ b/java/gov/nist/javax/sip/SipProviderImpl.java @@ -0,0 +1,1116 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.DialogTimeoutEvent.Reason; +import gov.nist.javax.sip.address.RouterExt; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; +import gov.nist.javax.sip.stack.HopImpl; +import gov.nist.javax.sip.stack.MessageChannel; +import gov.nist.javax.sip.stack.SIPClientTransaction; +import gov.nist.javax.sip.stack.SIPDialog; +import gov.nist.javax.sip.stack.SIPDialogErrorEvent; +import gov.nist.javax.sip.stack.SIPDialogEventListener; +import gov.nist.javax.sip.stack.SIPServerTransaction; +import gov.nist.javax.sip.stack.SIPTransaction; +import gov.nist.javax.sip.stack.SIPTransactionErrorEvent; +import gov.nist.javax.sip.stack.SIPTransactionEventListener; + +import java.io.IOException; +import java.text.ParseException; +import java.util.EventObject; +import java.util.Iterator; +import java.util.TooManyListenersException; +import java.util.concurrent.ConcurrentHashMap; + +import javax.sip.ClientTransaction; +import javax.sip.Dialog; +import javax.sip.DialogState; +import javax.sip.InvalidArgumentException; +import javax.sip.ListeningPoint; +import javax.sip.ObjectInUseException; +import javax.sip.RequestEvent; +import javax.sip.ResponseEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.SipListener; +import javax.sip.SipStack; +import javax.sip.Timeout; +import javax.sip.TimeoutEvent; +import javax.sip.Transaction; +import javax.sip.TransactionAlreadyExistsException; +import javax.sip.TransactionState; +import javax.sip.TransactionUnavailableException; +import javax.sip.address.Hop; +import javax.sip.header.CallIdHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Contributions (bug fixes) made by: Daniel J. Martinez Manzano, Hagai Sela. + * Bug reports by Shanti Kadiyala, Rhys Ulerich,Victor Hugo + */ +/** + * Implementation of the JAIN-SIP provider interface. + * + * @version 1.2 $Revision: 1.82 $ $Date: 2009/11/24 17:16:59 $ + * + * @author M. Ranganathan <br/> + * + * + */ + +public class SipProviderImpl implements javax.sip.SipProvider, gov.nist.javax.sip.SipProviderExt, + SIPTransactionEventListener, SIPDialogEventListener { + + private SipListener sipListener; + + protected SipStackImpl sipStack; + + /* + * A set of listening points associated with the provider At most one LP per + * transport + */ + private ConcurrentHashMap listeningPoints; + + private EventScanner eventScanner; + + private String address; + + private int port; + + private boolean automaticDialogSupportEnabled ; + /** + * A string containing the 0.0.0.0 IPv4 ANY address. + */ + private String IN_ADDR_ANY = "0.0.0.0"; + + /** + * A string containing the ::0 IPv6 ANY address. + */ + private String IN6_ADDR_ANY = "::0"; + + private boolean dialogErrorsAutomaticallyHandled = true; + + private SipProviderImpl() { + + } + + /** + * Stop processing messages for this provider. Post an empty message to our + * message processing queue that signals us to quit. + */ + protected void stop() { + // Put an empty event in the queue and post ourselves a message. + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Exiting provider"); + for (Iterator it = listeningPoints.values().iterator(); it.hasNext();) { + ListeningPointImpl listeningPoint = (ListeningPointImpl) it.next(); + listeningPoint.removeSipProvider(); + } + this.eventScanner.stop(); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getListeningPoint(java.lang.String) + */ + public ListeningPoint getListeningPoint(String transport) { + if (transport == null) + throw new NullPointerException("Null transport param"); + return (ListeningPoint) this.listeningPoints.get(transport + .toUpperCase()); + } + + /** + * Handle the SIP event - because we have only one listener and we are + * already in the context of a separate thread, we dont need to enque the + * event and signal another thread. + * + * @param sipEvent + * is the event to process. + * + */ + + public void handleEvent(EventObject sipEvent, SIPTransaction transaction) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "handleEvent " + sipEvent + "currentTransaction = " + + transaction + "this.sipListener = " + + this.getSipListener() + "sipEvent.source = " + + sipEvent.getSource()); + if (sipEvent instanceof RequestEvent) { + Dialog dialog = ((RequestEvent) sipEvent).getDialog(); + if ( sipStack.isLoggingEnabled()) sipStack.getStackLogger().logDebug("Dialog = " + dialog); + } else if (sipEvent instanceof ResponseEvent) { + Dialog dialog = ((ResponseEvent) sipEvent).getDialog(); + if (sipStack.isLoggingEnabled() ) sipStack.getStackLogger().logDebug("Dialog = " + dialog); + } + sipStack.getStackLogger().logStackTrace(); + } + + EventWrapper eventWrapper = new EventWrapper(sipEvent, transaction); + + if (!sipStack.reEntrantListener) { + // Run the event in the context of a single thread. + this.eventScanner.addEvent(eventWrapper); + } else { + // just call the delivery method + this.eventScanner.deliverEvent(eventWrapper); + } + } + + /** Creates a new instance of SipProviderImpl */ + protected SipProviderImpl(SipStackImpl sipStack) { + this.eventScanner = sipStack.getEventScanner(); // for quick access. + this.sipStack = sipStack; + this.eventScanner.incrementRefcount(); + this.listeningPoints = new ConcurrentHashMap<String,ListeningPointImpl>(); + this.automaticDialogSupportEnabled = this.sipStack + .isAutomaticDialogSupportEnabled(); + this.dialogErrorsAutomaticallyHandled = this.sipStack.isAutomaticDialogErrorHandlingEnabled(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#clone() + */ + protected Object clone() throws java.lang.CloneNotSupportedException { + throw new java.lang.CloneNotSupportedException(); + } + + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#addSipListener(javax.sip.SipListener) + */ + public void addSipListener(SipListener sipListener) + throws TooManyListenersException { + + if (sipStack.sipListener == null) { + sipStack.sipListener = sipListener; + } else if (sipStack.sipListener != sipListener) { + throw new TooManyListenersException( + "Stack already has a listener. Only one listener per stack allowed"); + } + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("add SipListener " + sipListener); + this.sipListener = sipListener; + + } + + /* + * This method is deprecated (non-Javadoc) + * + * @see javax.sip.SipProvider#getListeningPoint() + */ + + public ListeningPoint getListeningPoint() { + if (this.listeningPoints.size() > 0) + return (ListeningPoint) this.listeningPoints.values().iterator() + .next(); + else + return null; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getNewCallId() + */ + public CallIdHeader getNewCallId() { + String callId = Utils.getInstance().generateCallIdentifier(this.getListeningPoint() + .getIPAddress()); + CallID callid = new CallID(); + try { + callid.setCallId(callId); + } catch (java.text.ParseException ex) { + } + return callid; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getNewClientTransaction(javax.sip.message.Request) + */ + public ClientTransaction getNewClientTransaction(Request request) + throws TransactionUnavailableException { + if (request == null) + throw new NullPointerException("null request"); + if (!sipStack.isAlive()) + throw new TransactionUnavailableException("Stack is stopped"); + + SIPRequest sipRequest = (SIPRequest) request; + if (sipRequest.getTransaction() != null) + throw new TransactionUnavailableException( + "Transaction already assigned to request"); + if ( sipRequest.getMethod().equals(Request.ACK)) { + throw new TransactionUnavailableException ("Cannot create client transaction for " + Request.ACK); + } + // Be kind and assign a via header for this provider if the user is + // sloppy + if (sipRequest.getTopmostVia() == null) { + ListeningPointImpl lp = (ListeningPointImpl) this + .getListeningPoint("udp"); + Via via = lp.getViaHeader(); + request.setHeader(via); + } + // Give the request a quick check to see if all headers are assigned. + try { + sipRequest.checkHeaders(); + } catch (ParseException ex) { + throw new TransactionUnavailableException(ex.getMessage(), ex); + } + + /* + * User decided to give us his own via header branch. Lets see if it + * results in a clash. If so reject the request. + */ + if (sipRequest.getTopmostVia().getBranch() != null + && sipRequest.getTopmostVia().getBranch().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE) + && sipStack.findTransaction((SIPRequest) request, false) != null) { + throw new TransactionUnavailableException( + "Transaction already exists!"); + } + + + + + if (request.getMethod().equalsIgnoreCase(Request.CANCEL)) { + SIPClientTransaction ct = (SIPClientTransaction) sipStack + .findCancelTransaction((SIPRequest) request, false); + if (ct != null) { + ClientTransaction retval = sipStack.createClientTransaction( + (SIPRequest) request, ct.getMessageChannel()); + + ((SIPTransaction) retval).addEventListener(this); + sipStack.addTransaction((SIPClientTransaction) retval); + if (ct.getDialog() != null) { + ((SIPClientTransaction) retval).setDialog((SIPDialog) ct + .getDialog(), sipRequest.getDialogId(false)); + + } + return retval; + } + + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "could not find existing transaction for " + + ((SIPRequest) request).getFirstLine() + + " creating a new one "); + + // Could not find a dialog or the route is not set in dialog. + + Hop hop = null; + try { + hop = sipStack.getNextHop((SIPRequest) request); + if (hop == null) + throw new TransactionUnavailableException( + "Cannot resolve next hop -- transaction unavailable"); + } catch (SipException ex) { + throw new TransactionUnavailableException( + "Cannot resolve next hop -- transaction unavailable", ex); + } + String transport = hop.getTransport(); + ListeningPointImpl listeningPoint = (ListeningPointImpl) this + .getListeningPoint(transport); + + String dialogId = sipRequest.getDialogId(false); + SIPDialog dialog = sipStack.getDialog(dialogId); + if (dialog != null && dialog.getState() == DialogState.TERMINATED) { + + // throw new TransactionUnavailableException + // ("Found a terminated dialog -- possible re-use of old tag + // parameters"); + sipStack.removeDialog(dialog); + + } + + // An out of dialog route was found. Assign this to the + // client transaction. + + try { + // Set the brannch id before you ask for a tx. + // If the user has set his own branch Id and the + // branch id starts with a valid prefix, then take it. + // otherwise, generate one. If branch ID checking has + // been requested, set the branch ID. + String branchId = null; + if (sipRequest.getTopmostVia().getBranch() == null + || !sipRequest.getTopmostVia().getBranch().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE) + || sipStack.checkBranchId() ) { + branchId = Utils.getInstance().generateBranchId(); + + sipRequest.getTopmostVia().setBranch(branchId); + } + Via topmostVia = sipRequest.getTopmostVia(); + + //set port and transport if user hasn't already done this. + if(topmostVia.getTransport() == null) + topmostVia.setTransport(transport); + + if(topmostVia.getPort() == -1) + topmostVia.setPort(listeningPoint.getPort()); + branchId = sipRequest.getTopmostVia().getBranch(); + + SIPClientTransaction ct = (SIPClientTransaction) sipStack + .createMessageChannel(sipRequest, listeningPoint + .getMessageProcessor(), hop); + if (ct == null) + throw new TransactionUnavailableException("Cound not create tx"); + ct.setNextHop(hop); + ct.setOriginalRequest(sipRequest); + ct.setBranch(branchId); + // if the stack supports dialogs then + if (sipStack.isDialogCreated(request.getMethod())) { + // create a new dialog to contain this transaction + // provided this is necessary. + // This could be a re-invite + // in which case the dialog is re-used. + // (but noticed by Brad Templeton) + if (dialog != null) + ct.setDialog(dialog, sipRequest.getDialogId(false)); + else if (this.isAutomaticDialogSupportEnabled()) { + SIPDialog sipDialog = sipStack.createDialog(ct); + ct.setDialog(sipDialog, sipRequest.getDialogId(false)); + } + } else { + if (dialog != null) { + ct.setDialog(dialog, sipRequest.getDialogId(false)); + } + + } + + // The provider is the event listener for all transactions. + ct.addEventListener(this); + return (ClientTransaction) ct; + } catch (IOException ex) { + + throw new TransactionUnavailableException( + "Could not resolve next hop or listening point unavailable! ", + ex); + + } catch (java.text.ParseException ex) { + InternalErrorHandler.handleException(ex); + throw new TransactionUnavailableException( + "Unexpected Exception FIXME! ", ex); + } catch (InvalidArgumentException ex) { + InternalErrorHandler.handleException(ex); + throw new TransactionUnavailableException( + "Unexpected Exception FIXME! ", ex); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getNewServerTransaction(javax.sip.message.Request) + */ + public ServerTransaction getNewServerTransaction(Request request) + throws TransactionAlreadyExistsException, + TransactionUnavailableException { + + if (!sipStack.isAlive()) + throw new TransactionUnavailableException("Stack is stopped"); + SIPServerTransaction transaction = null; + SIPRequest sipRequest = (SIPRequest) request; + try { + sipRequest.checkHeaders(); + } catch (ParseException ex) { + throw new TransactionUnavailableException(ex.getMessage(), ex); + } + + if ( request.getMethod().equals(Request.ACK)) { + if ( sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("Creating server transaction for ACK -- makes no sense!"); + throw new TransactionUnavailableException("Cannot create Server transaction for ACK "); + } + /* + * Got a notify. + */ + if (sipRequest.getMethod().equals(Request.NOTIFY) + && sipRequest.getFromTag() != null + && sipRequest.getToTag() == null) { + + SIPClientTransaction ct = sipStack.findSubscribeTransaction( + sipRequest, (ListeningPointImpl) this.getListeningPoint()); + /* Issue 104 */ + if (ct == null && ! sipStack.deliverUnsolicitedNotify) { + throw new TransactionUnavailableException( + "Cannot find matching Subscription (and gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY not set)"); + } + } + if ( !sipStack.acquireSem()) { + throw new TransactionUnavailableException( + "Transaction not available -- could not acquire stack lock"); + } + try { + if (sipStack.isDialogCreated(sipRequest.getMethod())) { + if (sipStack.findTransaction((SIPRequest) request, true) != null) + throw new TransactionAlreadyExistsException( + "server transaction already exists!"); + + transaction = (SIPServerTransaction) ((SIPRequest) request) + .getTransaction(); + if (transaction == null) + throw new TransactionUnavailableException( + "Transaction not available"); + if (transaction.getOriginalRequest() == null) + transaction.setOriginalRequest(sipRequest); + try { + sipStack.addTransaction(transaction); + } catch (IOException ex) { + throw new TransactionUnavailableException( + "Error sending provisional response"); + } + // So I can handle timeouts. + transaction.addEventListener(this); + if (isAutomaticDialogSupportEnabled()) { + // If automatic dialog support is enabled then + // this tx gets his own dialog. + String dialogId = sipRequest.getDialogId(true); + SIPDialog dialog = sipStack.getDialog(dialogId); + if (dialog == null) { + dialog = sipStack.createDialog(transaction); + + } + transaction.setDialog(dialog, sipRequest.getDialogId(true)); + if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) { + sipStack.putInMergeTable(transaction, sipRequest); + } + dialog.addRoute(sipRequest); + if (dialog.getRemoteTag() != null + && dialog.getLocalTag() != null) { + this.sipStack.putDialog(dialog); + } + } + + } else { + if (isAutomaticDialogSupportEnabled()) { + /* + * Under automatic dialog support, dialog is tied into a transaction. You cannot + * create a server tx except for dialog creating transactions. After that, all + * subsequent transactions are created for you by the stack. + */ + transaction = (SIPServerTransaction) sipStack.findTransaction( + (SIPRequest) request, true); + if (transaction != null) + throw new TransactionAlreadyExistsException( + "Transaction exists! "); + transaction = (SIPServerTransaction) ((SIPRequest) request) + .getTransaction(); + if (transaction == null) + throw new TransactionUnavailableException( + "Transaction not available!"); + if (transaction.getOriginalRequest() == null) + transaction.setOriginalRequest(sipRequest); + // Map the transaction. + try { + sipStack.addTransaction(transaction); + } catch (IOException ex) { + throw new TransactionUnavailableException( + "Could not send back provisional response!"); + } + + // If there is a dialog already assigned then just update the + // dialog state. + String dialogId = sipRequest.getDialogId(true); + SIPDialog dialog = sipStack.getDialog(dialogId); + if (dialog != null) { + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, sipRequest.getDialogId(true)); + } + + } else { + transaction = (SIPServerTransaction) sipStack.findTransaction( + (SIPRequest) request, true); + if (transaction != null) + throw new TransactionAlreadyExistsException( + "Transaction exists! "); + transaction = (SIPServerTransaction) ((SIPRequest) request) + .getTransaction(); + if (transaction != null) { + if (transaction.getOriginalRequest() == null) + transaction.setOriginalRequest(sipRequest); + // Map the transaction. + sipStack.mapTransaction(transaction); + + // If there is a dialog already assigned then just + // assign the dialog to the transaction. + String dialogId = sipRequest.getDialogId(true); + SIPDialog dialog = sipStack.getDialog(dialogId); + if (dialog != null) { + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, sipRequest + .getDialogId(true)); + } + + return transaction; + } else { + // tx does not exist so create the tx. + + MessageChannel mc = (MessageChannel) sipRequest + .getMessageChannel(); + transaction = sipStack.createServerTransaction(mc); + if (transaction == null) + throw new TransactionUnavailableException( + "Transaction unavailable -- too many servrer transactions"); + + transaction.setOriginalRequest(sipRequest); + sipStack.mapTransaction(transaction); + + // If there is a dialog already assigned then just + // assign the dialog to the transaction. + String dialogId = sipRequest.getDialogId(true); + SIPDialog dialog = sipStack.getDialog(dialogId); + if (dialog != null) { + dialog.addTransaction(transaction); + dialog.addRoute(sipRequest); + transaction.setDialog(dialog, sipRequest + .getDialogId(true)); + } + + return transaction; + } + } + + } + return transaction; + } finally { + sipStack.releaseSem(); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getSipStack() + */ + public SipStack getSipStack() { + return (SipStack) this.sipStack; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#removeSipListener(javax.sip.SipListener) + */ + public void removeSipListener(SipListener sipListener) { + if (sipListener == this.getSipListener()) { + this.sipListener = null; + } + + boolean found = false; + + for (Iterator<SipProviderImpl> it = sipStack.getSipProviders(); it.hasNext();) { + SipProviderImpl nextProvider = (SipProviderImpl) it.next(); + if (nextProvider.getSipListener() != null) + found = true; + } + if (!found) { + sipStack.sipListener = null; + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#sendRequest(javax.sip.message.Request) + */ + public void sendRequest(Request request) throws SipException { + if (!sipStack.isAlive()) + throw new SipException("Stack is stopped."); + + // mranga: added check to ensure we are not sending empty (keepalive) + // message. + if (((SIPRequest) request).getRequestLine() != null + && request.getMethod().equals(Request.ACK)) { + Dialog dialog = sipStack.getDialog(((SIPRequest) request) + .getDialogId(false)); + if (dialog != null && dialog.getState() != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning( + "Dialog exists -- you may want to use Dialog.sendAck() " + + dialog.getState()); + } + } + Hop hop = sipStack.getRouter((SIPRequest) request).getNextHop(request); + if (hop == null) + throw new SipException("could not determine next hop!"); + SIPRequest sipRequest = (SIPRequest) request; + // Check if we have a valid via. + // Null request is used to send default proxy keepalive messages. + if ((!sipRequest.isNullRequest()) && sipRequest.getTopmostVia() == null) + throw new SipException("Invalid SipRequest -- no via header!"); + + try { + /* + * JvB: Via branch should already be OK, dont touch it here? Some + * apps forward statelessly, and then it's not set. So set only when + * not set already, dont overwrite CANCEL branch here.. + */ + if (!sipRequest.isNullRequest()) { + Via via = sipRequest.getTopmostVia(); + String branch = via.getBranch(); + if (branch == null || branch.length() == 0) { + via.setBranch(sipRequest.getTransactionId()); + } + } + MessageChannel messageChannel = null; + if (this.listeningPoints.containsKey(hop.getTransport() + .toUpperCase())) + messageChannel = sipStack.createRawMessageChannel( + this.getListeningPoint(hop.getTransport()).getIPAddress(), + this.getListeningPoint(hop.getTransport()).getPort(), hop); + if (messageChannel != null) { + messageChannel.sendMessage((SIPMessage) sipRequest,hop); + } else { + throw new SipException( + "Could not create a message channel for " + + hop.toString()); + } + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logException(ex); + } + + throw new SipException( + "IO Exception occured while Sending Request", ex); + + } catch (ParseException ex1) { + InternalErrorHandler.handleException(ex1); + } finally { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "done sending " + request.getMethod() + " to hop " + + hop); + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#sendResponse(javax.sip.message.Response) + */ + public void sendResponse(Response response) throws SipException { + if (!sipStack.isAlive()) + throw new SipException("Stack is stopped"); + SIPResponse sipResponse = (SIPResponse) response; + Via via = sipResponse.getTopmostVia(); + if (via == null) + throw new SipException("No via header in response!"); + SIPServerTransaction st = (SIPServerTransaction) sipStack.findTransaction((SIPMessage)response, true); + if ( st != null && st.getState() != TransactionState.TERMINATED && this.isAutomaticDialogSupportEnabled()) { + throw new SipException("Transaction exists -- cannot send response statelessly"); + } + String transport = via.getTransport(); + + // check to see if Via has "received paramaeter". If so + // set the host to the via parameter. Else set it to the + // Via host. + String host = via.getReceived(); + + if (host == null) + host = via.getHost(); + + // Symmetric nat support + int port = via.getRPort(); + if (port == -1) { + port = via.getPort(); + if (port == -1) { + if (transport.equalsIgnoreCase("TLS")) + port = 5061; + else + port = 5060; + } + } + + // for correct management of IPv6 addresses. + if (host.indexOf(":") > 0) + if (host.indexOf("[") < 0) + host = "[" + host + "]"; + + Hop hop = sipStack.getAddressResolver().resolveAddress( + new HopImpl(host, port, transport)); + + try { + ListeningPointImpl listeningPoint = (ListeningPointImpl) this + .getListeningPoint(transport); + if (listeningPoint == null) + throw new SipException( + "whoopsa daisy! no listening point found for transport " + + transport); + MessageChannel messageChannel = sipStack.createRawMessageChannel( + this.getListeningPoint(hop.getTransport()).getIPAddress(), + listeningPoint.port, hop); + messageChannel.sendMessage(sipResponse); + } catch (IOException ex) { + throw new SipException(ex.getMessage()); + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#setListeningPoint(javax.sip.ListeningPoint) + */ + public synchronized void setListeningPoint(ListeningPoint listeningPoint) { + if (listeningPoint == null) + throw new NullPointerException("Null listening point"); + ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; + lp.sipProvider = this; + String transport = lp.getTransport().toUpperCase(); + this.address = listeningPoint.getIPAddress(); + this.port = listeningPoint.getPort(); + // This is the first listening point. + this.listeningPoints.clear(); + this.listeningPoints.put(transport, listeningPoint); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getNewDialog(javax.sip.Transaction) + */ + + public Dialog getNewDialog(Transaction transaction) throws SipException { + if (transaction == null) + throw new NullPointerException("Null transaction!"); + + if (!sipStack.isAlive()) + throw new SipException("Stack is stopped."); + + if (isAutomaticDialogSupportEnabled()) + throw new SipException(" Error - AUTOMATIC_DIALOG_SUPPORT is on"); + + if (!sipStack.isDialogCreated(transaction.getRequest().getMethod())) + throw new SipException("Dialog cannot be created for this method " + + transaction.getRequest().getMethod()); + + SIPDialog dialog = null; + SIPTransaction sipTransaction = (SIPTransaction) transaction; + + if (transaction instanceof ServerTransaction) { + SIPServerTransaction st = (SIPServerTransaction) transaction; + Response response = st.getLastResponse(); + if (response != null) { + if (response.getStatusCode() != 100) + throw new SipException( + "Cannot set dialog after response has been sent"); + } + SIPRequest sipRequest = (SIPRequest) transaction.getRequest(); + String dialogId = sipRequest.getDialogId(true); + dialog = sipStack.getDialog(dialogId); + if (dialog == null) { + dialog = sipStack.createDialog((SIPTransaction) transaction); + // create and register the dialog and add the inital route set. + dialog.addTransaction(sipTransaction); + dialog.addRoute(sipRequest); + sipTransaction.setDialog(dialog, null); + + } else { + sipTransaction.setDialog(dialog, sipRequest.getDialogId(true)); + } + if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) { + sipStack.putInMergeTable(st, sipRequest); + } + } else { + + SIPClientTransaction sipClientTx = (SIPClientTransaction) transaction; + + SIPResponse response = sipClientTx.getLastResponse(); + + if (response == null) { + // A response has not yet been received, then set this up as the + // default dialog. + SIPRequest request = (SIPRequest) sipClientTx.getRequest(); + + String dialogId = request.getDialogId(false); + dialog = sipStack.getDialog(dialogId); + if (dialog != null) { + throw new SipException("Dialog already exists!"); + } else { + dialog = sipStack.createDialog(sipTransaction); + } + sipClientTx.setDialog(dialog, null); + + } else { + throw new SipException( + "Cannot call this method after response is received!"); + } + } + dialog.addEventListener(this); + return dialog; + + } + + /** + * Invoked when an error has ocurred with a transaction. Propagate up to the + * listeners. + * + * @param transactionErrorEvent + * Error event. + */ + public void transactionErrorEvent( + SIPTransactionErrorEvent transactionErrorEvent) { + SIPTransaction transaction = (SIPTransaction) transactionErrorEvent + .getSource(); + + if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) { + // There must be a way to inform the TU here!! + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "TransportError occured on " + transaction); + } + // Treat this like a timeout event. (Suggestion from Christophe). + Object errorObject = transactionErrorEvent.getSource(); + Timeout timeout = Timeout.TRANSACTION; + TimeoutEvent ev = null; + + if (errorObject instanceof SIPServerTransaction) { + ev = new TimeoutEvent(this, (ServerTransaction) errorObject, + timeout); + } else { + SIPClientTransaction clientTx = (SIPClientTransaction) errorObject; + Hop hop = clientTx.getNextHop(); + if ( sipStack.getRouter() instanceof RouterExt ) { + ((RouterExt) sipStack.getRouter()).transactionTimeout(hop); + } + ev = new TimeoutEvent(this, (ClientTransaction) errorObject, + timeout); + } + // Handling transport error like timeout + this.handleEvent(ev, (SIPTransaction) errorObject); + } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_ERROR) { + // This is a timeout event. + Object errorObject = transactionErrorEvent.getSource(); + Timeout timeout = Timeout.TRANSACTION; + TimeoutEvent ev = null; + + if (errorObject instanceof SIPServerTransaction) { + ev = new TimeoutEvent(this, (ServerTransaction) errorObject, + timeout); + } else { + SIPClientTransaction clientTx = (SIPClientTransaction) errorObject; + Hop hop = clientTx.getNextHop(); + if ( sipStack.getRouter() instanceof RouterExt ) { + ((RouterExt) sipStack.getRouter()).transactionTimeout(hop); + } + + ev = new TimeoutEvent(this, (ClientTransaction) errorObject, + timeout); + } + this.handleEvent(ev, (SIPTransaction) errorObject); + + } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) { + // This is a timeout retransmit event. + // We should never get this if retransmit filter is + // enabled (ie. in that case the stack should handle. + // all retransmits. + Object errorObject = transactionErrorEvent.getSource(); + Transaction tx = (Transaction) errorObject; + + if (tx.getDialog() != null) + InternalErrorHandler.handleException("Unexpected event !", + this.sipStack.getStackLogger()); + + Timeout timeout = Timeout.RETRANSMIT; + TimeoutEvent ev = null; + + if (errorObject instanceof SIPServerTransaction) { + ev = new TimeoutEvent(this, (ServerTransaction) errorObject, + timeout); + } else { + ev = new TimeoutEvent(this, (ClientTransaction) errorObject, + timeout); + } + this.handleEvent(ev, (SIPTransaction) errorObject); + } + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent) + */ + public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) { + SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource(); + Reason reason = Reason.AckNotReceived; + if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT) { + reason= Reason.AckNotSent; + } else if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT) { + reason = Reason.ReInviteTimeout; + } + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Dialog TimeoutError occured on " + sipDialog); + } + DialogTimeoutEvent ev = new DialogTimeoutEvent(this, sipDialog, reason); + // Handling transport error like timeout + this.handleEvent(ev, null); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#getListeningPoints() + */ + public synchronized ListeningPoint[] getListeningPoints() { + + ListeningPoint[] retval = new ListeningPointImpl[this.listeningPoints + .size()]; + this.listeningPoints.values().toArray(retval); + return retval; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#addListeningPoint(javax.sip.ListeningPoint) + */ + public synchronized void addListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException { + ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; + if (lp.sipProvider != null && lp.sipProvider != this) + throw new ObjectInUseException( + "Listening point assigned to another provider"); + String transport = lp.getTransport().toUpperCase(); + if (this.listeningPoints.isEmpty()) { + // first one -- record the IP address/port of the LP + + this.address = listeningPoint.getIPAddress(); + this.port = listeningPoint.getPort(); + } else { + if ((!this.address.equals(listeningPoint.getIPAddress())) + || this.port != listeningPoint.getPort()) + throw new ObjectInUseException( + "Provider already has different IP Address associated"); + + } + if (this.listeningPoints.containsKey(transport) + && this.listeningPoints.get(transport) != listeningPoint) + throw new ObjectInUseException( + "Listening point already assigned for transport!"); + + // This is for backwards compatibility. + lp.sipProvider = this; + + this.listeningPoints.put(transport, lp); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#removeListeningPoint(javax.sip.ListeningPoint) + */ + public synchronized void removeListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException { + ListeningPointImpl lp = (ListeningPointImpl) listeningPoint; + if (lp.messageProcessor.inUse()) + throw new ObjectInUseException("Object is in use"); + this.listeningPoints.remove(lp.getTransport().toUpperCase()); + + } + + /** + * Remove all the listening points for this sip provider. This is called + * when the stack removes the Provider + */ + public synchronized void removeListeningPoints() { + for (Iterator it = this.listeningPoints.values().iterator(); it + .hasNext();) { + ListeningPointImpl lp = (ListeningPointImpl) it.next(); + lp.messageProcessor.stop(); + it.remove(); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipProvider#setAutomaticDialogSupportEnabled(boolean) + */ + public void setAutomaticDialogSupportEnabled( + boolean automaticDialogSupportEnabled) { + this.automaticDialogSupportEnabled = automaticDialogSupportEnabled; + if ( this.automaticDialogSupportEnabled ) { + this.dialogErrorsAutomaticallyHandled = true; + } + } + + /** + * @return Returns the automaticDialogSupportEnabled. + */ + public boolean isAutomaticDialogSupportEnabled() { + return automaticDialogSupportEnabled; + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.SipProviderExt#setDialogErrorsAutomaticallyHandled() + */ + public void setDialogErrorsAutomaticallyHandled() { + this.dialogErrorsAutomaticallyHandled = true; + } + + public boolean isDialogErrorsAutomaticallyHandled() { + return this.dialogErrorsAutomaticallyHandled; + } + + + /** + * @return the sipListener + */ + public SipListener getSipListener() { + return sipListener; + } + + +} diff --git a/java/gov/nist/javax/sip/SipStackExt.java b/java/gov/nist/javax/sip/SipStackExt.java new file mode 100644 index 0000000..46842f3 --- /dev/null +++ b/java/gov/nist/javax/sip/SipStackExt.java @@ -0,0 +1,146 @@ +package gov.nist.javax.sip; + +import gov.nist.core.net.AddressResolver; +import gov.nist.javax.sip.clientauthutils.AccountManager; +import gov.nist.javax.sip.clientauthutils.AuthenticationHelper; +import gov.nist.javax.sip.clientauthutils.SecureAccountManager; +import gov.nist.javax.sip.header.extensions.JoinHeader; +import gov.nist.javax.sip.header.extensions.ReplacesHeader; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketAddress; +import java.util.Collection; + +import javax.sip.Dialog; +import javax.sip.SipStack; +import javax.sip.header.HeaderFactory; + +/** + * SIP Stack extensions to be added to the next spec revision. Only these may be safely used in + * the interim between now and the next release. SipStackImpl implements this interface. + * + * The following new stack initialization flags are defined (not the gov.nist prefix will be + * dropped when the spec is updated): + * + * <ul> + *<li>gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING + *<li>gov.nist.javax.sip.IS_BACK_TO_BACK_USER_AGENT + *<li>gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG + *<li>gov.nist.javax.sip.MAX_FORK_TIME_SECONDS + * </ul> + * @author M. Ranganathan + * + */ +public interface SipStackExt extends SipStack { + + /** + * Get the collection of dialogs currently in the Dialog table. This is useful for debugging + * purposes. + * + */ + public Collection<Dialog> getDialogs(); + + /** + * Get the ReferedTo dialog in the Replaces header. + * + * @return Dialog object matching the Replaces header, provided it is in an appropriate state + * to be replaced, <code>null</code> otherwise + * + * @since 2.0 + */ + public Dialog getReplacesDialog(ReplacesHeader replacesHeader); + + /** + * Get the authentication helper. + * + * + * @param accountManager -- account manager (for fetching credentials). + * @param headerFactory -- header factory. + * + * @return - the authentication helper which can be used for generating the appropriate + * headers for handling authentication challenges for user agents. + * + * @since 2.0 + */ + public AuthenticationHelper getAuthenticationHelper(AccountManager accountManager, + HeaderFactory headerFactory); + + /** + * Get the authentication helper. + * + * + * @param accountManager -- account manager (for fetching credentials). + * @param headerFactory -- header factory. + * + * @return - the authentication helper which can be used for generating the appropriate + * headers for handling authentication challenges for user agents. + * + * @since 2.0 + */ + public AuthenticationHelper getSecureAuthenticationHelper(SecureAccountManager accountManager, + HeaderFactory headerFactory); + + /** + * Set the address resolution interface. The address resolver allows you to register custom + * lookup schemes ( for example DNS SRV lookup ) that are not directly supported by the JDK. + * + * @param addressResolver -- the address resolver to set. + * + * @since 2.0 + */ + public void setAddressResolver(AddressResolver addressResolver); + + /** + * Get the dialog in the Join header. + * + * @return Dialog object matching the Join header, provided it is in an appropriate state to + * be replaced, <code>null</code> otherwise + * + * @since 2.0 + */ + public Dialog getJoinDialog(JoinHeader joinHeader); + + /** + * Set the list of cipher suites supported by the stack. A stack can have only one set of + * suites. These are not validated against the supported cipher suites of the java runtime, so + * specifying a cipher here does not guarantee that it will work.<br> + * The stack has a default cipher suite of: + * <ul> + * <li> TLS_RSA_WITH_AES_128_CBC_SHA </li> + * <li> SSL_RSA_WITH_3DES_EDE_CBC_SHA </li> + * <li> TLS_DH_anon_WITH_AES_128_CBC_SHA </li> + * <li> SSL_DH_anon_WITH_3DES_EDE_CBC_SHA </li> + * </ul> + * + * <b>NOTE: This function must be called before adding a TLS listener</b> + * + * @since 2.0 + * @param newCipherSuites -- The new set of ciphers to support. + * + */ + public void setEnabledCipherSuites(String[] newCipherSuites); + + /** + * Creates and binds, if necessary, a TCP socket connected to the specified + * destination address and port and then returns its local address. + * + * @param dst the destination address that the socket would need to connect + * to. + * @param dstPort the port number that the connection would be established + * with. + * @param localAddress the address that we would like to bind on + * (null for the "any" address). + * @param localPort the port that we'd like our socket to bind to (0 for a + * random port). + * + * @return the SocketAddress that this handler would use when connecting to + * the specified destination address and port. + * + * @throws IOException + */ + public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort, + InetAddress localAddress, int localPort) + throws IOException; + +} diff --git a/java/gov/nist/javax/sip/SipStackImpl.java b/java/gov/nist/javax/sip/SipStackImpl.java new file mode 100644 index 0000000..8b118db --- /dev/null +++ b/java/gov/nist/javax/sip/SipStackImpl.java @@ -0,0 +1,1496 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip; + +import gov.nist.core.ServerLogger; +import gov.nist.core.StackLogger; +import gov.nist.core.net.AddressResolver; +import gov.nist.core.net.NetworkLayer; +import gov.nist.core.net.SslNetworkLayer; +import gov.nist.javax.sip.clientauthutils.AccountManager; +import gov.nist.javax.sip.clientauthutils.AuthenticationHelper; +import gov.nist.javax.sip.clientauthutils.AuthenticationHelperImpl; +import gov.nist.javax.sip.clientauthutils.SecureAccountManager; +import gov.nist.javax.sip.parser.StringMsgParser; +import gov.nist.javax.sip.stack.DefaultMessageLogFactory; +import gov.nist.javax.sip.stack.DefaultRouter; +import gov.nist.javax.sip.stack.MessageProcessor; +import gov.nist.javax.sip.stack.SIPTransactionStack; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.InetAddress; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.sip.InvalidArgumentException; +import javax.sip.ListeningPoint; +import javax.sip.ObjectInUseException; +import javax.sip.PeerUnavailableException; +import javax.sip.ProviderDoesNotExistException; +import javax.sip.SipException; +import javax.sip.SipListener; +import javax.sip.SipProvider; +import javax.sip.SipStack; +import javax.sip.TransportNotSupportedException; +import javax.sip.address.Router; +import javax.sip.header.HeaderFactory; +import javax.sip.message.Request; + +/** + * Implementation of SipStack. + * + * The JAIN-SIP stack is initialized by a set of properties (see the JAIN SIP + * documentation for an explanation of these properties + * {@link javax.sip.SipStack} ). In addition to these, the following are + * meaningful properties for the NIST SIP stack (specify these in the property + * array when you create the JAIN-SIP statck): + * <ul> + * + * <li><b>gov.nist.javax.sip.TRACE_LEVEL = integer </b><br/> + * <b> Use of this property is still supported but deprecated. Please use + * gov.nist.javax.sip.STACK_LOGGER and gov.nist.javax.sip.SERVER_LOGGER for + * integration with logging frameworks and for custom formatting of log records. + * </b> This property is used by the built in log4j based logger. You can use + * the standard log4j level names here (i.e. ERROR, INFO, WARNING, OFF, DEBUG, + * TRACE) If this is set to INFO or above, then incoming valid messages are + * logged in SERVER_LOG. If you set this to 32 and specify a DEBUG_LOG then vast + * amounts of trace information will be dumped in to the specified DEBUG_LOG. + * The server log accumulates the signaling trace. <a href="{@docRoot} + * /tools/tracesviewer/tracesviewer.html"> This can be viewed using the trace + * viewer tool .</a> Please send us both the server log and debug log when + * reporting non-obvious problems. You can also use the strings DEBUG or INFO + * for level 32 and 16 respectively. If the value of this property is set to + * LOG4J, then the effective log levels are determined from the log4j settings + * file (e.g. log4j.properties). The logger name for the stack is specified + * using the gov.nist.javax.sip.LOG4J_LOGGER_NAME property. By default log4j + * logger name for the stack is the same as the stack name. For example, <code> + * properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "LOG4J"); + * properties.setProperty("gov.nist.javax.sip.LOG4J_LOGGER_NAME", "SIPStackLogger"); + * </code> allows you to now control logging in the stack entirely using log4j + * facilities.</li> + * + * <li><b>gov.nist.javax.sip.LOG_FACTORY = classpath </b> <b> Use of this + * property is still supported but deprecated. Please use + * gov.nist.javax.sip.STACK_LOGGER and gov.nist.javax.sip.SERVER_LOGGER for + * integration with logging frameworks and for custom formatting of log records. + * </b> <br/> + * The fully qualified classpath for an implementation of the MessageLogFactory. + * The stack calls the MessageLogFactory functions to format the log for + * messages that are received or sent. This function allows you to log auxiliary + * information related to the application or environmental conditions into the + * log stream. The log factory must have a default constructor.</li> + * + * <li><b>gov.nist.javax.sip.SERVER_LOG = fileName </b><br/> + * <b> Use of this property is still supported but deprecated. Please use + * gov.nist.javax.sip.STACK_LOGGER and gov.nist.javax.sip.SERVER_LOGGER for + * integration with logging frameworks and for custom formatting of log records. + * </b> Log valid incoming messages here. If this is left null AND the + * TRACE_LEVEL is above INFO (or TRACE) then the messages are printed to stdout. + * Otherwise messages are logged in a format that can later be viewed using the + * trace viewer application which is located in the tools/tracesviewer + * directory. <font color=red> Mail this to us with bug reports. </font></li> + * + * <li><b>gov.nist.javax.sip.DEBUG_LOG = fileName </b> <b> Use of this property + * is still supported but deprecated. Please use gov.nist.javax.sip.STACK_LOGGER + * and gov.nist.javax.sip.SERVER_LOGGER for integration with logging frameworks + * and for custom formatting of log records. </b> <br/> + * Where the debug log goes. <font color=red> Mail this to us with bug reports. + * </font></li> + * + * <li><b>gov.nist.javax.sip.LOG_MESSAGE_CONTENT = true|false </b><br/> + * Set true if you want to capture content into the log. Default is false. A bad + * idea to log content if you are using SIP to push a lot of bytes through TCP.</li> + * + * <li><b>gov.nist.javax.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND = true|false </b><br/> + * Set true if you want to to log a stack trace at INFO level for each message + * send. This is really handy for debugging.</li> + * + * <li><b>gov.nist.javax.sip.STACK_LOGGER = full path name to the class + * implementing gov.nist.core.StackLogger interface</b><br/> + * If this property is defined the sip stack will try to instantiate it through + * a no arg constructor. This allows to use different logging implementations + * than the ones provided by default to log what happens within the stack while + * processing SIP messages. If this property is not defined, the default sip + * stack LogWriter will be used for logging</li> + * + * <li><b>gov.nist.javax.sip.SERVER_LOGGER = full path name to the class + * implementing gov.nist.core.ServerLogger interface</b><br/> + * If this property is defined the sip stack will try to instantiate it through + * a no arg constructor. This allows to use different logging implementations + * than the ones provided by default to log sent/received messages by the sip + * stack. If this property is not defined, the default sip stack ServerLog will + * be used for logging</li> + * + * <li><b>gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING = [true|false] </b> + * <br/> + * Default is <it>true</it>. This is also settable on a per-provider basis. This + * flag is set to true by default. When set + * to <it>false</it> the following behaviors are enabled: + * + * + * <li>Turn off Merged requests Loop Detection: The following behavior is turned off + * : If the request has no tag in the To header field, the UAS core MUST check + * the request against ongoing transactions. If the From tag, Call-ID, and CSeq + * exactly match those associated with an ongoing transaction, but the request + * does not match that transaction (based on the matching rules in Section + * 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and pass + * it to the server transaction. + * + * </ul> + * + * <li><b>gov.nist.javax.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/> + * Default is <it>false</it> This property controls a setting on the Dialog + * objects that the stack manages. Pure B2BUA applications should set this flag + * to <it>true</it>. This property can also be set on a per-dialog basis. + * Setting this to <it>true</it> imposes serialization on re-INVITE and makes + * the sending of re-INVITEs asynchronous. The sending of re-INVITE is + * controlled as follows : If the previous in-DIALOG request was an invite + * ClientTransaction then the next re-INVITEs that uses the dialog will wait + * till an ACK has been sent before admitting the new re-INVITE. If the previous + * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for + * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within + * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li> + * <li><b>gov.nist.javax.sip.MAX_MESSAGE_SIZE = integer</b> <br/> + * Maximum size of content that a TCP connection can read. Must be at least 4K. + * Default is "infinity" -- ie. no limit. This is to prevent DOS attacks + * launched by writing to a TCP connection until the server chokes.</li> + * + * <li><b>gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG = [true|false] </b><br/> + * If set to false (the default), the application does NOT get notified when a Dialog in the + * NULL state is terminated. ( Dialogs in the NULL state are not associated with an actual SIP Dialog. + * They are a programming convenience. A Dialog is in the NULL state before the first response for the + * Dialog forming Transaction). If set to true, the SipListener will get a DialogTerminatedEvent + * when a Dialog in the NULL state is terminated. + * </li> + * + * <li><b>gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS = [true|false] </b> <br/> + * Default value is true. Setting this to false makes the Stack close the server + * socket after a Server Transaction goes to the TERMINATED state. This allows a + * server to protectect against TCP based Denial of Service attacks launched by + * clients (ie. initiate hundreds of client transactions). If true (default + * action), the stack will keep the socket open so as to maximize performance at + * the expense of Thread and memory resources - leaving itself open to DOS + * attacks.</li> + * + * + * <li><b>gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS = [true|false] </b> <br/> + * Default value is true. Setting this to false makes the Stack close the server + * socket after a Client Transaction goes to the TERMINATED state. This allows a + * client release any buffers threads and socket connections associated with a + * client transaction after the transaction has terminated at the expense of + * performance.</li> + * + * <li><b>gov.nist.javax.sip.THREAD_POOL_SIZE = integer </b> <br/> + * Concurrency control for number of simultaneous active threads. If + * unspecificed, the default is "infinity". This feature is useful if you are + * trying to build a container. + * <ul> + * <li> + * <li>If this is not specified, <b> and the listener is re-entrant</b>, each + * event delivered to the listener is run in the context of a new thread.</li> + * <li>If this is specified and the listener is re-entrant, then the stack will + * run the listener using a thread from the thread pool. This allows you to + * manage the level of concurrency to a fixed maximum. Threads are pre-allocated + * when the stack is instantiated.</li> + * <li>If this is specified and the listener is not re-entrant, then the stack + * will use the thread pool thread from this pool to parse and manage the state + * machine but will run the listener in its own thread.</li> + * </ul> + * + * <li><b>gov.nist.javax.sip.REENTRANT_LISTENER = true|false </b> <br/> + * Default is false. Set to true if the listener is re-entrant. If the listener + * is re-entrant then the stack manages a thread pool and synchronously calls + * the listener from the same thread which read the message. Multiple + * transactions may concurrently receive messages and this will result in + * multiple threads being active in the listener at the same time. The listener + * has to be written with this in mind. <b> If you want good performance on a + * multithreaded machine write your listener to be re-entrant and set this + * property to be true </b></li> + * + * <li><b>gov.nist.javax.sip.MAX_CONNECTIONS = integer </b> <br/> + * Max number of simultaneous TCP connections handled by stack.</li> + * + * <li><b>gov.nist.javax.sip.MAX_SERVER_TRANSACTIONS = integer </b> <br/> + * Maximum size of server transaction table. The low water mark is 80% of the + * high water mark. Requests are selectively dropped in the lowater mark to + * highwater mark range. Requests are unconditionally accepted if the table is + * smaller than the low water mark. The default highwater mark is 5000</li> + * + * <li><b>gov.nist.javax.sip.MAX_CLIENT_TRANSACTIONS = integer </b> <br/> + * Max number of active client transactions before the caller blocks and waits + * for the number to drop below a threshold. Default is unlimited, i.e. the + * caller never blocks and waits for a client transaction to become available + * (i.e. it does its own resource management in the application).</li> + * + * <li><b>gov.nist.javax.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER = true|false + * </b> <br/> + * If true then the listener will see the ACK for non-2xx responses for server + * transactions. This is not standard behavior per RFC 3261 (INVITE server + * transaction state machine) but this is a useful flag for testing. The TCK + * uses this flag for example.</li> + * + * <li><b>gov.nist.javax.sip.MAX_LISTENER_RESPONSE_TIME = Integer </b> <br/> + * Max time (seconds) before sending a response to a server transaction. If a + * response is not sent within this time period, the transaction will be deleted + * by the stack. Default time is "infinity" - i.e. if the listener never + * responds, the stack will hang on to a reference for the transaction and + * result in a memory leak. + * + * <li><b>gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_ACK = [true|false]</b> + * <br/> + * Default is <it>false</it>. ACK Server Transaction is a Pseuedo-transaction. + * If you want termination notification on ACK transactions (so all server + * transactions can be handled uniformly in user code during cleanup), then set + * this flag to <it>true</it>.</li> + * + * <li><b>gov.nist.javax.sip.READ_TIMEOUT = integer </b> <br/> + * This is relevant for incoming TCP connections to prevent starvation at the + * server. This defines the timeout in miliseconds between successive reads + * after the first byte of a SIP message is read by the stack. All the sip + * headers must be delivered in this interval and each successive buffer must be + * of the content delivered in this interval. Default value is -1 (ie. the stack + * is wide open to starvation attacks) and the client can be as slow as it wants + * to be.</li> + * + * <li><b>gov.nist.javax.sip.NETWORK_LAYER = classpath </b> <br/> + * This is an EXPERIMENTAL property (still under active devlopment). Defines a + * network layer that allows a client to have control over socket allocations + * and monitoring of socket activity. A network layer should implement + * gov.nist.core.net.NetworkLayer. The default implementation simply acts as a + * wrapper for the standard java.net socket layer. This functionality is still + * under active development (may be extended to support security and other + * features).</li> + * + * <li><b>gov.nist.javax.sip.ADDRESS_RESOLVER = classpath </b><br/> + * The fully qualified class path for an implementation of the AddressResolver + * interface. The AddressResolver allows you to support lookup schemes for + * addresses that are not directly resolvable to IP adresses using + * getHostByName. Specifying your own address resolver allows you to customize + * address lookup. The default address resolver is a pass-through address + * resolver (i.e. just returns the input string without doing a resolution). See + * gov.nist.javax.sip.DefaultAddressResolver.</li> + * + * <li><b>gov.nist.javax.sip.AUTO_GENERATE_TIMESTAMP= [true| false] </b><br/> + * (default is false) Automatically generate a getTimeOfDay timestamp for a + * retransmitted request if the original request contained a timestamp. This is + * useful for profiling.</li> + * + * <li><b>gov.nist.javax.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS = long </b> <br/> + * Defines how often the application intends to audit the SIP Stack about the + * health of its internal threads (the property specifies the time in + * miliseconds between successive audits). The audit allows the application to + * detect catastrophic failures like an internal thread terminating because of + * an exception or getting stuck in a deadlock condition. Events like these will + * make the stack inoperable and therefore require immediate action from the + * application layer (e.g., alarms, traps, reboot, failover, etc.) Thread audits + * are disabled by default. If this property is not specified, audits will + * remain disabled. An example of how to use this property is in + * src/examples/threadaudit.</li> + * + * + * + * <li><b>gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY = + * [true|false] </b> <br/> + * Default is <it>false</it> If set to <it>true</it>, when you are creating a + * message from a <it>String</it>, the MessageFactory will compute the content + * length from the message content and ignore the provided content length + * parameter in the Message. Otherwise, it will use the content length supplied + * and generate a parse exception if the content is truncated. + * + * <li><b>gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED = [true|false] + * </b> <br/> + * Default is <it>true</it>. This flag is added in support of load balancers or + * failover managers where you may want to cancel ongoing transactions from a + * different stack than the original stack. If set to <it>false</it> then the + * CANCEL client transaction is not checked for the existence of the INVITE or + * the state of INVITE when you send the CANCEL request. Hence you can CANCEL an + * INVITE from a different stack than the INVITE. You can also create a CANCEL + * client transaction late and send it out after the INVITE server transaction + * has been Terminated. Clearly this will result in protocol errors. Setting the + * flag to true ( default ) enables you to avoid common protocol errors.</li> + * + * <li><b>gov.nist.javax.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/> + * Default is <it>false</it> This property controls a setting on the Dialog + * objects that the stack manages. Pure B2BUA applications should set this flag + * to <it>true</it>. This property can also be set on a per-dialog basis. + * Setting this to <it>true</it> imposes serialization on re-INVITE and makes + * the sending of re-INVITEs asynchronous. The sending of re-INVITE is + * controlled as follows : If the previous in-DIALOG request was an invite + * ClientTransaction then the next re-INVITEs that uses the dialog will wait + * till an ACK has been sent before admitting the new re-INVITE. If the previous + * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for + * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within + * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li> + * + * + * <li><b>gov.nist.javax.sip.RECEIVE_UDP_BUFFER_SIZE = int </b> <br/> + * Default is <it>8*1024</it>. This property control the size of the UDP buffer + * used for SIP messages. Under load, if the buffer capacity is overflown the + * messages are dropped causing retransmissions, further increasing the load and + * causing even more retransmissions. Good values to this property for servers + * is a big number in the order of 8*8*1024.</li> + * + * <li><b>gov.nist.javax.sip.SEND_UDP_BUFFER_SIZE = int </b> <br/> + * Default is <it>8*1024</it>. This property control the size of the UDP buffer + * used for SIP messages. Under load, if the buffer capacity is overflown the + * messages are dropped causing retransmissions, further increasing the load and + * causing even more retransmissions. Good values to this property for servers + * is a big number in the order of 8*8*1024 or higher.</li> + * + * <li><b>gov.nist.javax.sip.CONGESTION_CONTROL_ENABLED = boolean </b> Defailt + * is true. If set to true stack will enforce queue length limitation for UDP. + * The Max queue size is 5000 messages. The minimum queue size is 2500 messages. + * </li> + * + * <li><b>gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY = [true|false] </b> <br/> + * Default is <it>false</it>. This flag is added to allow Sip Listeners to + * receive all NOTIFY requests including those that are not part of a valid + * dialog.</li> + * + * <li><b>gov.nist.javax.sip.REJECT_STRAY_RESPONSES = [true|false] </b> Default + * is <it>false</it> A flag that checks responses to test whether the response + * corresponds to a via header that was previously generated by us. Note that + * setting this flag implies that the stack will take control over setting the + * VIA header for Sip Requests sent through the stack. The stack will attach a + * suffix to the VIA header branch and check any response arriving at the stack + * to see if that response suffix is present. If it is not present, then the + * stack will silently drop the response.</li> + * + * <li><b>gov.nist.javax.sip.MAX_FORK_TIME_SECONDS = integer </b> Maximum time for which the original + * transaction for which a forked response is received is tracked. This property + * is only relevant to Dialog Stateful applications ( User Agents or B2BUA). + * When a forked response is received in this time interval from when the original + * INVITE client transaction was sent, the stack will place the original INVITE + * client transction in the ResponseEventExt and deliver that to the application. + * The event handler can get the original transaction from this event. </li> + * + * * <li><b>gov.nist.javax.sip.TLS_CLIENT_PROTOCOLS = String </b> + * Comma-separated list of protocols to use when creating outgoing TLS connections. + * The default is "SSLv3, SSLv2Hello, TLSv1". + * Some servers do not support SSLv2Hello, so override to "SSLv3, TLSv1". + * </li> + + * <li><b>javax.net.ssl.keyStore = fileName </b> <br/> + * Default is <it>NULL</it>. If left undefined the keyStore and trustStore will + * be left to the java runtime defaults. If defined, any TLS sockets created + * (client and server) will use the key store provided in the fileName. The + * trust store will default to the same store file. A password must be provided + * to access the keyStore using the following property: <br> + * <code> + * properties.setProperty("javax.net.ssl.keyStorePassword", "<password>"); + * </code> <br> + * The trust store can be changed, to a separate file with the following + * setting: <br> + * <code> + * properties.setProperty("javax.net.ssl.trustStore", "<trustStoreFileName location>"); + * </code> <br> + * If the trust store property is provided the password on the trust store must + * be the same as the key store. <br> + * <br> + * <b> Note that the stack supports the extensions that are defined in + * SipStackExt. These will be supported in the next release of JAIN-SIP. You + * should only use the extensions that are defined in this class. </b> + * + * + * @version 1.2 $Revision: 1.115 $ $Date: 2010/01/10 00:13:14 $ + * + * @author M. Ranganathan <br/> + * + * + * + * + */ +public class SipStackImpl extends SIPTransactionStack implements + javax.sip.SipStack, SipStackExt { + + private EventScanner eventScanner; + + private Hashtable<String, ListeningPointImpl> listeningPoints; + + private LinkedList<SipProviderImpl> sipProviders; + + /** + * Max datagram size. + */ + public static final Integer MAX_DATAGRAM_SIZE = 8 * 1024; + + // Flag to indicate that the listener is re-entrant and hence + // Use this flag with caution. + boolean reEntrantListener; + + SipListener sipListener; + + // If set to true then a transaction terminated event is + // delivered for ACK transactions. + boolean deliverTerminatedEventForAck = false; + + // If set to true then the application want to receive + // unsolicited NOTIFYs, ie NOTIFYs that don't match any dialog + boolean deliverUnsolicitedNotify = false; + + // Stack semaphore (global lock). + private Semaphore stackSemaphore = new Semaphore(1); + + // RFC3261: TLS_RSA_WITH_AES_128_CBC_SHA MUST be supported + // RFC3261: TLS_RSA_WITH_3DES_EDE_CBC_SHA SHOULD be supported for backwards + // compat + private String[] cipherSuites = { + "TLS_RSA_WITH_AES_128_CBC_SHA", // AES difficult to get with + // c++/Windows + // "TLS_RSA_WITH_3DES_EDE_CBC_SHA", // Unsupported by Sun impl, + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", // For backwards comp., C++ + + // JvB: patch from Sebastien Mazy, issue with mismatching + // ciphersuites + "TLS_DH_anon_WITH_AES_128_CBC_SHA", + "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", }; + + // Supported protocols for TLS client: can be overridden by application + private String[] enabledProtocols = { + "SSLv3", + "SSLv2Hello", + "TLSv1" + }; + + /** + * Creates a new instance of SipStackImpl. + */ + + protected SipStackImpl() { + super(); + NistSipMessageFactoryImpl msgFactory = new NistSipMessageFactoryImpl( + this); + super.setMessageFactory(msgFactory); + this.eventScanner = new EventScanner(this); + this.listeningPoints = new Hashtable<String, ListeningPointImpl>(); + this.sipProviders = new LinkedList<SipProviderImpl>(); + + } + + /** + * ReInitialize the stack instance. + */ + private void reInitialize() { + super.reInit(); + this.eventScanner = new EventScanner(this); + this.listeningPoints = new Hashtable<String, ListeningPointImpl>(); + this.sipProviders = new LinkedList<SipProviderImpl>(); + this.sipListener = null; + + } + + /** + * Return true if automatic dialog support is enabled for this stack. + * + * @return boolean, true if automatic dialog support is enabled for this + * stack + */ + boolean isAutomaticDialogSupportEnabled() { + return super.isAutomaticDialogSupportEnabled; + } + + /** + * Constructor for the stack. + * + * @param configurationProperties + * -- stack configuration properties including NIST-specific + * extensions. + * @throws PeerUnavailableException + */ + public SipStackImpl(Properties configurationProperties) + throws PeerUnavailableException { + this(); + String address = configurationProperties + .getProperty("javax.sip.IP_ADDRESS"); + try { + /** Retrieve the stack IP address */ + if (address != null) { + // In version 1.2 of the spec the IP address is + // associated with the listening point and + // is not madatory. + super.setHostAddress(address); + + } + } catch (java.net.UnknownHostException ex) { + throw new PeerUnavailableException("bad address " + address); + } + + /** Retrieve the stack name */ + String name = configurationProperties + .getProperty("javax.sip.STACK_NAME"); + if (name == null) + throw new PeerUnavailableException("stack name is missing"); + super.setStackName(name); + String stackLoggerClassName = configurationProperties + .getProperty("gov.nist.javax.sip.STACK_LOGGER"); + // To log debug messages. + if (stackLoggerClassName == null) + stackLoggerClassName = "gov.nist.core.LogWriter"; + try { + Class<?> stackLoggerClass = Class.forName(stackLoggerClassName); + Class<?>[] constructorArgs = new Class[0]; + Constructor<?> cons = stackLoggerClass + .getConstructor(constructorArgs); + Object[] args = new Object[0]; + StackLogger stackLogger = (StackLogger) cons.newInstance(args); + stackLogger.setStackProperties(configurationProperties); + super.setStackLogger(stackLogger); + } catch (InvocationTargetException ex1) { + throw new IllegalArgumentException( + "Cound not instantiate stack logger " + + stackLoggerClassName + + "- check that it is present on the classpath and that there is a no-args constructor defined", + ex1); + } catch (Exception ex) { + throw new IllegalArgumentException( + "Cound not instantiate stack logger " + + stackLoggerClassName + + "- check that it is present on the classpath and that there is a no-args constructor defined", + ex); + } + + String serverLoggerClassName = configurationProperties + .getProperty("gov.nist.javax.sip.SERVER_LOGGER"); + // To log debug messages. + if (serverLoggerClassName == null) + serverLoggerClassName = "gov.nist.javax.sip.stack.ServerLog"; + try { + Class<?> serverLoggerClass = Class + .forName(serverLoggerClassName); + Class<?>[] constructorArgs = new Class[0]; + Constructor<?> cons = serverLoggerClass + .getConstructor(constructorArgs); + Object[] args = new Object[0]; + this.serverLogger = (ServerLogger) cons.newInstance(args); + serverLogger.setSipStack(this); + serverLogger.setStackProperties(configurationProperties); + } catch (InvocationTargetException ex1) { + throw new IllegalArgumentException( + "Cound not instantiate server logger " + + stackLoggerClassName + + "- check that it is present on the classpath and that there is a no-args constructor defined", + ex1); + } catch (Exception ex) { + throw new IllegalArgumentException( + "Cound not instantiate server logger " + + stackLoggerClassName + + "- check that it is present on the classpath and that there is a no-args constructor defined", + ex); + } + + // Default router -- use this for routing SIP URIs. + // Our router does not do DNS lookups. + this.outboundProxy = configurationProperties + .getProperty("javax.sip.OUTBOUND_PROXY"); + + this.defaultRouter = new DefaultRouter(this, outboundProxy); + + /** Retrieve the router path */ + String routerPath = configurationProperties + .getProperty("javax.sip.ROUTER_PATH"); + if (routerPath == null) + routerPath = "gov.nist.javax.sip.stack.DefaultRouter"; + + try { + Class<?> routerClass = Class.forName(routerPath); + Class<?>[] constructorArgs = new Class[2]; + constructorArgs[0] = javax.sip.SipStack.class; + constructorArgs[1] = String.class; + Constructor<?> cons = routerClass.getConstructor(constructorArgs); + Object[] args = new Object[2]; + args[0] = (SipStack) this; + args[1] = outboundProxy; + Router router = (Router) cons.newInstance(args); + super.setRouter(router); + } catch (InvocationTargetException ex1) { + getStackLogger() + .logError( + "could not instantiate router -- invocation target problem", + (Exception) ex1.getCause()); + throw new PeerUnavailableException( + "Cound not instantiate router - check constructor", ex1); + } catch (Exception ex) { + getStackLogger().logError("could not instantiate router", + (Exception) ex.getCause()); + throw new PeerUnavailableException("Could not instantiate router", + ex); + } + + // The flag that indicates that the default router is to be ignored. + String useRouterForAll = configurationProperties + .getProperty("javax.sip.USE_ROUTER_FOR_ALL_URIS"); + this.useRouterForAll = true; + if (useRouterForAll != null) { + this.useRouterForAll = "true".equalsIgnoreCase(useRouterForAll); + } + + /* + * Retrieve the EXTENSION Methods. These are used for instantiation of + * Dialogs. + */ + String extensionMethods = configurationProperties + .getProperty("javax.sip.EXTENSION_METHODS"); + + if (extensionMethods != null) { + java.util.StringTokenizer st = new java.util.StringTokenizer( + extensionMethods); + while (st.hasMoreTokens()) { + String em = st.nextToken(":"); + if (em.equalsIgnoreCase(Request.BYE) + || em.equalsIgnoreCase(Request.INVITE) + || em.equalsIgnoreCase(Request.SUBSCRIBE) + || em.equalsIgnoreCase(Request.NOTIFY) + || em.equalsIgnoreCase(Request.ACK) + || em.equalsIgnoreCase(Request.OPTIONS)) + throw new PeerUnavailableException("Bad extension method " + + em); + else + this.addExtensionMethod(em); + } + } + String keyStoreFile = configurationProperties + .getProperty("javax.net.ssl.keyStore"); + String trustStoreFile = configurationProperties + .getProperty("javax.net.ssl.trustStore"); + if (keyStoreFile != null) { + if (trustStoreFile == null) { + trustStoreFile = keyStoreFile; + } + String keyStorePassword = configurationProperties + .getProperty("javax.net.ssl.keyStorePassword"); + try { + this.networkLayer = new SslNetworkLayer(trustStoreFile, + keyStoreFile, keyStorePassword.toCharArray(), + configurationProperties + .getProperty("javax.net.ssl.keyStoreType")); + } catch (Exception e1) { + getStackLogger().logError( + "could not instantiate SSL networking", e1); + } + } + + // Set the auto dialog support flag. + super.isAutomaticDialogSupportEnabled = configurationProperties + .getProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "on") + .equalsIgnoreCase("on"); + + super.isAutomaticDialogErrorHandlingEnabled = configurationProperties + .getProperty("gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING","true") + .equals(Boolean.TRUE.toString()); + if ( super.isAutomaticDialogSupportEnabled ) { + super.isAutomaticDialogErrorHandlingEnabled = true; + } + + if (configurationProperties + .getProperty("gov.nist.javax.sip.MAX_LISTENER_RESPONSE_TIME") != null) { + super.maxListenerResponseTime = Integer + .parseInt(configurationProperties + .getProperty("gov.nist.javax.sip.MAX_LISTENER_RESPONSE_TIME")); + if (super.maxListenerResponseTime <= 0) + throw new PeerUnavailableException( + "Bad configuration parameter gov.nist.javax.sip.MAX_LISTENER_RESPONSE_TIME : should be positive"); + } else { + super.maxListenerResponseTime = -1; + } + + + + this.deliverTerminatedEventForAck = configurationProperties + .getProperty( + "gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_ACK", + "false").equalsIgnoreCase("true"); + + this.deliverUnsolicitedNotify = configurationProperties.getProperty( + "gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "false") + .equalsIgnoreCase("true"); + + String forkedSubscriptions = configurationProperties + .getProperty("javax.sip.FORKABLE_EVENTS"); + if (forkedSubscriptions != null) { + StringTokenizer st = new StringTokenizer(forkedSubscriptions); + while (st.hasMoreTokens()) { + String nextEvent = st.nextToken(); + this.forkedEvents.add(nextEvent); + } + } + + // The following features are unique to the NIST implementation. + + /* + * gets the NetworkLayer implementation, if any. Note that this is a + * NIST only feature. + */ + + final String NETWORK_LAYER_KEY = "gov.nist.javax.sip.NETWORK_LAYER"; + + if (configurationProperties.containsKey(NETWORK_LAYER_KEY)) { + String path = configurationProperties + .getProperty(NETWORK_LAYER_KEY); + try { + Class<?> clazz = Class.forName(path); + Constructor<?> c = clazz.getConstructor(new Class[0]); + networkLayer = (NetworkLayer) c.newInstance(new Object[0]); + } catch (Exception e) { + throw new PeerUnavailableException( + "can't find or instantiate NetworkLayer implementation: " + + path); + } + } + + final String ADDRESS_RESOLVER_KEY = "gov.nist.javax.sip.ADDRESS_RESOLVER"; + + if (configurationProperties.containsKey(ADDRESS_RESOLVER_KEY)) { + String path = configurationProperties + .getProperty(ADDRESS_RESOLVER_KEY); + try { + Class<?> clazz = Class.forName(path); + Constructor<?> c = clazz.getConstructor(new Class[0]); + this.addressResolver = (AddressResolver) c + .newInstance(new Object[0]); + } catch (Exception e) { + throw new PeerUnavailableException( + "can't find or instantiate AddressResolver implementation: " + + path); + } + } + + String maxConnections = configurationProperties + .getProperty("gov.nist.javax.sip.MAX_CONNECTIONS"); + if (maxConnections != null) { + try { + this.maxConnections = new Integer(maxConnections).intValue(); + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + getStackLogger().logError( + "max connections - bad value " + ex.getMessage()); + } + } + + String threadPoolSize = configurationProperties + .getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE"); + if (threadPoolSize != null) { + try { + this.threadPoolSize = new Integer(threadPoolSize).intValue(); + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + this.getStackLogger().logError( + "thread pool size - bad value " + ex.getMessage()); + } + } + + String serverTransactionTableSize = configurationProperties + .getProperty("gov.nist.javax.sip.MAX_SERVER_TRANSACTIONS"); + if (serverTransactionTableSize != null) { + try { + this.serverTransactionTableHighwaterMark = new Integer( + serverTransactionTableSize).intValue(); + this.serverTransactionTableLowaterMark = this.serverTransactionTableHighwaterMark * 80 / 100; + // Lowater is 80% of highwater + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + this.getStackLogger() + .logError( + "transaction table size - bad value " + + ex.getMessage()); + } + } else { + // Issue 256 : consistent with MAX_CLIENT_TRANSACTIONS, if the MAX_SERVER_TRANSACTIONS is not set + // we assume the transaction table size can grow unlimited + this.unlimitedServerTransactionTableSize = true; + } + + String clientTransactionTableSize = configurationProperties + .getProperty("gov.nist.javax.sip.MAX_CLIENT_TRANSACTIONS"); + if (clientTransactionTableSize != null) { + try { + this.clientTransactionTableHiwaterMark = new Integer( + clientTransactionTableSize).intValue(); + this.clientTransactionTableLowaterMark = this.clientTransactionTableLowaterMark * 80 / 100; + // Lowater is 80% of highwater + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + this.getStackLogger() + .logError( + "transaction table size - bad value " + + ex.getMessage()); + } + } else { + this.unlimitedClientTransactionTableSize = true; + } + + super.cacheServerConnections = true; + String flag = configurationProperties + .getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS"); + + if (flag != null && "false".equalsIgnoreCase(flag.trim())) { + super.cacheServerConnections = false; + } + + super.cacheClientConnections = true; + String cacheflag = configurationProperties + .getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS"); + + if (cacheflag != null && "false".equalsIgnoreCase(cacheflag.trim())) { + super.cacheClientConnections = false; + } + + String readTimeout = configurationProperties + .getProperty("gov.nist.javax.sip.READ_TIMEOUT"); + if (readTimeout != null) { + try { + + int rt = Integer.parseInt(readTimeout); + if (rt >= 100) { + super.readTimeout = rt; + } else { + System.err.println("Value too low " + readTimeout); + } + } catch (NumberFormatException nfe) { + // Ignore. + if (isLoggingEnabled()) + getStackLogger().logError("Bad read timeout " + readTimeout); + } + } + + // Get the address of the stun server. + + String stunAddr = configurationProperties + .getProperty("gov.nist.javax.sip.STUN_SERVER"); + + if (stunAddr != null) + this.getStackLogger().logWarning( + "Ignoring obsolete property " + + "gov.nist.javax.sip.STUN_SERVER"); + + String maxMsgSize = configurationProperties + .getProperty("gov.nist.javax.sip.MAX_MESSAGE_SIZE"); + + try { + if (maxMsgSize != null) { + super.maxMessageSize = new Integer(maxMsgSize).intValue(); + if (super.maxMessageSize < 4096) + super.maxMessageSize = 4096; + } else { + // Allow for "infinite" size of message + super.maxMessageSize = 0; + } + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + getStackLogger().logError( + "maxMessageSize - bad value " + ex.getMessage()); + } + + String rel = configurationProperties + .getProperty("gov.nist.javax.sip.REENTRANT_LISTENER"); + this.reEntrantListener = (rel != null && "true".equalsIgnoreCase(rel)); + + // Check if a thread audit interval is specified + String interval = configurationProperties + .getProperty("gov.nist.javax.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS"); + if (interval != null) { + try { + // Make the monitored threads ping the auditor twice as fast as + // the audits + getThreadAuditor().setPingIntervalInMillisecs( + Long.valueOf(interval).longValue() / 2); + } catch (NumberFormatException ex) { + if (isLoggingEnabled()) + getStackLogger().logError( + "THREAD_AUDIT_INTERVAL_IN_MILLISECS - bad value [" + + interval + "] " + ex.getMessage()); + } + } + + // JvB: added property for testing + this + .setNon2XXAckPassedToListener(Boolean + .valueOf( + configurationProperties + .getProperty( + "gov.nist.javax.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER", + "false")).booleanValue()); + + this.generateTimeStampHeader = Boolean.valueOf( + configurationProperties.getProperty( + "gov.nist.javax.sip.AUTO_GENERATE_TIMESTAMP", "false")) + .booleanValue(); + + String messageLogFactoryClasspath = configurationProperties + .getProperty("gov.nist.javax.sip.LOG_FACTORY"); + if (messageLogFactoryClasspath != null) { + try { + Class<?> clazz = Class.forName(messageLogFactoryClasspath); + Constructor<?> c = clazz.getConstructor(new Class[0]); + this.logRecordFactory = (LogRecordFactory) c + .newInstance(new Object[0]); + } catch (Exception ex) { + if (isLoggingEnabled()) + getStackLogger() + .logError( + "Bad configuration value for LOG_FACTORY -- using default logger"); + this.logRecordFactory = new DefaultMessageLogFactory(); + } + + } else { + this.logRecordFactory = new DefaultMessageLogFactory(); + } + + boolean computeContentLength = configurationProperties.getProperty( + "gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", + "false").equalsIgnoreCase("true"); + StringMsgParser + .setComputeContentLengthFromMessage(computeContentLength); + + String tlsClientProtocols = configurationProperties.getProperty( + "gov.nist.javax.sip.TLS_CLIENT_PROTOCOLS"); + if (tlsClientProtocols != null) + { + StringTokenizer st = new StringTokenizer(tlsClientProtocols, " ,"); + String[] protocols = new String[st.countTokens()]; + + int i=0; + while (st.hasMoreTokens()) { + protocols[i++] = st.nextToken(); + } + this.enabledProtocols = protocols; + } + + super.rfc2543Supported = configurationProperties.getProperty( + "gov.nist.javax.sip.RFC_2543_SUPPORT_ENABLED", "true") + .equalsIgnoreCase("true"); + + super.cancelClientTransactionChecked = configurationProperties + .getProperty( + "gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", + "true").equalsIgnoreCase("true"); + super.logStackTraceOnMessageSend = configurationProperties.getProperty( + "gov.nist.javax.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND", "false") + .equalsIgnoreCase("true"); + if (isLoggingEnabled()) + getStackLogger().logDebug( + "created Sip stack. Properties = " + configurationProperties); + InputStream in = getClass().getResourceAsStream("/TIMESTAMP"); + if (in != null) { + BufferedReader streamReader = new BufferedReader( + new InputStreamReader(in)); + + try { + String buildTimeStamp = streamReader.readLine(); + if (in != null) { + in.close(); + } + getStackLogger().setBuildTimeStamp(buildTimeStamp); + } catch (IOException ex) { + getStackLogger().logError("Could not open build timestamp."); + } + } + + String bufferSize = configurationProperties.getProperty( + "gov.nist.javax.sip.RECEIVE_UDP_BUFFER_SIZE", MAX_DATAGRAM_SIZE + .toString()); + int bufferSizeInteger = new Integer(bufferSize).intValue(); + super.setReceiveUdpBufferSize(bufferSizeInteger); + + bufferSize = configurationProperties.getProperty( + "gov.nist.javax.sip.SEND_UDP_BUFFER_SIZE", MAX_DATAGRAM_SIZE + .toString()); + bufferSizeInteger = new Integer(bufferSize).intValue(); + super.setSendUdpBufferSize(bufferSizeInteger); + + boolean congetstionControlEnabled = Boolean + .parseBoolean(configurationProperties.getProperty( + "gov.nist.javax.sip.CONGESTION_CONTROL_ENABLED", + Boolean.TRUE.toString())); + super.stackDoesCongestionControl = congetstionControlEnabled; + + super.isBackToBackUserAgent = Boolean + .parseBoolean(configurationProperties.getProperty( + "gov.nist.javax.sip.IS_BACK_TO_BACK_USER_AGENT", + Boolean.FALSE.toString())); + super.checkBranchId = Boolean.parseBoolean(configurationProperties + .getProperty("gov.nist.javax.sip.REJECT_STRAY_RESPONSES", + Boolean.FALSE.toString())); + + super.isDialogTerminatedEventDeliveredForNullDialog = (Boolean.parseBoolean(configurationProperties.getProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", + Boolean.FALSE.toString()))); + + + super.maxForkTime = Integer.parseInt( + configurationProperties.getProperty("gov.nist.javax.sip.MAX_FORK_TIME_SECONDS","0")); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#createListeningPoint(java.lang.String, int, + * java.lang.String) + */ + public synchronized ListeningPoint createListeningPoint(String address, + int port, String transport) throws TransportNotSupportedException, + InvalidArgumentException { + if (isLoggingEnabled()) + getStackLogger().logDebug( + "createListeningPoint : address = " + address + " port = " + + port + " transport = " + transport); + + if (address == null) + throw new NullPointerException( + "Address for listening point is null!"); + if (transport == null) + throw new NullPointerException("null transport"); + if (port <= 0) + throw new InvalidArgumentException("bad port"); + + if (!transport.equalsIgnoreCase("UDP") + && !transport.equalsIgnoreCase("TLS") + && !transport.equalsIgnoreCase("TCP") + && !transport.equalsIgnoreCase("SCTP")) + throw new TransportNotSupportedException("bad transport " + + transport); + + /** Reusing an old stack instance */ + if (!this.isAlive()) { + this.toExit = false; + this.reInitialize(); + } + + String key = ListeningPointImpl.makeKey(address, port, transport); + + ListeningPointImpl lip = (ListeningPointImpl) listeningPoints.get(key); + if (lip != null) { + return lip; + } else { + try { + InetAddress inetAddr = InetAddress.getByName(address); + MessageProcessor messageProcessor = this + .createMessageProcessor(inetAddr, port, transport); + if (this.isLoggingEnabled()) { + this.getStackLogger().logDebug( + "Created Message Processor: " + address + + " port = " + port + " transport = " + + transport); + } + lip = new ListeningPointImpl(this, port, transport); + lip.messageProcessor = messageProcessor; + messageProcessor.setListeningPoint(lip); + this.listeningPoints.put(key, lip); + // start processing messages. + messageProcessor.start(); + return (ListeningPoint) lip; + } catch (java.io.IOException ex) { + if (isLoggingEnabled()) + getStackLogger().logError( + "Invalid argument address = " + address + " port = " + + port + " transport = " + transport); + throw new InvalidArgumentException(ex.getMessage(), ex); + } + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#createSipProvider(javax.sip.ListeningPoint) + */ + public SipProvider createSipProvider(ListeningPoint listeningPoint) + throws ObjectInUseException { + if (listeningPoint == null) + throw new NullPointerException("null listeningPoint"); + if (this.isLoggingEnabled()) + this.getStackLogger().logDebug( + "createSipProvider: " + listeningPoint); + ListeningPointImpl listeningPointImpl = (ListeningPointImpl) listeningPoint; + if (listeningPointImpl.sipProvider != null) + throw new ObjectInUseException("Provider already attached!"); + + SipProviderImpl provider = new SipProviderImpl(this); + + provider.setListeningPoint(listeningPointImpl); + listeningPointImpl.sipProvider = provider; + this.sipProviders.add(provider); + return provider; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#deleteListeningPoint(javax.sip.ListeningPoint) + */ + public void deleteListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException { + if (listeningPoint == null) + throw new NullPointerException("null listeningPoint arg"); + ListeningPointImpl lip = (ListeningPointImpl) listeningPoint; + // Stop the message processing thread in the listening point. + super.removeMessageProcessor(lip.messageProcessor); + String key = lip.getKey(); + this.listeningPoints.remove(key); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#deleteSipProvider(javax.sip.SipProvider) + */ + public void deleteSipProvider(SipProvider sipProvider) + throws ObjectInUseException { + + if (sipProvider == null) + throw new NullPointerException("null provider arg"); + SipProviderImpl sipProviderImpl = (SipProviderImpl) sipProvider; + + // JvB: API doc is not clear, but in_use == + // sipProviderImpl.sipListener!=null + // so we should throw if app did not call removeSipListener + // sipProviderImpl.sipListener = null; + if (sipProviderImpl.getSipListener() != null) { + throw new ObjectInUseException( + "SipProvider still has an associated SipListener!"); + } + + sipProviderImpl.removeListeningPoints(); + + // Bug reported by Rafael Barriuso + sipProviderImpl.stop(); + sipProviders.remove(sipProvider); + if (sipProviders.isEmpty()) { + this.stopStack(); + } + } + + /** + * Get the IP Address of the stack. + * + * @see javax.sip.SipStack#getIPAddress() + * @deprecated + */ + public String getIPAddress() { + return super.getHostAddress(); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#getListeningPoints() + */ + public java.util.Iterator getListeningPoints() { + return this.listeningPoints.values().iterator(); + } + + /** + * Return true if retransmission filter is active. + * + * @see javax.sip.SipStack#isRetransmissionFilterActive() + * @deprecated + */ + public boolean isRetransmissionFilterActive() { + return true; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#getSipProviders() + */ + public java.util.Iterator<SipProviderImpl> getSipProviders() { + return this.sipProviders.iterator(); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#getStackName() + */ + public String getStackName() { + return this.stackName; + } + + /** + * Finalization -- stop the stack on finalization. Exit the transaction + * scanner and release all resources. + * + * @see java.lang.Object#finalize() + */ + protected void finalize() { + this.stopStack(); + } + + /** + * This uses the default stack address to create a listening point. + * + * @see javax.sip.SipStack#createListeningPoint(java.lang.String, int, + * java.lang.String) + * @deprecated + */ + public ListeningPoint createListeningPoint(int port, String transport) + throws TransportNotSupportedException, InvalidArgumentException { + if (super.stackAddress == null) + throw new NullPointerException( + "Stack does not have a default IP Address!"); + return this.createListeningPoint(super.stackAddress, port, transport); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#stop() + */ + public void stop() { + if (isLoggingEnabled()) { + getStackLogger().logDebug("stopStack -- stoppping the stack"); + } + this.stopStack(); + this.sipProviders = new LinkedList<SipProviderImpl>(); + this.listeningPoints = new Hashtable<String, ListeningPointImpl>(); + /* + * Check for presence of an event scanner ( may happen if stack is + * stopped before listener is attached ). + */ + if (this.eventScanner != null) + this.eventScanner.forceStop(); + this.eventScanner = null; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#start() + */ + public void start() throws ProviderDoesNotExistException, SipException { + // Start a new event scanner if one does not exist. + if (this.eventScanner == null) { + this.eventScanner = new EventScanner(this); + } + + } + + /** + * Get the listener for the stack. A stack can have only one listener. To + * get an event from a provider, the listener has to be registered with the + * provider. The SipListener is application code. + * + * @return -- the stack SipListener + * + */ + public SipListener getSipListener() { + return this.sipListener; + } + + /** + * Get the message log factory registered with the stack. + * + * @return -- the messageLogFactory of the stack. + */ + public LogRecordFactory getLogRecordFactory() { + return super.logRecordFactory; + } + + /** + * Set the log appender ( this is useful if you want to specify a particular + * log format or log to something other than a file for example). This method + * is will be removed May 11, 2010 or shortly there after. + * + * @param Appender + * - the log4j appender to add. + * @deprecated TODO: remove this method May 11, 2010. + */ + // BEGIN android-deleted + /* + @Deprecated + public void addLogAppender(org.apache.log4j.Appender appender) { + if (this.getStackLogger() instanceof gov.nist.core.LogWriter) { + ((gov.nist.core.LogWriter) this.getStackLogger()).addAppender(appender); + } + } + */ + // END android-deleted + + /** + * Get the log4j logger ( for log stream integration ). + * This method will be removed May 11, 2010 or shortly there after. + * + * @return the log4j logger. + * @deprecated TODO: This method will be removed May 11, 2010. + */ + @Deprecated + // BEGIN andoird-deleted + /* + public org.apache.log4j.Logger getLogger() { + if (this.getStackLogger() instanceof gov.nist.core.LogWriter) { + return ((gov.nist.core.LogWriter) this.getStackLogger()).getLogger(); + } + return null; + } + */ + // END android-deleted + + public EventScanner getEventScanner() { + return eventScanner; + } + + /* + * (non-Javadoc) + * + * @see + * gov.nist.javax.sip.SipStackExt#getAuthenticationHelper(gov.nist.javax + * .sip.clientauthutils.AccountManager, javax.sip.header.HeaderFactory) + */ + public AuthenticationHelper getAuthenticationHelper( + AccountManager accountManager, HeaderFactory headerFactory) { + return new AuthenticationHelperImpl(this, accountManager, headerFactory); + } + + /* + * (non-Javadoc) + * + * @see + * gov.nist.javax.sip.SipStackExt#getAuthenticationHelper(gov.nist.javax + * .sip.clientauthutils.AccountManager, javax.sip.header.HeaderFactory) + */ + public AuthenticationHelper getSecureAuthenticationHelper( + SecureAccountManager accountManager, HeaderFactory headerFactory) { + return new AuthenticationHelperImpl(this, accountManager, headerFactory); + } + + /** + * Set the list of cipher suites supported by the stack. A stack can have + * only one set of suites. These are not validated against the supported + * cipher suites of the java runtime, so specifying a cipher here does not + * guarantee that it will work.<br> + * The stack has a default cipher suite of: + * <ul> + * <li>TLS_RSA_WITH_AES_128_CBC_SHA</li> + * <li>SSL_RSA_WITH_3DES_EDE_CBC_SHA</li> + * <li>TLS_DH_anon_WITH_AES_128_CBC_SHA</li> + * <li>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</li> + * </ul> + * + * <b>NOTE: This function must be called before adding a TLS listener</b> + * + * @param String + * [] The new set of ciphers to support. + * @return + * + */ + public void setEnabledCipherSuites(String[] newCipherSuites) { + cipherSuites = newCipherSuites; + } + + /** + * Return the currently enabled cipher suites of the Stack. + * + * @return The currently enabled cipher suites. + */ + public String[] getEnabledCipherSuites() { + return cipherSuites; + } + + /** + * Set the list of protocols supported by the stack for outgoing TLS connections. + * A stack can have only one set of protocols. + * These are not validated against the supported + * protocols of the java runtime, so specifying a protocol here does not + * guarantee that it will work.<br> + * The stack has a default protocol suite of: + * <ul> + * <li>SSLv3</li> + * <li>SSLv2Hello</li> + * <li>TLSv1</li> + * </ul> + * + * <b>NOTE: This function must be called before creating a TLSMessageChannel.</b> + * + * @param String + * [] The new set of protocols to use for outgoing TLS connections. + * @return + * + */ + public void setEnabledProtocols(String[] newProtocols) { + enabledProtocols = newProtocols; + } + + /** + * Return the currently enabled protocols to use when creating TLS connection. + * + * @return The currently enabled protocols. + */ + public String[] getEnabledProtocols() { + return enabledProtocols; + } + + /** + * Set the "back to back User Agent" flag. + * + * @param flag + * - boolean flag to set. + * + */ + public void setIsBackToBackUserAgent(boolean flag) { + super.isBackToBackUserAgent = flag; + } + + /** + * Get the "back to back User Agent" flag. + * + * return the value of the flag + * + */ + public boolean isBackToBackUserAgent() { + return super.isBackToBackUserAgent; + } + + public boolean isAutomaticDialogErrorHandlingEnabled() { + return super.isAutomaticDialogErrorHandlingEnabled; + } + + public boolean acquireSem() { + try { + return this.stackSemaphore.tryAcquire(10, TimeUnit.SECONDS); + } catch ( InterruptedException ex) { + return false; + } + } + + public void releaseSem() { + this.stackSemaphore.release(); + } + + + + +} diff --git a/java/gov/nist/javax/sip/TransactionExt.java b/java/gov/nist/javax/sip/TransactionExt.java new file mode 100644 index 0000000..5024944 --- /dev/null +++ b/java/gov/nist/javax/sip/TransactionExt.java @@ -0,0 +1,69 @@ + +package gov.nist.javax.sip; + +import java.security.cert.Certificate; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.sip.SipProvider; +import javax.sip.Transaction; + +public interface TransactionExt extends Transaction { + + /** + * Get the Sip Provider associated with this transaction + */ + public SipProvider getSipProvider(); + + /** + * Returns the IP address of the upstream/downstream hop from which this message was initially received + * @return the IP address of the upstream/downstream hop from which this message was initially received + * @since 2.0 + */ + public String getPeerAddress(); + /** + * Returns the port of the upstream/downstream hop from which this message was initially received + * @return the port of the upstream/downstream hop from which this message was initially received + * @since 2.0 + */ + public int getPeerPort(); + /** + * Returns the name of the protocol with which this message was initially received + * @return the name of the protocol with which this message was initially received + * @since 2.0 + */ + public String getTransport(); + + /** + * return the ip address on which this message was initially received + * @return the ip address on which this message was initially received + */ + public String getHost(); + /** + * return the port on which this message was initially received + * @return the port on which this message was initially received + */ + public int getPort(); + + /** + * Return the Cipher Suite that was used for the SSL handshake. + * + * @return Returns the cipher suite in use by the session which was produced by the handshake. + * @throw UnsupportedOperationException if this is not a secure client transaction. + */ + public String getCipherSuite() throws UnsupportedOperationException; + + /** + * Get the certificate(s) that were sent to the peer during handshaking. + *@return the certificate(s) that were sent to the peer during handshaking. + *@throw UnsupportedOperationException if this is not a secure client transaction. + * + */ + Certificate[] getLocalCertificates() throws UnsupportedOperationException; + + /** + * @return the identity of the peer which was identified as part of defining the session. + * @throws SSLPeerUnverifiedException + * @throw UnsupportedOperationException if this is not a secure client transaction. + */ + Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException; +} diff --git a/java/gov/nist/javax/sip/Utils.java b/java/gov/nist/javax/sip/Utils.java new file mode 100644 index 0000000..be66aeb --- /dev/null +++ b/java/gov/nist/javax/sip/Utils.java @@ -0,0 +1,208 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip; + +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.message.SIPResponse; + +import java.security.MessageDigest; +import java.util.HashSet; + +/** + * A few utilities that are used in various places by the stack. This is used to + * convert byte arrays to hex strings etc. Generate tags and branch identifiers + * and odds and ends. + * + * @author mranga + * @version 1.2 $Revision: 1.21 $ $Date: 2009/10/18 13:46:37 $ + */ +public class Utils implements UtilsExt { + + private static MessageDigest digester; + + private static java.util.Random rand; + + private static long counter = 0; + + private static int callIDCounter; + + private static String signature ; + + private static Utils instance = new Utils(); + + + /** + * to hex converter + */ + private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + static { + try { + digester = MessageDigest.getInstance("MD5"); + } catch (Exception ex) { + throw new RuntimeException("Could not intialize Digester ", ex); + } + rand = new java.util.Random(); + signature = toHexString(Integer.toString(Math.abs( rand.nextInt() % 1000 )).getBytes()); + } + + + public static Utils getInstance() { + return instance; + } + + /** + * convert an array of bytes to an hexadecimal string + * + * @return a string + * @param b + * bytes array to convert to a hexadecimal string + */ + + public static String toHexString(byte b[]) { + int pos = 0; + char[] c = new char[b.length * 2]; + for (int i = 0; i < b.length; i++) { + c[pos++] = toHex[(b[i] >> 4) & 0x0F]; + c[pos++] = toHex[b[i] & 0x0f]; + } + return new String(c); + } + + /** + * Put quotes around a string and return it. + * Any " characters appearing in str are escaped + * + * @return a quoted string + * @param str + * string to be quoted + */ + public static String getQuotedString(String str) { + return '"' + str.replace( "\"", "\\\"" ) + '"'; + } + + /** + * Squeeze out all white space from a string and return the reduced string. + * + * @param input + * input string to sqeeze. + * @return String a reduced string. + */ + protected static String reduceString(String input) { + String newString = input.toLowerCase(); + int len = newString.length(); + String retval = ""; + for (int i = 0; i < len; i++) { + if (newString.charAt(i) == ' ' || newString.charAt(i) == '\t') + continue; + else + retval += newString.charAt(i); + } + return retval; + } + + /** + * Generate a call identifier. This is useful when we want to generate a + * call identifier in advance of generating a message. + */ + public synchronized String generateCallIdentifier(String address) { + + String date = Long.toString(System.currentTimeMillis() + callIDCounter++ + + rand.nextLong()); + byte cid[] = digester.digest(date.getBytes()); + + String cidString = Utils.toHexString(cid); + return cidString + "@" + address; + + } + + /** + * Generate a tag for a FROM header or TO header. Just return a random 4 + * digit integer (should be enough to avoid any clashes!) Tags only need to + * be unique within a call. + * + * @return a string that can be used as a tag parameter. + * + * synchronized: needed for access to 'rand', else risk to generate same tag + * twice + */ + public synchronized String generateTag() { + + return Integer.toHexString(rand.nextInt()); + + } + + /** + * Generate a cryptographically random identifier that can be used to + * generate a branch identifier. + * + * @return a cryptographically random gloablly unique string that can be + * used as a branch identifier. + */ + public synchronized String generateBranchId() { + // + + + long num = rand.nextLong() + Utils.counter++ + System.currentTimeMillis(); + + byte bid[] = digester.digest(Long.toString(num).getBytes()); + // prepend with a magic cookie to indicate we are bis09 compatible. + return SIPConstants.BRANCH_MAGIC_COOKIE + Utils.toHexString(bid) + this.signature; + + + } + + public boolean responseBelongsToUs(SIPResponse response) { + Via topmostVia = response.getTopmostVia(); + String branch = topmostVia.getBranch(); + return branch != null && branch.endsWith(this.signature); + } + + public static String getSignature() { + return signature; + } + + public static void main(String[] args) { + HashSet branchIds = new HashSet(); + for (int b = 0; b < 100000; b++) { + String bid = Utils.getInstance().generateBranchId(); + if (branchIds.contains(bid)) { + throw new RuntimeException("Duplicate Branch ID"); + } else { + branchIds.add(bid); + } + } + System.out.println("Done!!"); + + } + + + +} diff --git a/java/gov/nist/javax/sip/UtilsExt.java b/java/gov/nist/javax/sip/UtilsExt.java new file mode 100644 index 0000000..4fbed61 --- /dev/null +++ b/java/gov/nist/javax/sip/UtilsExt.java @@ -0,0 +1,55 @@ +/* + * JBoss, Home of Professional Open Source + * This code has been contributed to the public domain. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip; + +/** + * @author jean.deruelle@gmail.com + * + */ +public interface UtilsExt { + + /** + * Generate a call identifier. This is useful when we want to generate a + * call identifier in advance of generating a message. + * @since 2.0 + */ + public String generateCallIdentifier(String address); + + /** + * Generate a tag for a FROM header or TO header. Just return a random 4 + * digit integer (should be enough to avoid any clashes!) Tags only need to + * be unique within a call. + * + * @return a string that can be used as a tag parameter. + * + * synchronized: needed for access to 'rand', else risk to generate same tag + * twice + * @since 2.0 + */ + public String generateTag(); + /** + * Generate a cryptographically random identifier that can be used to + * generate a branch identifier. + * + * @return a cryptographically random gloablly unique string that can be + * used as a branch identifier. + * @since 2.0 + */ + public String generateBranchId(); + + +} diff --git a/java/gov/nist/javax/sip/address/AddressFactoryImpl.java b/java/gov/nist/javax/sip/address/AddressFactoryImpl.java new file mode 100644 index 0000000..0f23304 --- /dev/null +++ b/java/gov/nist/javax/sip/address/AddressFactoryImpl.java @@ -0,0 +1,228 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; + +import gov.nist.javax.sip.parser.*; + +import java.text.ParseException; +import javax.sip.address.*; + +/** + * Implementation of the JAIN-SIP address factory. + * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/22 10:25:56 $ + * + * @author M. Ranganathan <br/> + * + * + * + * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/> + * Network Research Team (http://www-r2.u-strasbg.fr))<br/> + * Louis Pasteur University - Strasbourg - France<br/> + * + */ +public class AddressFactoryImpl implements javax.sip.address.AddressFactory { + + /** Creates a new instance of AddressFactoryImpl + */ + public AddressFactoryImpl() { + } + + + /** + * + *Create an empty address object. + * + *SPEC_REVISION + */ + + public javax.sip.address.Address createAddress() { + return new AddressImpl(); + } + /** + * Creates an Address with the new display name and URI attribute + * values. + * + * @param displayName - the new string value of the display name of the + * address. A <code>null</code> value does not set the display name. + * @param uri - the new URI value of the address. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the displayName value. + */ + public javax.sip.address.Address createAddress( + String displayName, + javax.sip.address.URI uri) { + if (uri == null) + throw new NullPointerException("null URI"); + AddressImpl addressImpl = new AddressImpl(); + if (displayName != null) + addressImpl.setDisplayName(displayName); + addressImpl.setURI(uri); + return addressImpl; + + } + + /** create a sip uri. + * + *@param uri -- the uri to parse. + */ + public javax.sip.address.SipURI createSipURI(String uri) + // throws java.net.URISyntaxException { + throws ParseException { + if (uri == null) + throw new NullPointerException("null URI"); + try { + StringMsgParser smp = new StringMsgParser(); + SipUri sipUri = smp.parseSIPUrl(uri); + return (SipURI) sipUri; + } catch (ParseException ex) { + // throw new java.net.URISyntaxException(uri, ex.getMessage()); + throw new ParseException(ex.getMessage(), 0); + } + + } + + /** Create a SipURI + * + *@param user -- the user + *@param host -- the host. + */ + public javax.sip.address.SipURI createSipURI(String user, String host) + throws ParseException { + if (host == null) + throw new NullPointerException("null host"); + + StringBuffer uriString = new StringBuffer("sip:"); + if (user != null) { + uriString.append(user); + uriString.append("@"); + } + + //if host is an IPv6 string we should enclose it in sq brackets + if (host.indexOf(':') != host.lastIndexOf(':') + && host.trim().charAt(0) != '[') + host = '[' + host + ']'; + + uriString.append(host); + + StringMsgParser smp = new StringMsgParser(); + try { + + SipUri sipUri = smp.parseSIPUrl(uriString.toString()); + return sipUri; + } catch (ParseException ex) { + throw new ParseException(ex.getMessage(), 0); + } + } + + /** + * Creates a TelURL based on given URI string. The scheme or '+' should + * not be included in the phoneNumber string argument. + * + * @param uri - the new string value of the phoneNumber. + * @throws URISyntaxException if the URI string is malformed. + */ + public javax.sip.address.TelURL createTelURL(String uri) + throws ParseException { + if (uri == null) + throw new NullPointerException("null url"); + String telUrl = "tel:" + uri; + try { + StringMsgParser smp = new StringMsgParser(); + TelURLImpl timp = (TelURLImpl) smp.parseUrl(telUrl); + return (TelURL) timp; + } catch (ParseException ex) { + throw new ParseException(ex.getMessage(), 0); + } + } + + public javax.sip.address.Address createAddress(javax.sip.address.URI uri) { + if (uri == null) + throw new NullPointerException("null address"); + AddressImpl addressImpl = new AddressImpl(); + addressImpl.setURI(uri); + return addressImpl; + } + + /** + * Creates an Address with the new address string value. The address + * string is parsed in order to create the new Address instance. Create + * with a String value of "*" creates a wildcard address. The wildcard + * can be determined if + * <code>((SipURI)Address.getURI).getUser() == *;</code>. + * + * @param address - the new string value of the address. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the address value. + */ + public javax.sip.address.Address createAddress(String address) + throws java.text.ParseException { + if (address == null) + throw new NullPointerException("null address"); + + if (address.equals("*")) { + AddressImpl addressImpl = new AddressImpl(); + addressImpl.setAddressType(AddressImpl.WILD_CARD); + SipURI uri = new SipUri(); + uri.setUser("*"); + addressImpl.setURI( uri ); + return addressImpl; + } else { + StringMsgParser smp = new StringMsgParser(); + return smp.parseAddress(address); + } + } + + /** + * Creates a URI based on given URI string. The URI string is parsed in + * order to create the new URI instance. Depending on the scheme the + * returned may or may not be a SipURI or TelURL cast as a URI. + * + * @param uri - the new string value of the URI. + * @throws URISyntaxException if the URI string is malformed. + */ + + public javax.sip.address.URI createURI(String uri) throws ParseException { + if (uri == null) + throw new NullPointerException("null arg"); + try { + URLParser urlParser = new URLParser(uri); + String scheme = urlParser.peekScheme(); + if (scheme == null) + throw new ParseException("bad scheme", 0); + if (scheme.equalsIgnoreCase("sip")) { + return (javax.sip.address.URI) urlParser.sipURL(true); + } else if (scheme.equalsIgnoreCase("sips")) { + return (javax.sip.address.URI) urlParser.sipURL(true); + } else if (scheme.equalsIgnoreCase("tel")) { + return (javax.sip.address.URI) urlParser.telURL(true); + } + } catch (ParseException ex) { + throw new ParseException(ex.getMessage(), 0); + } + return new gov.nist.javax.sip.address.GenericURI(uri); + } + +} diff --git a/java/gov/nist/javax/sip/address/AddressImpl.java b/java/gov/nist/javax/sip/address/AddressImpl.java new file mode 100644 index 0000000..0ab4a93 --- /dev/null +++ b/java/gov/nist/javax/sip/address/AddressImpl.java @@ -0,0 +1,346 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.address; +import gov.nist.core.*; +import javax.sip.address.*; + +/* + * BUG Fix from Antonis Kadris. + */ +/** + * Address structure. Imbeds a URI and adds a display name. + * + *@author M. Ranganathan <br/> + * + * + * + *@version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:21 $ + * + */ +public final class AddressImpl + extends NetObject + implements javax.sip.address.Address { + + + private static final long serialVersionUID = 429592779568617259L; + + /** Constant field. + */ + public static final int NAME_ADDR = 1; + + /** constant field. + */ + public static final int ADDRESS_SPEC = 2; + + /** Constant field. + */ + public static final int WILD_CARD = 3; + + protected int addressType; + + /** displayName field + */ + protected String displayName; + + /** address field + */ + protected GenericURI address; + + /** Match on the address only. + * Dont care about the display name. + */ + + public boolean match(Object other) { + // TODO -- add the matcher; + if (other == null) + return true; + if (!(other instanceof Address)) + return false; + else { + AddressImpl that = (AddressImpl) other; + if (that.getMatcher() != null) + return that.getMatcher().match(this.encode()); + else if (that.displayName != null && this.displayName == null) + return false; + else if (that.displayName == null) + return address.match(that.address); + else + return displayName.equalsIgnoreCase(that.displayName) + && address.match(that.address); + } + + } + + /** Get the host port portion of the address spec. + *@return host:port in a HostPort structure. + */ + public HostPort getHostPort() { + if (!(address instanceof SipUri)) + throw new RuntimeException("address is not a SipUri"); + SipUri uri = (SipUri) address; + return uri.getHostPort(); + } + + /** Get the port from the imbedded URI. This assumes that a SIP URL + * is encapsulated in this address object. + * + *@return the port from the address. + * + */ + public int getPort() { + if (!(address instanceof SipUri)) + throw new RuntimeException("address is not a SipUri"); + SipUri uri = (SipUri) address; + return uri.getHostPort().getPort(); + } + + /** Get the user@host:port for the address field. This assumes + * that the encapsulated object is a SipUri. + * + * + *@return string containing user@host:port. + */ + public String getUserAtHostPort() { + if (address instanceof SipUri) { + SipUri uri = (SipUri) address; + return uri.getUserAtHostPort(); + } else + return address.toString(); + } + + /** Get the host name from the address. + * + *@return the host name. + */ + public String getHost() { + if (!(address instanceof SipUri)) + throw new RuntimeException("address is not a SipUri"); + SipUri uri = (SipUri) address; + return uri.getHostPort().getHost().getHostname(); + } + + /** Remove a parameter from the address. + * + *@param parameterName is the name of the parameter to remove. + */ + public void removeParameter(String parameterName) { + if (!(address instanceof SipUri)) + throw new RuntimeException("address is not a SipUri"); + SipUri uri = (SipUri) address; + uri.removeParameter(parameterName); + } + + /** + * Encode the address as a string and return it. + * @return String canonical encoded version of this address. + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (this.addressType == WILD_CARD) { + buffer.append('*'); + } + else { + if (displayName != null) { + buffer.append(DOUBLE_QUOTE) + .append(displayName) + .append(DOUBLE_QUOTE) + .append(SP); + } + if (address != null) { + if (addressType == NAME_ADDR || displayName != null) + buffer.append(LESS_THAN); + address.encode(buffer); + if (addressType == NAME_ADDR || displayName != null) + buffer.append(GREATER_THAN); + } + } + return buffer; + } + + public AddressImpl() { + this.addressType = NAME_ADDR; + } + + /** + * Get the address type; + * @return int + */ + public int getAddressType() { + return addressType; + } + + /** + * Set the address type. The address can be NAME_ADDR, ADDR_SPEC or + * WILD_CARD + * + * @param atype int to set + * + */ + public void setAddressType(int atype) { + addressType = atype; + } + + /** + * get the display name + * + * @return String + * + */ + public String getDisplayName() { + return displayName; + } + + /** + * Set the displayName member + * + * @param displayName String to set + * + */ + public void setDisplayName(String displayName) { + this.displayName = displayName; + this.addressType = NAME_ADDR; + } + + /** + * Set the address field + * + * @param address SipUri to set + * + */ + public void setAddess(javax.sip.address.URI address) { + this.address = (GenericURI) address; + } + + /** + * hashCode impelmentation + * + */ + public int hashCode() { + return this.address.hashCode(); + } + + /** + * Compare two address specs for equality. + * + * @param other Object to compare this this address + * + * @return boolean + * + */ + public boolean equals(Object other) { + + if (this==other) return true; + + if (other instanceof Address) { + final Address o = (Address) other; + + // Don't compare display name (?) + return this.getURI().equals( o.getURI() ); + } + return false; + } + + /** return true if DisplayName exist. + * + * @return boolean + */ + public boolean hasDisplayName() { + return (displayName != null); + } + + /** remove the displayName field + */ + public void removeDisplayName() { + displayName = null; + } + + /** Return true if the imbedded URI is a sip URI. + * + * @return true if the imbedded URI is a SIP URI. + * + */ + public boolean isSIPAddress() { + return address instanceof SipUri; + } + + /** Returns the URI address of this Address. The type of URI can be + * determined by the scheme. + * + * @return address parmater of the Address object + */ + public URI getURI() { + return this.address; + } + + /** This determines if this address is a wildcard address. That is + * <code>Address.getAddress.getUserInfo() == *;</code> + * + * @return true if this name address is a wildcard, false otherwise. + */ + public boolean isWildcard() { + return this.addressType == WILD_CARD; + } + + /** Sets the URI address of this Address. The URI can be either a + * TelURL or a SipURI. + * + * @param address - the new URI address value of this NameAddress. + */ + public void setURI(URI address) { + this.address = (GenericURI) address; + } + + /** Set the user name for the imbedded URI. + * + *@param user -- user name to set for the imbedded URI. + */ + public void setUser(String user) { + ((SipUri) this.address).setUser(user); + } + + /** Mark this a wild card address type. + * Also set the SIP URI to a special wild card address. + */ + public void setWildCardFlag() { + this.addressType = WILD_CARD; + this.address = new SipUri(); + ((SipUri)this.address).setUser("*"); + } + + public Object clone() { + AddressImpl retval = (AddressImpl) super.clone(); + if (this.address != null) + retval.address = (GenericURI) this.address.clone(); + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/address/Authority.java b/java/gov/nist/javax/sip/address/Authority.java new file mode 100644 index 0000000..c277dd1 --- /dev/null +++ b/java/gov/nist/javax/sip/address/Authority.java @@ -0,0 +1,236 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.address; +import gov.nist.core.*; + +/** + * Authority part of a URI structure. Section 3.2.2 RFC2396 + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/12/16 14:48:33 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class Authority extends NetObject { + + private static final long serialVersionUID = -3570349777347017894L; + + /** hostport field + */ + protected HostPort hostPort; + + /** userInfo field + */ + protected UserInfo userInfo; + + /** + * Return the host name in encoded form. + * @return encoded string (does the same thing as toString) + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (userInfo != null) { + userInfo.encode(buffer); + buffer.append(AT); + hostPort.encode(buffer); + } else { + hostPort.encode(buffer); + } + return buffer; + } + + /** retruns true if the two Objects are equals , false otherwise. + * @param other Object to test. + * @return boolean + */ + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (other.getClass() != getClass()) { + return false; + } + Authority otherAuth = (Authority) other; + if (!this.hostPort.equals(otherAuth.hostPort)) { + return false; + } + if (this.userInfo != null && otherAuth.userInfo != null) { + if (!this.userInfo.equals(otherAuth.userInfo)) { + return false; + } + } + return true; + } + + /** + * get the hostPort member. + * @return HostPort + */ + public HostPort getHostPort() { + return hostPort; + } + + /** + * get the userInfo memnber. + * @return UserInfo + */ + public UserInfo getUserInfo() { + return userInfo; + } + + /** + * Get password from the user info. + * @return String + */ + public String getPassword() { + if (userInfo == null) + return null; + else + return userInfo.password; + } + + /** + * Get the user name if it exists. + * @return String user or null if not set. + */ + public String getUser() { + return userInfo != null ? userInfo.user : null; + } + + /** + * Get the host name. + * @return Host (null if not set) + */ + public Host getHost() { + if (hostPort == null) + return null; + else + return hostPort.getHost(); + } + + /** + * Get the port. + * @return int port (-1) if port is not set. + */ + public int getPort() { + if (hostPort == null) + return -1; + else + return hostPort.getPort(); + } + + /** remove the port. + */ + public void removePort() { + if (hostPort != null) + hostPort.removePort(); + } + + /** + * set the password. + * @param passwd String to set + */ + public void setPassword(String passwd) { + if (userInfo == null) + userInfo = new UserInfo(); + userInfo.setPassword(passwd); + } + + /** + * Set the user name of the userInfo member. + * @param user String to set + */ + public void setUser(String user) { + if (userInfo == null) + userInfo = new UserInfo(); + this.userInfo.setUser(user); + } + + /** + * set the host. + * @param host Host to set + */ + public void setHost(Host host) { + if (hostPort == null) + hostPort = new HostPort(); + hostPort.setHost(host); + } + + /** + * Set the port. + * @param port int to set + */ + public void setPort(int port) { + if (hostPort == null) + hostPort = new HostPort(); + hostPort.setPort(port); + } + + /** + * Set the hostPort member + * @param h HostPort to set + */ + public void setHostPort(HostPort h) { + hostPort = h; + } + + /** + * Set the userInfo member + * @param u UserInfo to set + */ + public void setUserInfo(UserInfo u) { + userInfo = u; + } + + /** Remove the user Infor. + * + */ + public void removeUserInfo() { + this.userInfo = null; + } + + public Object clone() { + Authority retval = (Authority) super.clone(); + if (this.hostPort != null) + retval.hostPort = (HostPort) this.hostPort.clone(); + if (this.userInfo != null) + retval.userInfo = (UserInfo) this.userInfo.clone(); + return retval; + } + + @Override + public int hashCode() { + if ( this.hostPort == null ) throw new UnsupportedOperationException("Null hostPort cannot compute hashcode"); + return this.hostPort.encode().hashCode(); + } +} diff --git a/java/gov/nist/javax/sip/address/GenericURI.java b/java/gov/nist/javax/sip/address/GenericURI.java new file mode 100644 index 0000000..9b51b4b --- /dev/null +++ b/java/gov/nist/javax/sip/address/GenericURI.java @@ -0,0 +1,134 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; +import java.text.ParseException; + +import javax.sip.address.URI; + +/** + * Implementation of the URI class. This relies on the 1.4 URI class. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/15 19:50:45 $ + * + * + */ +public class GenericURI extends NetObject implements javax.sip.address.URI { + /** + * + */ + private static final long serialVersionUID = 3237685256878068790L; + public static final String SIP = ParameterNames.SIP_URI_SCHEME; + public static final String SIPS = ParameterNames.SIPS_URI_SCHEME; + public static final String TEL = ParameterNames.TEL_URI_SCHEME; + public static final String POSTDIAL = ParameterNames.POSTDIAL; + public static final String PHONE_CONTEXT_TAG = + ParameterNames.PHONE_CONTEXT_TAG; + public static final String ISUB = ParameterNames.ISUB; + public static final String PROVIDER_TAG = ParameterNames.PROVIDER_TAG; + + /** Imbedded URI + */ + protected String uriString; + + /** + * The URI Scheme. + */ + protected String scheme; + + /** Consturctor + */ + protected GenericURI() { + } + + /** Constructor given the URI string + * @param uriString The imbedded URI string. + * @throws java.net.URISyntaxException When there is a syntaz error in the imbedded URI. + */ + public GenericURI(String uriString) throws ParseException { + try { + this.uriString = uriString; + int i = uriString.indexOf(":"); + scheme = uriString.substring(0, i); + } catch (Exception e) { + throw new ParseException("GenericURI, Bad URI format", 0); + } + } + + /** Encode the URI. + * @return The encoded URI + */ + public String encode() { + return uriString; + } + + public StringBuffer encode(StringBuffer buffer) { + return buffer.append(uriString); + } + + /** Encode this URI. + * @return The encoded URI + */ + public String toString() { + return this.encode(); + + } + + /** Returns the value of the "scheme" of + * this URI, for example "sip", "sips" or "tel". + * + * @return the scheme paramter of the URI + */ + public String getScheme() { + return scheme; + } + + /** This method determines if this is a URI with a scheme of + * "sip" or "sips". + * + * @return true if the scheme is "sip" or "sips", false otherwise. + */ + public boolean isSipURI() { + return this instanceof SipUri; + } + + // @Override + public boolean equals(Object that) { + if (this==that) return true; + else if (that instanceof URI) { + final URI o = (URI) that; + + // This is not sufficient for equality; revert to String equality... + // return this.getScheme().equalsIgnoreCase( o.getScheme() ) + return this.toString().equalsIgnoreCase( o.toString() ); + } + return false; + } + + public int hashCode() { + return this.toString().hashCode(); + } +} diff --git a/java/gov/nist/javax/sip/address/NetObject.java b/java/gov/nist/javax/sip/address/NetObject.java new file mode 100644 index 0000000..6dd3ec6 --- /dev/null +++ b/java/gov/nist/javax/sip/address/NetObject.java @@ -0,0 +1,396 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.address; + +import gov.nist.core.*; + +import java.lang.reflect.*; + +/** + * Root object for all objects in this package. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:22 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public abstract class NetObject extends GenericObject { + + protected static final String CORE_PACKAGE = PackageNames.CORE_PACKAGE; + protected static final String NET_PACKAGE = PackageNames.NET_PACKAGE; + protected static final String PARSER_PACKAGE = PackageNames.PARSER_PACKAGE; + protected static final String UDP = "udp"; + protected static final String TCP = "tcp"; + protected static final String TRANSPORT = "transport"; + protected static final String METHOD = "method"; + protected static final String USER = "user"; + protected static final String PHONE = "phone"; + protected static final String MADDR = "maddr"; + protected static final String TTL = "ttl"; + protected static final String LR = "lr"; + protected static final String SIP = "sip"; + protected static final String SIPS = "sips"; + + // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + protected static final String TLS = "tls"; + + // Added by Peter Musgrave <pmusgrave@newheights.com> + // params for outbound and gruu drafts + protected static final String GRUU = "gr"; + + + /** Default constructor + */ + public NetObject() { + super(); + } + + /** + * An introspection based equality predicate for SIPObjects. + *@param that is the other object to test against. + */ + public boolean equals(Object that) { + if (!this.getClass().equals(that.getClass())) + return false; + Class<?> myclass = this.getClass(); + Class<?> hisclass = that.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } + } else if (g.get(that) == f.get(this)) + continue; + else if (f.get(this) == null && g.get(that) != null) + return false; + else if (g.get(that) == null && f.get(that) != null) + return false; + else if (!f.get(this).equals(g.get(that))) + return false; + } catch (IllegalAccessException ex1) { + InternalErrorHandler.handleException(ex1); + } + } + if (myclass.equals(NetObject.class)) + break; + else { + myclass = myclass.getSuperclass(); + hisclass = hisclass.getSuperclass(); + } + } + return true; + } + + + + + /** An introspection based predicate matching using a template + * object. Allows for partial match of two protocl Objects. + *@param other the match pattern to test against. The match object + * has to be of the same type (class). Primitive types + * and non-sip fields that are non null are matched for equality. + * Null in any field matches anything. Some book-keeping fields + * are ignored when making the comparison. + *@return true if match succeeds false otherwise. + */ + + public boolean match(Object other) { + if (other == null) + return true; + if (!this.getClass().equals(other.getClass())) + return false; + GenericObject that = (GenericObject) other; + // System.out.println("Comparing " + that.encode()); + // System.out.println("this = " + this.encode()); + + Class<?> hisclass = other.getClass(); + Class<?> myclass = this.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } + } else { + Object myObj = f.get(this); + Object hisObj = g.get(that); + if (hisObj != null && myObj == null) + return false; + else if (hisObj == null && myObj != null) + continue; + else if (hisObj == null && myObj == null) + continue; + else if ( + hisObj instanceof java.lang.String + && myObj instanceof java.lang.String) { + if (((String) hisObj).equals("")) + continue; + if (((String) myObj) + .compareToIgnoreCase((String) hisObj) + != 0) + return false; + } else if ( + GenericObject.isMySubclass(myObj.getClass()) + && GenericObject.isMySubclass(hisObj.getClass()) + && myObj.getClass().equals(hisObj.getClass()) + && ((GenericObject) hisObj).getMatcher() + != null) { + String myObjEncoded = + ((GenericObject) myObj).encode(); + boolean retval = + ((GenericObject) hisObj).getMatcher().match( + myObjEncoded); + if (!retval) + return false; + } else if ( + GenericObject.isMySubclass(myObj.getClass()) + && !((GenericObject) myObj).match(hisObj)) + return false; + else if ( + GenericObjectList.isMySubclass(myObj.getClass()) + && !((GenericObjectList) myObj).match(hisObj)) + return false; + } + } catch (IllegalAccessException ex1) { + InternalErrorHandler.handleException(ex1); + } + } + if (myclass.equals(NetObject.class)) + break; + else { + myclass = myclass.getSuperclass(); + hisclass = hisclass.getSuperclass(); + } + } + return true; + } + + /** + * An introspection based string formatting method. We need this because + * in this package (although it is an exact duplicate of the one in + * the superclass) because it needs to access the protected members + * of the other objects in this class. + * @return String + */ + public String debugDump() { + stringRepresentation = ""; + Class<?> myclass = getClass(); + sprint(myclass.getName()); + sprint("{"); + Field[] fields = myclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + // avoid nasty recursions... + continue; + } + if (fieldName.compareTo("indentation") == 0) { + // formatting stuff - not relevant here. + continue; + } + sprint(fieldName + ":"); + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + sprint(fname + ":"); + if (fname.compareTo("int") == 0) { + int intfield = f.getInt(this); + sprint(intfield); + } else if (fname.compareTo("short") == 0) { + short shortField = f.getShort(this); + sprint(shortField); + } else if (fname.compareTo("char") == 0) { + char charField = f.getChar(this); + sprint(charField); + } else if (fname.compareTo("long") == 0) { + long longField = f.getLong(this); + sprint(longField); + } else if (fname.compareTo("boolean") == 0) { + boolean booleanField = f.getBoolean(this); + sprint(booleanField); + } else if (fname.compareTo("double") == 0) { + double doubleField = f.getDouble(this); + sprint(doubleField); + } else if (fname.compareTo("float") == 0) { + float floatField = f.getFloat(this); + sprint(floatField); + } + } else if (GenericObject.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObject) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else if ( + GenericObjectList.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObjectList) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else { + // Dont do recursion on things that are not + // of our header type... + if (f.get(this) != null) { + sprint(f.get(this).getClass().getName() + ":"); + } else { + sprint(fieldType.getName() + ":"); + } + + sprint("{"); + if (f.get(this) != null) { + sprint(f.get(this).toString()); + } else { + sprint("<null>"); + } + sprint("}"); + } + } catch (IllegalAccessException ex1) { + continue; // we are accessing a private field... + } + } + sprint("}"); + return stringRepresentation; + } + + + + + /** + * Formatter with a given starting indentation (for nested structs). + * @param indent int to set + * @return String + */ + public String debugDump(int indent) { + int save = indentation; + indentation = indent; + String retval = this.debugDump(); + indentation = save; + return retval; + } + + /** Encode this to a string. + * + *@return string representation for this object. + */ + public String toString() { + return this.encode(); + } +} diff --git a/java/gov/nist/javax/sip/address/NetObjectList.java b/java/gov/nist/javax/sip/address/NetObjectList.java new file mode 100644 index 0000000..9545cf2 --- /dev/null +++ b/java/gov/nist/javax/sip/address/NetObjectList.java @@ -0,0 +1,152 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.address; +import gov.nist.core.*; +import java.util.ListIterator; +import java.util.LinkedList; +import java.util.Iterator; +import java.lang.reflect.*; + +/** +* Root class for all the collection objects in this list: +* a wrapper class on the GenericObjectList class for lists of objects +* that can appear in NetObjects. +* IMPORTANT NOTE: NetObjectList cannot derive from NetObject as this +* will screw up the way in which we attach objects to headers. +* +*@version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:22 $ +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public class NetObjectList extends GenericObjectList { + + + /** + * + */ + private static final long serialVersionUID = -1551780600806959023L; + + /** + * Construct a NetObject List given a list name. + * @param lname String to set + */ + public NetObjectList(String lname) { + super(lname); + } + + /** + * Construct a NetObject List given a list name and a class for + * the objects that go into the list. + * @param lname String to set + * @param cname Class to set + */ + public NetObjectList(String lname, Class<?> cname) { + super(lname, cname); + } + + + + /** + * Construct an empty NetObjectList. + */ + public NetObjectList() { + super(); + } + + /** + * Add a new object to the list. + * @param obj NetObject to set + */ + public void add(NetObject obj) { + super.add(obj); + } + + /** concatenate the two Lists + * @param net_obj_list NetObjectList to set + */ + public void concatenate(NetObjectList net_obj_list) { + super.concatenate(net_obj_list); + } + + + + /** returns the first element + * @return GenericObject + */ + public GenericObject first() { + return (NetObject) super.first(); + } + + + + /** returns the next element + * @return GenericObject + */ + public GenericObject next() { + return (NetObject) super.next(); + } + + /** returns the next element + * @param li ListIterator to set + * @return GenericObject + */ + public GenericObject next(ListIterator li) { + return (NetObject) super.next(li); + } + + + + /** set the class + * @param cl Class to set + */ + public void setMyClass(Class cl) { + super.setMyClass(cl); + } + + /** + * Convert to a string given an indentation(for pretty printing). + * @param indent int to set + * @return String + */ + public String debugDump(int indent) { + return super.debugDump(indent); + } + + /** + * Encode this to a string. + * + *@return a string representation for this object. + */ + public String toString() { + return this.encode(); + } +} diff --git a/java/gov/nist/javax/sip/address/ParameterNames.java b/java/gov/nist/javax/sip/address/ParameterNames.java new file mode 100644 index 0000000..84eebbe --- /dev/null +++ b/java/gov/nist/javax/sip/address/ParameterNames.java @@ -0,0 +1,118 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; + +/** + * Common parameter names. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:22 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public interface ParameterNames { + public static final String SIP_URI_SCHEME = "sip"; + public static final String SIPS_URI_SCHEME = "sips"; + public static final String TEL_URI_SCHEME = "tel"; + public static final String POSTDIAL = "postdial"; + public static final String PHONE_CONTEXT_TAG = "context-tag"; + public static final String ISUB = "isub"; + public static final String PROVIDER_TAG = "provider-tag"; + public static final String UDP = GenericURI.UDP; + public static final String TCP = GenericURI.TCP; + public static final String TLS = GenericURI.TLS; +} +/* + * $Log: ParameterNames.java,v $ + * Revision 1.6 2009/07/17 18:57:22 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.5 2006/07/13 09:02:30 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:29 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:34 mranga + * + * Import + * + * + * Revision 1.3 2004/10/28 19:02:49 mranga + * Submitted by: Daniel Martinez + * Reviewed by: M. Ranganathan + * + * Added changes for TLS support contributed by Daniel Martinez + * + * Revision 1.2 2004/01/22 13:26:28 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/address/RFC2396UrlDecoder.java b/java/gov/nist/javax/sip/address/RFC2396UrlDecoder.java new file mode 100644 index 0000000..2ba6e46 --- /dev/null +++ b/java/gov/nist/javax/sip/address/RFC2396UrlDecoder.java @@ -0,0 +1,91 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; + +import java.io.UnsupportedEncodingException; + +/** + * Copied from Apache Excalibur project. + * Source code available at http://www.google.com/codesearch?hl=en&q=+excalibur+decodePath+show:sK_gDY0W5Rw:OTjCHAiSuF0:th3BdHtpX20&sa=N&cd=1&ct=rc&cs_p=http://apache.edgescape.com/excalibur/excalibur-sourceresolve/source/excalibur-sourceresolve-1.1-src.zip&cs_f=excalibur-sourceresolve-1.1/src/java/org/apache/excalibur/source/SourceUtil.java + * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A> + * + */ +public class RFC2396UrlDecoder { + + /** + * Decode a path. + * + * <p>Interprets %XX (where XX is hexadecimal number) as UTF-8 encoded bytes. + * <p>The validity of the input path is not checked (i.e. characters that + * were not encoded will not be reported as errors). + * <p>This method differs from URLDecoder.decode in that it always uses UTF-8 + * (while URLDecoder uses the platform default encoding, often ISO-8859-1), + * and doesn't translate + characters to spaces. + * + * @param uri the path to decode + * @return the decoded path + */ + public static String decode(String uri) { + StringBuffer translatedUri = new StringBuffer(uri.length()); + byte[] encodedchars = new byte[uri.length() / 3]; + int i = 0; + int length = uri.length(); + int encodedcharsLength = 0; + while (i < length) { + if (uri.charAt(i) == '%') { + //we must process all consecutive %-encoded characters in one go, because they represent + //an UTF-8 encoded string, and in UTF-8 one character can be encoded as multiple bytes + while (i < length && uri.charAt(i) == '%') { + if (i + 2 < length) { + try { + byte x = (byte)Integer.parseInt(uri.substring(i + 1, i + 3), 16); + encodedchars[encodedcharsLength] = x; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Illegal hex characters in pattern %" + uri.substring(i + 1, i + 3)); + } + encodedcharsLength++; + i += 3; + } else { + throw new IllegalArgumentException("% character should be followed by 2 hexadecimal characters."); + } + } + try { + String translatedPart = new String(encodedchars, 0, encodedcharsLength, "UTF-8"); + translatedUri.append(translatedPart); + } catch (UnsupportedEncodingException e) { + //the situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception + throw new RuntimeException("Problem in decodePath: UTF-8 encoding not supported."); + } + encodedcharsLength = 0; + } else { + //a normal character + translatedUri.append(uri.charAt(i)); + i++; + } + } + return translatedUri.toString(); + } +}
\ No newline at end of file diff --git a/java/gov/nist/javax/sip/address/RouterExt.java b/java/gov/nist/javax/sip/address/RouterExt.java new file mode 100644 index 0000000..60ecfa0 --- /dev/null +++ b/java/gov/nist/javax/sip/address/RouterExt.java @@ -0,0 +1,42 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* +*/ + +package gov.nist.javax.sip.address; + +import javax.sip.address.Hop; +import javax.sip.address.Router; + +/** + * + */ +public interface RouterExt extends Router { + + /** + * Record that a transaction failure occured for the given hop. + * + */ + public void transactionTimeout(Hop hop); + +} diff --git a/java/gov/nist/javax/sip/address/SipURIExt.java b/java/gov/nist/javax/sip/address/SipURIExt.java new file mode 100644 index 0000000..dc75a27 --- /dev/null +++ b/java/gov/nist/javax/sip/address/SipURIExt.java @@ -0,0 +1,47 @@ +package gov.nist.javax.sip.address; + +import javax.sip.address.SipURI; + +/** + * URI Interface extensions that will be added to version 2.0 of the JSR 32 spec. + * + * @author mranga + * + * @since 2.0 + * + */ +public interface SipURIExt extends SipURI { + + /** + * Strip the headers that are tacked to the URI. + * + * @since 2.0 + */ + public void removeHeaders(); + + /** + * Strip a specific header tacked to the URI. + * + * @param headerName -- the name of the header. + * + * @since 2.0 + */ + public void removeHeader(String headerName); + + /** + * Returns whether the <code>gr</code> parameter is set. + * + * @since 2.0 + */ + public boolean hasGrParam(); + + /** + * Sets the <code>gr</code> parameter. + * + * @param value -- the GRUU param value. + * + * @since 2.0 + */ + public void setGrParam(String value); + +} diff --git a/java/gov/nist/javax/sip/address/SipUri.java b/java/gov/nist/javax/sip/address/SipUri.java new file mode 100644 index 0000000..4ab16fc --- /dev/null +++ b/java/gov/nist/javax/sip/address/SipUri.java @@ -0,0 +1,1058 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.address; + +/* + *Bug fix contributions + *Daniel J. Martinez Manzano <dani@dif.um.es> + *Stefan Marx. + *pmusgrave@newheights.com (Additions for gruu and outbound drafts) + *Jeroen van Bemmel ( additions for SCTP transport ) + */ +import gov.nist.core.*; +import java.util.*; +import java.text.ParseException; + +import javax.sip.PeerUnavailableException; +import javax.sip.SipFactory; +import javax.sip.address.SipURI; +import javax.sip.header.Header; +import javax.sip.header.HeaderFactory; + + +/** + * Implementation of the SipURI interface. + * + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.22 $ $Date: 2009/11/15 19:50:45 $ + * + * + * + */ +public class SipUri extends GenericURI implements javax.sip.address.SipURI , SipURIExt{ + + + private static final long serialVersionUID = 7749781076218987044L; + + /** Authority for the uri. + */ + + protected Authority authority; + + /** uriParms list + */ + protected NameValueList uriParms; + + /** qheaders list + */ + protected NameValueList qheaders; + + /** telephoneSubscriber field + */ + protected TelephoneNumber telephoneSubscriber; + + public SipUri() { + this.scheme = SIP; + this.uriParms = new NameValueList(); + this.qheaders = new NameValueList(); + this.qheaders.setSeparator("&"); + } + + /** Constructor given the scheme. + * The scheme must be either Sip or Sips + */ + public void setScheme(String scheme) { + if (scheme.compareToIgnoreCase(SIP) != 0 + && scheme.compareToIgnoreCase(SIPS) != 0) + throw new IllegalArgumentException("bad scheme " + scheme); + this.scheme = scheme.toLowerCase(); + } + + /** Get the scheme. + */ + public String getScheme() { + return scheme; + } + + /** + * clear all URI Parameters. + * @since v1.0 + */ + public void clearUriParms() { + uriParms = new NameValueList(); + } + /** + *Clear the password from the user part if it exists. + */ + public void clearPassword() { + if (this.authority != null) { + UserInfo userInfo = authority.getUserInfo(); + if (userInfo != null) + userInfo.clearPassword(); + } + } + + /** Get the authority. + */ + public Authority getAuthority() { + return this.authority; + } + + /** + * Clear all Qheaders. + */ + public void clearQheaders() { + qheaders = new NameValueList(); + } + + /** + * Compare two URIs and return true if they are equal. + * @param that the object to compare to. + * @return true if the object is equal to this object. + * + * JvB: Updated to define equality in terms of API methods, according to the rules + * in RFC3261 section 19.1.4 + * + * Jean Deruelle: Updated to define equality of API methods, according to the rules + * in RFC3261 section 19.1.4 convert potential ie : + * %HEX HEX encoding parts of the URI before comparing them + * transport param added in comparison + * header equality enforced in comparison + * + */ + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object that) { + + // Shortcut for same object + if (that==this) return true; + + if (that instanceof SipURI) { + final SipURI a = this; + final SipURI b = (SipURI) that; + + // A SIP and SIPS URI are never equivalent + if ( a.isSecure() ^ b.isSecure() ) return false; + + // For two URIs to be equal, the user, password, host, and port + // components must match; comparison of userinfo is case-sensitive + if (a.getUser()==null ^ b.getUser()==null) return false; + if (a.getUserPassword()==null ^ b.getUserPassword()==null) return false; + + if (a.getUser()!=null && !RFC2396UrlDecoder.decode(a.getUser()).equals(RFC2396UrlDecoder.decode(b.getUser()))) return false; + if (a.getUserPassword()!=null && !RFC2396UrlDecoder.decode(a.getUserPassword()).equals(RFC2396UrlDecoder.decode(b.getUserPassword()))) return false; + if (a.getHost() == null ^ b.getHost() == null) return false; + if (a.getHost() != null && !a.getHost().equalsIgnoreCase(b.getHost())) return false; + if (a.getPort() != b.getPort()) return false; + + // URI parameters + for (Iterator i = a.getParameterNames(); i.hasNext();) { + String pname = (String) i.next(); + + String p1 = a.getParameter(pname); + String p2 = b.getParameter(pname); + + // those present in both must match (case-insensitive) + if (p1!=null && p2!=null && !RFC2396UrlDecoder.decode(p1).equalsIgnoreCase(RFC2396UrlDecoder.decode(p2))) return false; + } + + // transport, user, ttl or method must match when present in either + if (a.getTransportParam()==null ^ b.getTransportParam()==null) return false; + if (a.getUserParam()==null ^ b.getUserParam()==null) return false; + if (a.getTTLParam()==-1 ^ b.getTTLParam()==-1) return false; + if (a.getMethodParam()==null ^ b.getMethodParam()==null) return false; + if (a.getMAddrParam()==null ^ b.getMAddrParam()==null) return false; + + // Headers: must match according to their definition. + if(a.getHeaderNames().hasNext() && !b.getHeaderNames().hasNext()) return false; + if(!a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) return false; + + if(a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) { + HeaderFactory headerFactory = null; + try { + headerFactory = SipFactory.getInstance().createHeaderFactory(); + } catch (PeerUnavailableException e) { + Debug.logError("Cannot get the header factory to parse the header of the sip uris to compare", e); + return false; + } + for (Iterator i = a.getHeaderNames(); i.hasNext();) { + String hname = (String) i.next(); + + String h1 = a.getHeader(hname); + String h2 = b.getHeader(hname); + + if(h1 == null && h2 != null) return false; + if(h2 == null && h1 != null) return false; + // The following check should not be needed but we add it for findbugs. + if(h1 == null && h2 == null) continue; + try { + Header header1 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h1)); + Header header2 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h2)); + // those present in both must match according to the equals method of the corresponding header + if (!header1.equals(header2)) return false; + } catch (ParseException e) { + Debug.logError("Cannot parse one of the header of the sip uris to compare " + a + " " + b, e); + return false; + } + } + } + + // Finally, we can conclude that they are indeed equal + return true; + } + return false; + } + + /** + * Construct a URL from the parsed structure. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + buffer.append(scheme).append(COLON); + if (authority != null) + authority.encode(buffer); + if (!uriParms.isEmpty()) { + buffer.append(SEMICOLON); + uriParms.encode(buffer); + } + if (!qheaders.isEmpty()) { + buffer.append(QUESTION); + qheaders.encode(buffer); + } + return buffer; + } + + /** Return a string representation. + * + *@return the String representation of this URI. + * + */ + public String toString() { + return this.encode(); + } + + /** + * getUser@host + * @return user@host portion of the uri (null if none exists). + * + * Peter Musgrave - handle null user + */ + public String getUserAtHost() { + String user = ""; + if (authority.getUserInfo() != null) + user = authority.getUserInfo().getUser(); + + String host = authority.getHost().encode(); + StringBuffer s = null; + if (user.equals("")) { + s = new StringBuffer(); + } else { + s = new StringBuffer(user).append(AT); + } + return s.append(host).toString(); + } + + /** + * getUser@host + * @return user@host portion of the uri (null if none exists). + */ + public String getUserAtHostPort() { + String user = ""; + if (authority.getUserInfo() != null) + user = authority.getUserInfo().getUser(); + + String host = authority.getHost().encode(); + int port = authority.getPort(); + // If port not set assign the default. + StringBuffer s = null; + if (user.equals("")) { + s = new StringBuffer(); + } else { + s = new StringBuffer(user).append(AT); + } + if (port != -1) { + return s.append(host).append(COLON).append(port).toString(); + } else + return s.append(host).toString(); + + } + + /** + * get the parameter (do a name lookup) and return null if none exists. + * @param parmname Name of the parameter to get. + * @return Parameter of the given name (null if none exists). + */ + public Object getParm(String parmname) { + Object obj = uriParms.getValue(parmname); + return obj; + } + + /** + * Get the method parameter. + * @return Method parameter. + */ + public String getMethod() { + return (String) getParm(METHOD); + } + + /** + * Accessor for URI parameters + * @return A name-value list containing the parameters. + */ + public NameValueList getParameters() { + return uriParms; + } + + /** Remove the URI parameters. + * + */ + public void removeParameters() { + this.uriParms = new NameValueList(); + } + + /** + * Accessor forSIPObjects + * @return Get the query headers (that appear after the ? in + * the URL) + */ + public NameValueList getQheaders() { + return qheaders; + } + + /** + * Get the urse parameter. + * @return User parameter (user= phone or user=ip). + */ + public String getUserType() { + return (String) uriParms.getValue(USER); + } + + /** + * Get the password of the user. + * @return User password when it embedded as part of the uri + * ( a very bad idea). + */ + public String getUserPassword() { + if (authority == null) + return null; + return authority.getPassword(); + } + + /** Set the user password. + *@param password - password to set. + */ + public void setUserPassword(String password) { + if (this.authority == null) + this.authority = new Authority(); + authority.setPassword(password); + } + + /** + * Returns the stucture corresponding to the telephone number + * provided that the user is a telephone subscriber. + * @return TelephoneNumber part of the url (only makes sense + * when user = phone is specified) + */ + public TelephoneNumber getTelephoneSubscriber() { + if (telephoneSubscriber == null) { + + telephoneSubscriber = new TelephoneNumber(); + } + return telephoneSubscriber; + } + + /** + * Get the host and port of the server. + * @return get the host:port part of the url parsed into a + * structure. + */ + public HostPort getHostPort() { + + if (authority == null || authority.getHost() == null ) + return null; + else { + return authority.getHostPort(); + } + } + + /** Get the port from the authority field. + * + *@return the port from the authority field. + */ + public int getPort() { + HostPort hp = this.getHostPort(); + if (hp == null) + return -1; + return hp.getPort(); + } + + /** Get the host protion of the URI. + * @return the host portion of the url. + */ + public String getHost() { + if ( authority == null) return null; + else if (authority.getHost() == null ) return null; + else return authority.getHost().encode(); + } + + /** + * returns true if the user is a telephone subscriber. + * If the host is an Internet telephony + * gateway, a telephone-subscriber field MAY be used instead + * of a user field. The telephone-subscriber field uses the + * notation of RFC 2806 [19]. Any characters of the un-escaped + * "telephone-subscriber" that are not either in the set + * "unreserved" or "user-unreserved" MUST be escaped. The set + * of characters not reserved in the RFC 2806 description of + * telephone-subscriber contains a number of characters in + * various syntax elements that need to be escaped when used + * in SIP URLs, for example quotation marks (%22), hash (%23), + * colon (%3a), at-sign (%40) and the "unwise" characters, + * i.e., punctuation of %5b and above. + * + * The telephone number is a special case of a user name and + * cannot be distinguished by a BNF. Thus, a URL parameter, + * user, is added to distinguish telephone numbers from user + * names. + * + * The user parameter value "phone" indicates that the user + * part contains a telephone number. Even without this + * parameter, recipients of SIP URLs MAY interpret the pre-@ + * part as a telephone number if local restrictions on the + * @return true if the user is a telephone subscriber. + */ + public boolean isUserTelephoneSubscriber() { + String usrtype = (String) uriParms.getValue(USER); + if (usrtype == null) + return false; + return usrtype.equalsIgnoreCase(PHONE); + } + + /** + *remove the ttl value from the parameter list if it exists. + */ + public void removeTTL() { + if (uriParms != null) + uriParms.delete(TTL); + } + + /** + *Remove the maddr param if it exists. + */ + public void removeMAddr() { + if (uriParms != null) + uriParms.delete(MADDR); + } + + /** + *Delete the transport string. + */ + public void removeTransport() { + if (uriParms != null) + uriParms.delete(TRANSPORT); + } + + /** Remove a header given its name (provided it exists). + * @param name name of the header to remove. + */ + public void removeHeader(String name) { + if (qheaders != null) + qheaders.delete(name); + } + + /** Remove all headers. + */ + public void removeHeaders() { + qheaders = new NameValueList(); + } + + /** + * Set the user type. + */ + public void removeUserType() { + if (uriParms != null) + uriParms.delete(USER); + } + + /** + *remove the port setting. + */ + public void removePort() { + authority.removePort(); + } + + /** + * remove the Method. + */ + public void removeMethod() { + if (uriParms != null) + uriParms.delete(METHOD); + } + + /** Sets the user of SipURI. The identifier of a particular resource at + * the host being addressed. The user and the user password including the + * "at" sign make up the user-info. + * + * @param uname The new String value of the user. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the user value. + */ + public void setUser(String uname) { + if (this.authority == null) { + this.authority = new Authority(); + } + + this.authority.setUser(uname); + } + + /** Remove the user. + */ + public void removeUser() { + this.authority.removeUserInfo(); + } + + /** Set the default parameters for this URI. + * Do nothing if the parameter is already set to some value. + * Otherwise set it to the given value. + * @param name Name of the parameter to set. + * @param value value of the parameter to set. + */ + public void setDefaultParm(String name, Object value) { + if (uriParms.getValue(name) == null) { + NameValue nv = new NameValue(name, value); + uriParms.set(nv); + } + } + + /** Set the authority member + * @param authority Authority to set. + */ + public void setAuthority(Authority authority) { + this.authority = authority; + } + + /** Set the host for this URI. + * @param h host to set. + */ + public void setHost(Host h) { + if (this.authority == null) + this.authority = new Authority(); + this.authority.setHost(h); + } + + /** Set the uriParms member + * @param parms URI parameters to set. + */ + public void setUriParms(NameValueList parms) { + uriParms = parms; + } + + /** + * Set a given URI parameter. Note - parameter must be properly + * encoded before the function is called. + * @param name Name of the parameter to set. + * @param value value of the parameter to set. + */ + public void setUriParm(String name, Object value) { + NameValue nv = new NameValue(name, value); + uriParms.set(nv); + } + + /** Set the qheaders member + * @param parms query headers to set. + */ + public void setQheaders(NameValueList parms) { + qheaders = parms; + } + + /** + * Set the MADDR parameter . + * @param mAddr Host Name to set + */ + public void setMAddr(String mAddr) { + NameValue nameValue = uriParms.getNameValue(MADDR); + Host host = new Host(); + host.setAddress(mAddr); + if (nameValue != null) + nameValue.setValueAsObject(host); + else { + nameValue = new NameValue(MADDR, host); + uriParms.set(nameValue); + } + } + + /** Sets the value of the user parameter. The user URI parameter exists to + * distinguish telephone numbers from user names that happen to look like + * telephone numbers. This is equivalent to setParameter("user", user). + * + * @param usertype New value String value of the method parameter + */ + public void setUserParam(String usertype) { + uriParms.set(USER, usertype); + } + + /** + * Set the Method + * @param method method parameter + */ + public void setMethod(String method) { + uriParms.set(METHOD, method); + } + + /** + * Sets ISDN subaddress of SipURL + * @param isdnSubAddress ISDN subaddress + */ + public void setIsdnSubAddress(String isdnSubAddress) { + if (telephoneSubscriber == null) + telephoneSubscriber = new TelephoneNumber(); + telephoneSubscriber.setIsdnSubaddress(isdnSubAddress); + } + + /** + * Set the telephone subscriber field. + * @param tel Telephone subscriber field to set. + */ + public void setTelephoneSubscriber(TelephoneNumber tel) { + telephoneSubscriber = tel; + } + + /** set the port to a given value. + * @param p Port to set. + */ + public void setPort(int p) { + if (authority == null) + authority = new Authority(); + authority.setPort(p); + } + + /** + * Boolean to check if a parameter of a given name exists. + * @param name Name of the parameter to check on. + * @return a boolean indicating whether the parameter exists. + */ + public boolean hasParameter(String name) { + + return uriParms.getValue(name) != null; + } + + /** + * Set the query header when provided as a name-value pair. + * @param nameValue qeuery header provided as a name,value pair. + */ + public void setQHeader(NameValue nameValue) { + this.qheaders.set(nameValue); + } + + /** Set the parameter as given. + *@param nameValue - parameter to set. + */ + public void setUriParameter(NameValue nameValue) { + this.uriParms.set(nameValue); + } + + /** Return true if the transport parameter is defined. + * @return true if transport appears as a parameter and false otherwise. + */ + public boolean hasTransport() { + return hasParameter(TRANSPORT); + } + + /** + * Remove a parameter given its name + * @param name -- name of the parameter to remove. + */ + public void removeParameter(String name) { + uriParms.delete(name); + } + + /** Set the hostPort field of the imbedded authority field. + *@param hostPort is the hostPort to set. + */ + public void setHostPort(HostPort hostPort) { + if (this.authority == null) { + this.authority = new Authority(); + } + authority.setHostPort(hostPort); + } + + /** clone this. + */ + public Object clone() { + SipUri retval = (SipUri) super.clone(); + if (this.authority != null) + retval.authority = (Authority) this.authority.clone(); + if (this.uriParms != null) + retval.uriParms = (NameValueList) this.uriParms.clone(); + if (this.qheaders != null) + retval.qheaders = (NameValueList) this.qheaders.clone(); + if (this.telephoneSubscriber != null) + retval.telephoneSubscriber = (TelephoneNumber) this.telephoneSubscriber.clone(); + return retval; + } + + /** + * Returns the value of the named header, or null if it is not set. + * SIP/SIPS URIs may specify headers. As an example, the URI + * sip:joe@jcp.org?priority=urgent has a header "priority" whose + * value is "urgent". + * + * @param name name of header to retrieve + * @return the value of specified header + */ + public String getHeader(String name) { + return this.qheaders.getValue(name) != null + ? this.qheaders.getValue(name).toString() + : null; + + } + + /** + * Returns an Iterator over the names (Strings) of all headers present + * in this SipURI. + * + * @return an Iterator over all the header names + */ + public Iterator<String> getHeaderNames() { + return this.qheaders.getNames(); + + } + + /** Returns the value of the <code>lr</code> parameter, or null if this + * is not set. This is equivalent to getParameter("lr"). + * + * @return the value of the <code>lr</code> parameter + */ + public String getLrParam() { + boolean haslr = this.hasParameter(LR); + return haslr ? "true" : null; + } + + /** Returns the value of the <code>maddr</code> parameter, or null if this + * is not set. This is equivalent to getParameter("maddr"). + * + * @return the value of the <code>maddr</code> parameter + */ + public String getMAddrParam() { + NameValue maddr = uriParms.getNameValue(MADDR); + if (maddr == null) + return null; + String host = (String) maddr.getValueAsObject(); + return host; + } + + /** + * Returns the value of the <code>method</code> parameter, or null if this + * is not set. This is equivalent to getParameter("method"). + * + * @return the value of the <code>method</code> parameter + */ + public String getMethodParam() { + return this.getParameter(METHOD); + } + + /** + * Returns the value of the named parameter, or null if it is not set. A + * zero-length String indicates flag parameter. + * + * @param name name of parameter to retrieve + * @return the value of specified parameter + */ + public String getParameter(String name) { + Object val = uriParms.getValue(name); + if (val == null) + return null; + if (val instanceof GenericObject) + return ((GenericObject) val).encode(); + else + return val.toString(); + } + + /** + * Returns an Iterator over the names (Strings) of all parameters present + * + * in this ParametersHeader. + * + * + * + * @return an Iterator over all the parameter names + * + */ + public Iterator<String> getParameterNames() { + return this.uriParms.getNames(); + } + + /** Returns the value of the "ttl" parameter, or -1 if this is not set. + * This method is equivalent to getParameter("ttl"). + * + * @return the value of the <code>ttl</code> parameter + */ + public int getTTLParam() { + Integer ttl = (Integer) uriParms.getValue("ttl"); + if (ttl != null) + return ttl.intValue(); + else + return -1; + } + + /** Returns the value of the "transport" parameter, or null if this is not + * set. This is equivalent to getParameter("transport"). + * + * @return the transport paramter of the SipURI + */ + public String getTransportParam() { + if (uriParms != null) { + return (String) uriParms.getValue(TRANSPORT); + } else + return null; + } + + /** Returns the value of the <code>userParam</code>, + *or null if this is not set. + * <p> + * This is equivalent to getParameter("user"). + * + * @return the value of the <code>userParam</code> of the SipURI + */ + public String getUser() { + return authority.getUser(); + } + + /** Returns true if this SipURI is secure i.e. if this SipURI represents a + * sips URI. A sip URI returns false. + * + * @return <code>true</code> if this SipURI represents a sips URI, and + * <code>false</code> if it represents a sip URI. + */ + public boolean isSecure() { + return this.getScheme().equalsIgnoreCase(SIPS); + } + + /** This method determines if this is a URI with a scheme of "sip" or "sips". + * + * @return true if the scheme is "sip" or "sips", false otherwise. + */ + public boolean isSipURI() { + return true; + } + + /** Sets the value of the specified header fields to be included in a + * request constructed from the URI. If the header already had a value it + * will be overwritten. + * + * @param name - a String specifying the header name + * @param value - a String specifying the header value + */ + public void setHeader(String name, String value) { + NameValue nv = new NameValue(name, value); + qheaders.set(nv); + + } + + /** + * Set the host portion of the SipURI + * + * @param host host to set. + */ + public void setHost(String host) throws ParseException { + Host h = new Host(host); + this.setHost(h); + } + + /** Sets the value of the <code>lr</code> parameter of this SipURI. The lr + * parameter, when present, indicates that the element responsible for + * this resource implements the routing mechanisms specified in RFC 3261. + * This parameter will be used in the URIs proxies place in the + * Record-Route header field values, and may appear in the URIs in a + * pre-existing route set. + */ + public void setLrParam() { + this.uriParms.set("lr",null); // JvB: fixed to not add duplicates + } + + /** + * Sets the value of the <code>maddr</code> parameter of this SipURI. The + * maddr parameter indicates the server address to be contacted for this + * user, overriding any address derived from the host field. This is + * equivalent to setParameter("maddr", maddr). + * + * @param maddr New value of the <code>maddr</code> parameter + */ + public void setMAddrParam(String maddr) throws ParseException { + if (maddr == null) + throw new NullPointerException("bad maddr"); + setParameter("maddr", maddr); + } + + /** Sets the value of the <code>method</code> parameter. This specifies + * which SIP method to use in requests directed at this URI. This is + * equivalent to setParameter("method", method). + * + * @param method - new value String value of the method parameter + */ + public void setMethodParam(String method) throws ParseException { + setParameter("method", method); + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. A zero-length String indicates flag + * + * parameter. + * + * + * + * @param name - a String specifying the parameter name + * + * @param value - a String specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + public void setParameter(String name, String value) throws ParseException { + if (name.equalsIgnoreCase("ttl")) { + try { + Integer.parseInt(value); + } catch (NumberFormatException ex) { + throw new ParseException("bad parameter " + value, 0); + } + } + uriParms.set(name,value); + } + + /** Sets the scheme of this URI to sip or sips depending on whether the + * argument is true or false. The default value is false. + * + * @param secure - the boolean value indicating if the SipURI is secure. + */ + public void setSecure(boolean secure) { + if (secure) + this.scheme = SIPS; + else + this.scheme = SIP; + } + + /** Sets the value of the <code>ttl</code> parameter. The ttl parameter + * specifies the time-to-live value when packets are sent using UDP + * multicast. This is equivalent to setParameter("ttl", ttl). + * + * @param ttl - new value of the <code>ttl</code> parameter + */ + public void setTTLParam(int ttl) { + if (ttl <= 0) + throw new IllegalArgumentException("Bad ttl value"); + if (uriParms != null) { + NameValue nv = new NameValue("ttl", Integer.valueOf(ttl)); + uriParms.set(nv); + } + } + + /** Sets the value of the "transport" parameter. This parameter specifies + * which transport protocol to use for sending requests and responses to + * this entity. The following values are defined: "udp", "tcp", "sctp", + * "tls", but other values may be used also. This method is equivalent to + * setParameter("transport", transport). Transport parameter constants + * are defined in the {@link javax.sip.ListeningPoint}. + * + * @param transport - new value for the "transport" parameter + * @see javax.sip.ListeningPoint + */ + public void setTransportParam(String transport) throws ParseException { + if (transport == null) + throw new NullPointerException("null arg"); + if (transport.compareToIgnoreCase("UDP") == 0 + || transport.compareToIgnoreCase("TLS") == 0 + || transport.compareToIgnoreCase("TCP") == 0 + || transport.compareToIgnoreCase("SCTP") == 0) { + NameValue nv = new NameValue(TRANSPORT, transport.toLowerCase()); + uriParms.set(nv); + } else + throw new ParseException("bad transport " + transport, 0); + } + + /** Returns the user part of this SipURI, or null if it is not set. + * + * @return the user part of this SipURI + */ + public String getUserParam() { + return getParameter("user"); + + } + + /** Returns whether the the <code>lr</code> parameter is set. This is + * equivalent to hasParameter("lr"). This interface has no getLrParam as + * RFC3261 does not specify any values for the "lr" paramater. + * + * @return true if the "lr" parameter is set, false otherwise. + */ + public boolean hasLrParam() { + return uriParms.getNameValue("lr") != null; + } + + + /** + * Returns whether the <code>gr</code> parameter is set. + * + * Not part on the interface since gruu is not part of the base RFC3261. + */ + public boolean hasGrParam() { + return uriParms.getNameValue(GRUU) != null; + } + + /** + * Sets the <code>gr</code> parameter. + * + * Not part on the interface since gruu is not part of the base RFC3261. + */ + public void setGrParam(String value) { + this.uriParms.set(GRUU, value); // JvB: fixed to not add duplicates + } + + /** + * Sets the <code>gr</code> parameter. + * + * Not part on the interface since gruu is not part of the base RFC3261. + */ + public String getGrParam() { + return (String) this.uriParms.getValue(GRUU); // JvB: fixed to not add duplicates + } + + /** + *remove the +sip-instance value from the parameter list if it exists. + */ + +} diff --git a/java/gov/nist/javax/sip/address/TelURLImpl.java b/java/gov/nist/javax/sip/address/TelURLImpl.java new file mode 100644 index 0000000..62a6179 --- /dev/null +++ b/java/gov/nist/javax/sip/address/TelURLImpl.java @@ -0,0 +1,222 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; + +import gov.nist.core.NameValueList; + +import java.text.ParseException; +import java.util.Iterator; + +/** + * Implementation of the TelURL interface. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/15 19:50:45 $ + * + * @author M. Ranganathan + * + */ +public class TelURLImpl + extends GenericURI + implements javax.sip.address.TelURL { + + + private static final long serialVersionUID = 5873527320305915954L; + + protected TelephoneNumber telephoneNumber; + + /** Creates a new instance of TelURLImpl */ + public TelURLImpl() { + this.scheme = "tel"; + } + + /** Set the telephone number. + *@param telephoneNumber -- telephone number to set. + */ + + public void setTelephoneNumber(TelephoneNumber telephoneNumber) { + this.telephoneNumber = telephoneNumber; + } + + /** Returns the value of the <code>isdnSubAddress</code> parameter, or null + * if it is not set. + * + * @return the value of the <code>isdnSubAddress</code> parameter + */ + public String getIsdnSubAddress() { + return telephoneNumber.getIsdnSubaddress(); + } + + /** Returns the value of the <code>postDial</code> parameter, or null if it + * is not set. + * + * @return the value of the <code>postDial</code> parameter + */ + public String getPostDial() { + return telephoneNumber.getPostDial(); + } + + /** Returns the value of the "scheme" of this URI, for example "sip", "sips" + * or "tel". + * + * @return the scheme paramter of the URI + */ + public String getScheme() { + return this.scheme; + } + + /** Returns <code>true</code> if this TelURL is global i.e. if the TelURI + * has a global phone user. + * + * @return <code>true</code> if this TelURL represents a global phone user, + * and <code>false</code> otherwise. + */ + public boolean isGlobal() { + return telephoneNumber.isGlobal(); + } + + /** This method determines if this is a URI with a scheme of "sip" or "sips". + * + * @return true if the scheme is "sip" or "sips", false otherwise. + */ + public boolean isSipURI() { + return false; + } + + /** Sets phone user of this TelURL to be either global or local. The default + * value is false, hence the TelURL is defaulted to local. + * + * @param global - the boolean value indicating if the TelURL has a global + * phone user. + */ + public void setGlobal(boolean global) { + this.telephoneNumber.setGlobal(global); + } + + /** Sets ISDN subaddress of this TelURL. If a subaddress is present, it is + * appended to the phone number after ";isub=". + * + * @param isdnSubAddress - new value of the <code>isdnSubAddress</code> + * parameter + */ + public void setIsdnSubAddress(String isdnSubAddress) { + this.telephoneNumber.setIsdnSubaddress(isdnSubAddress); + } + + /** Sets post dial of this TelURL. The post-dial sequence describes what and + * when the local entity should send to the phone line. + * + * @param postDial - new value of the <code>postDial</code> parameter + */ + public void setPostDial(String postDial) { + this.telephoneNumber.setPostDial(postDial); + } + + /** + * Set the telephone number. + * @param telephoneNumber long phone number to set. + */ + public void setPhoneNumber(String telephoneNumber) { + this.telephoneNumber.setPhoneNumber(telephoneNumber); + } + + /** Get the telephone number. + * + *@return -- the telephone number. + */ + public String getPhoneNumber() { + return this.telephoneNumber.getPhoneNumber(); + } + + /** Return the string encoding. + * + *@return -- the string encoding. + */ + public String toString() { + return this.scheme + ":" + telephoneNumber.encode(); + } + + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + buffer.append(this.scheme).append(':'); + telephoneNumber.encode(buffer); + return buffer; + } + + /** Deep copy clone operation. + * + *@return -- a cloned version of this telephone number. + */ + public Object clone() { + TelURLImpl retval = (TelURLImpl) super.clone(); + if (this.telephoneNumber != null) + retval.telephoneNumber = (TelephoneNumber) this.telephoneNumber.clone(); + return retval; + } + + public String getParameter(String parameterName) { + return telephoneNumber.getParameter(parameterName); + } + + public void setParameter(String name, String value) { + telephoneNumber.setParameter(name, value); + } + + public Iterator<String> getParameterNames() { + return telephoneNumber.getParameterNames(); + } + + public NameValueList getParameters() { + return telephoneNumber.getParameters(); + } + + public void removeParameter(String name) { + telephoneNumber.removeParameter(name); + } + + /* (non-Javadoc) + * @see javax.sip.address.TelURL#setPhoneContext(java.lang.String) + */ + public void setPhoneContext(String phoneContext) throws ParseException { + + // JvB: set (null) should be interpreted as 'remove' + if (phoneContext==null) { + this.removeParameter("phone-context"); + } else { + this.setParameter("phone-context",phoneContext); + } + } + + /* (non-Javadoc) + * @see javax.sip.address.TelURL#getPhoneContext() + */ + public String getPhoneContext() { + + return this.getParameter("phone-context"); + } +} diff --git a/java/gov/nist/javax/sip/address/TelephoneNumber.java b/java/gov/nist/javax/sip/address/TelephoneNumber.java new file mode 100644 index 0000000..d5df96d --- /dev/null +++ b/java/gov/nist/javax/sip/address/TelephoneNumber.java @@ -0,0 +1,248 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.address; + +import gov.nist.core.*; + +import java.util.Iterator; + +/** + * Telephone number class. + * @version 1.2 + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:23 $ + * + * @author M. Ranganathan + * + */ +public class TelephoneNumber extends NetObject { + public static final String POSTDIAL = ParameterNames.POSTDIAL; + public static final String PHONE_CONTEXT_TAG = + ParameterNames.PHONE_CONTEXT_TAG; + public static final String ISUB = ParameterNames.ISUB; + public static final String PROVIDER_TAG = ParameterNames.PROVIDER_TAG; + + /** isglobal field + */ + protected boolean isglobal; + + /** phoneNumber field + */ + protected String phoneNumber; + + /** parmeters list + */ + protected NameValueList parameters; + + /** Creates new TelephoneNumber */ + public TelephoneNumber() { + parameters = new NameValueList(); + } + + /** delete the specified parameter. + * @param name String to set + */ + public void deleteParm(String name) { + parameters.delete(name); + } + + /** get the PhoneNumber field + * @return String + */ + public String getPhoneNumber() { + return phoneNumber; + } + + /** get the PostDial field + * @return String + */ + public String getPostDial() { + return (String) parameters.getValue(POSTDIAL); + } + + /** + * Get the isdn subaddress for this number. + * @return String + */ + public String getIsdnSubaddress() { + return (String) parameters.getValue(ISUB); + } + + /** returns true if th PostDial field exists + * @return boolean + */ + public boolean hasPostDial() { + return parameters.getValue(POSTDIAL) != null; + } + + /** return true if this header has parameters. + * @param pname String to set + * @return boolean + */ + public boolean hasParm(String pname) { + return parameters.hasNameValue(pname); + } + + /** + * return true if the isdn subaddress exists. + * @return boolean + */ + public boolean hasIsdnSubaddress() { + return hasParm(ISUB); + } + + /** + * is a global telephone number. + * @return boolean + */ + public boolean isGlobal() { + return isglobal; + } + + /** remove the PostDial field + */ + public void removePostDial() { + parameters.delete(POSTDIAL); + } + + /** + * Remove the isdn subaddress (if it exists). + */ + public void removeIsdnSubaddress() { + deleteParm(ISUB); + } + + /** + * Set the list of parameters. + * @param p NameValueList to set + */ + public void setParameters(NameValueList p) { + parameters = p; + } + + /** set the Global field + * @param g boolean to set + */ + public void setGlobal(boolean g) { + isglobal = g; + } + + /** set the PostDial field + * @param p String to set + */ + public void setPostDial(String p) { + NameValue nv = new NameValue(POSTDIAL, p); + parameters.set(nv); + } + + /** set the specified parameter + * @param name String to set + * @param value Object to set + */ + public void setParm(String name, Object value) { + NameValue nv = new NameValue(name, value); + parameters.set(nv); + } + + /** + * set the isdn subaddress for this structure. + * @param isub String to set + */ + public void setIsdnSubaddress(String isub) { + setParm(ISUB, isub); + } + + /** set the PhoneNumber field + * @param num String to set + */ + public void setPhoneNumber(String num) { + phoneNumber = num; + } + + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (isglobal) + buffer.append('+'); + buffer.append(phoneNumber); + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + return buffer; + } + + /** + * Returns the value of the named parameter, or null if it is not set. A + * zero-length String indicates flag parameter. + * + * @param name name of parameter to retrieve + * + * @return the value of specified parameter + * + */ + public String getParameter(String name) { + Object val = parameters.getValue(name); + if (val == null) + return null; + if (val instanceof GenericObject) + return ((GenericObject) val).encode(); + else + return val.toString(); + } + + /** + * + * Returns an Iterator over the names (Strings) of all parameters. + * + * @return an Iterator over all the parameter names + * + */ + public Iterator<String> getParameterNames() { + return this.parameters.getNames(); + } + + public void removeParameter(String parameter) { + this.parameters.delete(parameter); + } + + public void setParameter(String name, String value) { + NameValue nv = new NameValue(name, value); + this.parameters.set(nv); + } + + public Object clone() { + TelephoneNumber retval = (TelephoneNumber) super.clone(); + if (this.parameters != null) + retval.parameters = (NameValueList) this.parameters.clone(); + return retval; + } + + public NameValueList getParameters() { + return this.parameters; + } +} diff --git a/java/gov/nist/javax/sip/address/UserInfo.java b/java/gov/nist/javax/sip/address/UserInfo.java new file mode 100644 index 0000000..0b558ee --- /dev/null +++ b/java/gov/nist/javax/sip/address/UserInfo.java @@ -0,0 +1,183 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * Acknowledgement -- Lamine Brahimi + * Submitted a bug fix for a this class. + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.address; + +/** + * User information part of a URL. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:23 $ + * @author M. Ranganathan <br/> + * + */ +public final class UserInfo extends NetObject { + + + private static final long serialVersionUID = 7268593273924256144L; + + /** user field + */ + protected String user; + + /** password field + */ + protected String password; + + /** userType field + */ + protected int userType; + + /** Constant field + */ + public final static int TELEPHONE_SUBSCRIBER = 1; + + /** constant field + */ + public final static int USER = 2; + + /** Default constructor + */ + public UserInfo() { + super(); + } + + /** + * Compare for equality. + * @param obj Object to set + * @return true if the two headers are equals, false otherwise. + */ + public boolean equals(Object obj) { + if (getClass() != obj.getClass()) { + return false; + } + UserInfo other = (UserInfo) obj; + if (this.userType != other.userType) { + return false; + } + if (!this.user.equalsIgnoreCase(other.user)) { + return false; + } + if (this.password != null && other.password == null) + return false; + + if (other.password != null && this.password == null) + return false; + + if (this.password == other.password) + return true; + + return (this.password.equals(other.password)); + } + + /** + * Encode the user information as a string. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (password != null) + buffer.append(user).append(COLON).append(password); + else + buffer.append(user); + + return buffer; + } + + /** Clear the password field. + */ + public void clearPassword() { + this.password = null; + } + + /** + * Gets the user type (which can be set to TELEPHONE_SUBSCRIBER or USER) + * @return the type of user. + */ + public int getUserType() { + return userType; + } + + /** get the user field. + * @return String + */ + public String getUser() { + return user; + } + + /** get the password field. + * @return String + */ + public String getPassword() { + return password; + } + + /** + * Set the user member + * @param user String to set + */ + public void setUser(String user) { + this.user = user; + // BUG Fix submitted by Lamine Brahimi + // add this (taken form sip_messageParser) + // otherwise comparison of two SipUrl will fail because this + // parameter is not set (whereas it is set in sip_messageParser). + if (user != null + && (user.indexOf(POUND) >= 0 || user.indexOf(SEMICOLON) >= 0)) { + setUserType(TELEPHONE_SUBSCRIBER); + } else { + setUserType(USER); + } + } + + /** + * Set the password member + * @param p String to set + */ + public void setPassword(String p) { + password = p; + } + + /** + * Set the user type (to TELEPHONE_SUBSCRIBER or USER). + * @param type int to set + * @throws IllegalArgumentException if type is not in range. + */ + public void setUserType(int type) throws IllegalArgumentException { + if (type != TELEPHONE_SUBSCRIBER && type != USER) { + throw new IllegalArgumentException("Parameter not in range"); + } + userType = type; + } +} diff --git a/java/gov/nist/javax/sip/address/package.html b/java/gov/nist/javax/sip/address/package.html new file mode 100644 index 0000000..a4be435 --- /dev/null +++ b/java/gov/nist/javax/sip/address/package.html @@ -0,0 +1,4 @@ + +<body> +Implementation of the address package of the JAIN SIP API. +</body> diff --git a/java/gov/nist/javax/sip/clientauthutils/AccountManager.java b/java/gov/nist/javax/sip/clientauthutils/AccountManager.java new file mode 100644 index 0000000..6f20632 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/AccountManager.java @@ -0,0 +1,20 @@ +package gov.nist.javax.sip.clientauthutils; + +import javax.sip.ClientTransaction; + +public interface AccountManager { + + /** + * Returns the user credentials for a given SIP Domain. + * You can implement any desired method (such as popping up a dialog for example ) + * to retrieve the credentials. + * + * @param challengedTransaction - the transaction that is being challenged. + * @param realm - the realm that is being challenged for which a credential should be + * returned. + * @return -- the user credentials associated with the domain. + */ + + UserCredentials getCredentials(ClientTransaction challengedTransaction, String realm); + +} diff --git a/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelper.java b/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelper.java new file mode 100644 index 0000000..a826691 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelper.java @@ -0,0 +1,75 @@ +package gov.nist.javax.sip.clientauthutils; + +import java.text.ParseException; +import java.util.Collection; + +import javax.sip.ClientTransaction; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import javax.sip.SipProvider; +import javax.sip.header.AuthorizationHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/** + * A helper interface that provides useful functionality for clients that need to authenticate + * with servers. + * + * @author Emil Ivov + * @author Jeroen van Bemmel + * @author M. Ranganathan + * + * @since 2.0 + * + * + */ +public interface AuthenticationHelper { + + /** + * Uses securityAuthority to determinie a set of valid user credentials for + * the specified Response (Challenge) and appends it to the challenged + * request so that it could be retransmitted. + * + * + * + * @param challenge + * the 401/407 challenge response + * @param challengedTransaction + * the transaction established by the challenged request + * @param transactionCreator + * the JAIN SipProvider that we should use to create the new + * transaction. + * @param cacheTime The amount of time (seconds ) for which the authentication helper + * will keep a reference to the generated credentials in a cache. + * If you specify -1, then the authentication credentials are cached + * until you remove them from the cache. If you choose this option, make sure + * you remove the cached headers or you will have a memory leak. + * + * @return a transaction containing a re-originated request with the + * necessary authorization header. + * @throws SipException + * if we get an exception white creating the new transaction + * @throws NullPointerException + * if an argument or a header is null. + */ + public abstract ClientTransaction handleChallenge(Response challenge, + ClientTransaction challengedTransaction, + SipProvider transactionCreator, int cacheTime ) throws SipException, + NullPointerException; + + /** + * Attach authentication headers to the given request. This looks up + * the credential cache and picks up any stored authentication headers + * for the given call ID and attaches it to the request. + * @param request - the request for which we attach the authentication headers. + */ + public abstract void setAuthenticationHeaders(Request request) ; + + /** + * Remove cached entry. + * + * @param callId -- the call Id for which we want to remove the cached headers. + * + */ + public abstract void removeCachedAuthenticationHeaders(String callId); +} diff --git a/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java b/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java new file mode 100644 index 0000000..c15b569 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java @@ -0,0 +1,464 @@ +package gov.nist.javax.sip.clientauthutils; + +/* + * + * This code has been contributed with permission from: + * + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client but has been significantly changed. + * It is donated to the JAIN-SIP project as it is common code that many sip clients + * need to perform class and others will consitute a set of utility functions + * that will implement common operations that ease the life of the developer. + * + * Acknowledgements: + * ---------------- + * + * Fredrik Wickstrom reported that dialog cseq counters are not incremented + * when resending requests. He later uncovered additional problems and + * proposed a way to fix them (his proposition was taken into account). + */ + +import gov.nist.javax.sip.SipStackImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.stack.SIPClientTransaction; +import gov.nist.javax.sip.stack.SIPTransactionStack; + +import java.text.ParseException; +import java.util.Collection; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Timer; + +import javax.sip.ClientTransaction; +import javax.sip.DialogState; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import javax.sip.SipProvider; +import javax.sip.address.Hop; +import javax.sip.address.SipURI; +import javax.sip.address.URI; +import javax.sip.header.AuthorizationHeader; +import javax.sip.header.CSeqHeader; +import javax.sip.header.Header; +import javax.sip.header.HeaderFactory; +import javax.sip.header.ProxyAuthenticateHeader; +import javax.sip.header.ProxyAuthorizationHeader; +import javax.sip.header.ViaHeader; +import javax.sip.header.WWWAuthenticateHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/** + * The class handles authentication challenges, caches user credentials and takes care (through + * the SecurityAuthority interface) about retrieving passwords. + * + * + * @author Emil Ivov + * @author Jeroen van Bemmel + * @author M. Ranganathan + * + * @since 2.0 + */ + +public class AuthenticationHelperImpl implements AuthenticationHelper { + + /** + * Credentials cached so far. + */ + private CredentialsCache cachedCredentials; + + /** + * The account manager for the system. Stores user credentials. + */ + private Object accountManager = null; + + /* + * Header factory for this security manager. + */ + private HeaderFactory headerFactory; + + private SipStackImpl sipStack; + + Timer timer; + + /** + * Default constructor for the security manager. There is one Account manager. There is one + * SipSecurity manager for every user name, + * + * @param sipStack -- our stack. + * @param accountManager -- an implementation of the AccountManager interface. + * @param headerFactory -- header factory. + */ + public AuthenticationHelperImpl(SipStackImpl sipStack, AccountManager accountManager, + HeaderFactory headerFactory) { + this.accountManager = accountManager; + this.headerFactory = headerFactory; + this.sipStack = sipStack; + + this.cachedCredentials = new CredentialsCache(((SIPTransactionStack) sipStack).getTimer()); + } + + /** + * Default constructor for the security manager. There is one Account manager. There is one + * SipSecurity manager for every user name, + * + * @param sipStack -- our stack. + * @param accountManager -- an implementation of the AccountManager interface. + * @param headerFactory -- header factory. + */ + public AuthenticationHelperImpl(SipStackImpl sipStack, SecureAccountManager accountManager, + HeaderFactory headerFactory) { + this.accountManager = accountManager; + this.headerFactory = headerFactory; + this.sipStack = sipStack; + + this.cachedCredentials = new CredentialsCache(((SIPTransactionStack) sipStack).getTimer()); + } + + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#handleChallenge(javax.sip.message.Response, + * javax.sip.ClientTransaction, javax.sip.SipProvider) + */ + public ClientTransaction handleChallenge(Response challenge, + ClientTransaction challengedTransaction, SipProvider transactionCreator, int cacheTime) + throws SipException, NullPointerException { + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("handleChallenge: " + challenge); + } + + SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest()); + + Request reoriginatedRequest = null; + /* + * If the challenged request is part of a Dialog and the + * Dialog is confirmed the re-originated request should be + * generated as an in-Dialog request. + */ + if ( challengedRequest.getToTag() != null || + challengedTransaction.getDialog() == null || + challengedTransaction.getDialog().getState() != DialogState.CONFIRMED) { + reoriginatedRequest = (Request) challengedRequest.clone(); + } else { + /* + * Re-originate the request by consulting the dialog. In particular + * the route set could change between the original request and the + * in-dialog challenge. + */ + reoriginatedRequest = + challengedTransaction.getDialog().createRequest(challengedRequest.getMethod()); + Iterator<String> headerNames = challengedRequest.getHeaderNames(); + while (headerNames.hasNext()) { + String headerName = headerNames.next(); + if ( reoriginatedRequest.getHeader(headerName) != null) { + ListIterator<Header> iterator = reoriginatedRequest.getHeaders(headerName); + while (iterator.hasNext()) { + reoriginatedRequest.addHeader(iterator.next()); + } + } + } + } + + + + // remove the branch id so that we could use the request in a new + // transaction + removeBranchID(reoriginatedRequest); + + if (challenge == null || reoriginatedRequest == null) { + throw new NullPointerException("A null argument was passed to handle challenge."); + } + + ListIterator authHeaders = null; + + if (challenge.getStatusCode() == Response.UNAUTHORIZED) { + authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME); + } else if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) { + authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME); + } else { + throw new IllegalArgumentException("Unexpected status code "); + } + + if (authHeaders == null) { + throw new IllegalArgumentException( + "Could not find WWWAuthenticate or ProxyAuthenticate headers"); + } + + // Remove all authorization headers from the request (we'll re-add them + // from cache) + reoriginatedRequest.removeHeader(AuthorizationHeader.NAME); + reoriginatedRequest.removeHeader(ProxyAuthorizationHeader.NAME); + + // rfc 3261 says that the cseq header should be augmented for the new + // request. do it here so that the new dialog (created together with + // the new client transaction) takes it into account. + // Bug report - Fredrik Wickstrom + CSeqHeader cSeq = (CSeqHeader) reoriginatedRequest.getHeader((CSeqHeader.NAME)); + try { + cSeq.setSeqNumber(cSeq.getSeqNumber() + 1l); + } catch (InvalidArgumentException ex) { + throw new SipException("Invalid CSeq -- could not increment : " + + cSeq.getSeqNumber()); + } + + + /* Resolve this to the next hop based on the previous lookup. If we are not using + * lose routing (RFC2543) then just attach hop as a maddr param. + */ + if ( challengedRequest.getRouteHeaders() == null ) { + Hop hop = ((SIPClientTransaction) challengedTransaction).getNextHop(); + SipURI sipUri = (SipURI) reoriginatedRequest.getRequestURI(); + sipUri.setMAddrParam(hop.getHost()); + if ( hop.getPort() != -1 ) sipUri.setPort(hop.getPort()); + } + ClientTransaction retryTran = transactionCreator + .getNewClientTransaction(reoriginatedRequest); + + WWWAuthenticateHeader authHeader = null; + SipURI requestUri = (SipURI) challengedTransaction.getRequest().getRequestURI(); + while (authHeaders.hasNext()) { + authHeader = (WWWAuthenticateHeader) authHeaders.next(); + String realm = authHeader.getRealm(); + AuthorizationHeader authorization = null; + String sipDomain; + if ( this.accountManager instanceof SecureAccountManager ) { + UserCredentialHash credHash = + ((SecureAccountManager)this.accountManager).getCredentialHash(challengedTransaction,realm); + URI uri = reoriginatedRequest.getRequestURI(); + sipDomain = credHash.getSipDomain(); + authorization = this.getAuthorization(reoriginatedRequest + .getMethod(), uri.toString(), + (reoriginatedRequest.getContent() == null) ? "" : new String( + reoriginatedRequest.getRawContent()), authHeader, credHash); + } else { + UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm); + sipDomain = userCreds.getSipDomain(); + if (userCreds == null) + throw new SipException( + "Cannot find user creds for the given user name and realm"); + + // we haven't yet authenticated this realm since we were + // started. + + authorization = this.getAuthorization(reoriginatedRequest + .getMethod(), reoriginatedRequest.getRequestURI().toString(), + (reoriginatedRequest.getContent() == null) ? "" : new String( + reoriginatedRequest.getRawContent()), authHeader, userCreds); + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Created authorization header: " + authorization.toString()); + + if (cacheTime != 0) + cachedCredentials.cacheAuthorizationHeader(sipDomain, + authorization, cacheTime); + + reoriginatedRequest.addHeader(authorization); + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Returning authorization transaction." + retryTran); + } + return retryTran; + } catch (SipException ex) { + throw ex; + } catch (Exception ex) { + sipStack.getStackLogger().logError("Unexpected exception ", ex); + throw new SipException("Unexpected exception ", ex); + } + } + + + + + /** + * Generates an authorisation header in response to wwwAuthHeader. + * + * @param method method of the request being authenticated + * @param uri digest-uri + * @param requestBody the body of the request. + * @param authHeader the challenge that we should respond to + * @param userCredentials username and pass + * + * @return an authorisation header in response to authHeader. + * + * @throws OperationFailedException if auth header was malformated. + */ + private AuthorizationHeader getAuthorization(String method, String uri, String requestBody, + WWWAuthenticateHeader authHeader, UserCredentials userCredentials) { + String response = null; + + // JvB: authHeader.getQop() is a quoted _list_ of qop values + // (e.g. "auth,auth-int") Client is supposed to pick one + String qopList = authHeader.getQop(); + String qop = (qopList != null) ? "auth" : null; + String nc_value = "00000001"; + String cnonce = "xyz"; + + response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(), + userCredentials.getUserName(), authHeader.getRealm(), userCredentials + .getPassword(), authHeader.getNonce(), nc_value, // JvB added + cnonce, // JvB added + method, uri, requestBody, qop,sipStack.getStackLogger());// jvb changed + + AuthorizationHeader authorization = null; + try { + if (authHeader instanceof ProxyAuthenticateHeader) { + authorization = headerFactory.createProxyAuthorizationHeader(authHeader + .getScheme()); + } else { + authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme()); + } + + authorization.setUsername(userCredentials.getUserName()); + authorization.setRealm(authHeader.getRealm()); + authorization.setNonce(authHeader.getNonce()); + authorization.setParameter("uri", uri); + authorization.setResponse(response); + if (authHeader.getAlgorithm() != null) { + authorization.setAlgorithm(authHeader.getAlgorithm()); + } + + if (authHeader.getOpaque() != null) { + authorization.setOpaque(authHeader.getOpaque()); + } + + // jvb added + if (qop != null) { + authorization.setQop(qop); + authorization.setCNonce(cnonce); + authorization.setNonceCount(Integer.parseInt(nc_value)); + } + + authorization.setResponse(response); + + } catch (ParseException ex) { + throw new RuntimeException("Failed to create an authorization header!"); + } + + return authorization; + } + /** + * Generates an authorisation header in response to wwwAuthHeader. + * + * @param method method of the request being authenticated + * @param uri digest-uri + * @param requestBody the body of the request. + * @param authHeader the challenge that we should respond to + * @param userCredentials username and pass + * + * @return an authorisation header in response to authHeader. + * + * @throws OperationFailedException if auth header was malformated. + */ + private AuthorizationHeader getAuthorization(String method, String uri, String requestBody, + WWWAuthenticateHeader authHeader, UserCredentialHash userCredentials) { + String response = null; + + // JvB: authHeader.getQop() is a quoted _list_ of qop values + // (e.g. "auth,auth-int") Client is supposed to pick one + String qopList = authHeader.getQop(); + String qop = (qopList != null) ? "auth" : null; + String nc_value = "00000001"; + String cnonce = "xyz"; + + response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(), + userCredentials.getHashUserDomainPassword(), authHeader.getNonce(), nc_value, // JvB added + cnonce, // JvB added + method, uri, requestBody, qop,sipStack.getStackLogger());// jvb changed + + AuthorizationHeader authorization = null; + try { + if (authHeader instanceof ProxyAuthenticateHeader) { + authorization = headerFactory.createProxyAuthorizationHeader(authHeader + .getScheme()); + } else { + authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme()); + } + + authorization.setUsername(userCredentials.getUserName()); + authorization.setRealm(authHeader.getRealm()); + authorization.setNonce(authHeader.getNonce()); + authorization.setParameter("uri", uri); + authorization.setResponse(response); + if (authHeader.getAlgorithm() != null) { + authorization.setAlgorithm(authHeader.getAlgorithm()); + } + + if (authHeader.getOpaque() != null) { + authorization.setOpaque(authHeader.getOpaque()); + } + + // jvb added + if (qop != null) { + authorization.setQop(qop); + authorization.setCNonce(cnonce); + authorization.setNonceCount(Integer.parseInt(nc_value)); + } + + authorization.setResponse(response); + + } catch (ParseException ex) { + throw new RuntimeException("Failed to create an authorization header!"); + } + + return authorization; + } + /** + * Removes all via headers from <tt>request</tt> and replaces them with a new one, equal to + * the one that was top most. + * + * @param request the Request whose branchID we'd like to remove. + * + */ + private void removeBranchID(Request request) { + + ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); + + viaHeader.removeParameter("branch"); + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#attachAuthenticationHeaders(javax.sip.message.Request) + */ + public void setAuthenticationHeaders(Request request) { + SIPRequest sipRequest = (SIPRequest) request; + + String callId = sipRequest.getCallId().getCallId(); + + request.removeHeader(AuthorizationHeader.NAME); + Collection<AuthorizationHeader> authHeaders = this.cachedCredentials + .getCachedAuthorizationHeaders(callId); + if (authHeaders == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Could not find authentication headers for " + callId); + return; + } + + for (AuthorizationHeader authHeader : authHeaders) { + request.addHeader(authHeader); + } + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#removeCachedAuthenticationHeaders(java.lang.String) + */ + public void removeCachedAuthenticationHeaders(String callId) { + if (callId == null) + throw new NullPointerException("Null callId argument "); + this.cachedCredentials.removeAuthenticationHeader(callId); + + } + +} diff --git a/java/gov/nist/javax/sip/clientauthutils/CredentialsCache.java b/java/gov/nist/javax/sip/clientauthutils/CredentialsCache.java new file mode 100644 index 0000000..2a84f28 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/CredentialsCache.java @@ -0,0 +1,119 @@ +package gov.nist.javax.sip.clientauthutils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import javax.sip.*; +import javax.sip.header.*; +import javax.sip.address.*; +import javax.sip.message.*; + +/** + * A cache of authorization headers to be used for subsequent processing when we + * set up calls. We cache credentials on a per proxy domain per user basis. + * + */ + +class CredentialsCache { + + + /** + * The key for this map is the proxy domain name. A given proxy authorizes a + * user for a number of domains. The Hashtable value of the mapping is a + * mapping of user names to AuthorizationHeader list for that proxy domain. + */ + private ConcurrentHashMap<String, List<AuthorizationHeader>> authorizationHeaders = + new ConcurrentHashMap<String, List<AuthorizationHeader>>(); + private Timer timer; + + class TimeoutTask extends TimerTask { + String callId; + String userName; + + public TimeoutTask(String userName, String proxyDomain) { + this.callId = proxyDomain; + this.userName = userName; + } + + @Override + public void run() { + authorizationHeaders.remove(callId); + + } + + } + + + + CredentialsCache (Timer timer) { + this.timer = timer; + } + + /** + * Cache the bindings of proxyDomain and authorization header. + * + * @param callid + * the id of the call that the <tt>authorization</tt> header + * belongs to. + * @param authorization + * the authorization header that we'd like to cache. + */ + void cacheAuthorizationHeader(String callId, + AuthorizationHeader authorization, int cacheTime) { + String user = authorization.getUsername(); + if ( callId == null) throw new NullPointerException("Call ID is null!"); + if ( authorization == null) throw new NullPointerException("Null authorization domain"); + + List<AuthorizationHeader> authHeaders = authorizationHeaders.get(callId); + if (authHeaders == null) { + authHeaders = new LinkedList<AuthorizationHeader>(); + authorizationHeaders.put(callId, authHeaders); + } else { + String realm = authorization.getRealm(); + for (ListIterator<AuthorizationHeader> li = authHeaders.listIterator(); li.hasNext();) { + AuthorizationHeader authHeader = (AuthorizationHeader) li.next(); + if ( realm.equals(authHeader.getRealm()) ) { + li.remove(); + } + } + } + + authHeaders.add(authorization); + + TimeoutTask timeoutTask = new TimeoutTask( callId,user); + if ( cacheTime != -1) + this.timer.schedule(timeoutTask, cacheTime*1000); + + + } + + /** + * Returns an authorization header cached for the specified call id and null + * if no authorization header has been previously cached for this call. + * + * @param callid + * the call id that we'd like to retrive a cached authorization + * header for. + * + * @return authorization header corresponding to that user for the given + * proxy domain. + */ + Collection<AuthorizationHeader> getCachedAuthorizationHeaders( + String callid) { + if (callid == null) + throw new NullPointerException("Null arg!"); + return this.authorizationHeaders.get(callid); + + } + + /** + * Remove a cached authorization header. + * + * @param callId + */ + public void removeAuthenticationHeader(String callId) { + this.authorizationHeaders.remove(callId); + + } + +} diff --git a/java/gov/nist/javax/sip/clientauthutils/MessageDigestAlgorithm.java b/java/gov/nist/javax/sip/clientauthutils/MessageDigestAlgorithm.java new file mode 100644 index 0000000..8c1752d --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/MessageDigestAlgorithm.java @@ -0,0 +1,225 @@ +package gov.nist.javax.sip.clientauthutils; + +import gov.nist.core.StackLogger; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * The class takes standard Http Authentication details and returns a response according to the + * MD5 algorithm + * + * @author Emil Ivov + */ + +public class MessageDigestAlgorithm { + /** + * Calculates an http authentication response in accordance with rfc2617. + * <p> + * + * @param algorithm a string indicating a pair of algorithms (MD5 (default), or MD5-sess) used + * to produce the digest and a checksum. + * @param hashUserNameRealmPasswd MD5 hash of (username:realm:password) + * @param nonce_value A server-specified data string provided in the challenge. + * @param cnonce_value an optional client-chosen value whose purpose is to foil chosen + * plaintext attacks. + * @param method the SIP method of the request being challenged. + * @param digest_uri_value the value of the "uri" directive on the Authorization header in the + * request. + * @param entity_body the entity-body + * @param qop_value Indicates what "quality of protection" the client has applied to the + * message. + * @param nc_value the hexadecimal count of the number of requests (including the current + * request) that the client has sent with the nonce value in this request. + * @return a digest response as defined in rfc2617 + * @throws NullPointerException in case of incorrectly null parameters. + */ + + static String calculateResponse(String algorithm, String hashUserNameRealmPasswd, + String nonce_value, String nc_value, String cnonce_value, + String method, String digest_uri_value, String entity_body, String qop_value, + StackLogger stackLogger) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("trying to authenticate using : " + algorithm + ", "+ + hashUserNameRealmPasswd + ", " + nonce_value + ", " + + nc_value + ", " + cnonce_value + ", " + method + ", " + digest_uri_value + + ", " + entity_body + ", " + qop_value); + } + + if (hashUserNameRealmPasswd == null || method == null + || digest_uri_value == null || nonce_value == null) + throw new NullPointerException( + "Null parameter to MessageDigestAlgorithm.calculateResponse()"); + + // The following follows closely the algorithm for generating a response + // digest as specified by rfc2617 + + if (cnonce_value == null || cnonce_value.length() == 0) + throw new NullPointerException( + "cnonce_value may not be absent for MD5-Sess algorithm."); + + + String A2 = null; + if (qop_value == null || qop_value.trim().length() == 0 + || qop_value.trim().equalsIgnoreCase("auth")) { + A2 = method + ":" + digest_uri_value; + } else { + if (entity_body == null) + entity_body = ""; + A2 = method + ":" + digest_uri_value + ":" + H(entity_body); + } + + String request_digest = null; + + if (cnonce_value != null && qop_value != null && nc_value != null + && (qop_value.equalsIgnoreCase("auth") || qop_value.equalsIgnoreCase("auth-int"))) + + { + request_digest = KD(hashUserNameRealmPasswd, nonce_value + ":" + nc_value + ":" + cnonce_value + ":" + + qop_value + ":" + H(A2)); + + } else { + request_digest = KD(hashUserNameRealmPasswd, nonce_value + ":" + H(A2)); + } + + return request_digest; + + + } + + /** + * Calculates an http authentication response in accordance with rfc2617. + * <p> + * + * @param algorithm a string indicating a pair of algorithms (MD5 (default), or MD5-sess) used + * to produce the digest and a checksum. + * @param username_value username_value (see rfc2617) + * @param realm_value A string that has been displayed to the user in order to determine the + * context of the username and password to use. + * @param passwd the password to encode in the challenge response. + * @param nonce_value A server-specified data string provided in the challenge. + * @param cnonce_value an optional client-chosen value whose purpose is to foil chosen + * plaintext attacks. + * @param method the SIP method of the request being challenged. + * @param digest_uri_value the value of the "uri" directive on the Authorization header in the + * request. + * @param entity_body the entity-body + * @param qop_value Indicates what "quality of protection" the client has applied to the + * message. + * @param nc_value the hexadecimal count of the number of requests (including the current + * request) that the client has sent with the nonce value in this request. + * @return a digest response as defined in rfc2617 + * @throws NullPointerException in case of incorrectly null parameters. + */ + static String calculateResponse(String algorithm, String username_value, String realm_value, + String passwd, String nonce_value, String nc_value, String cnonce_value, + String method, String digest_uri_value, String entity_body, String qop_value, + StackLogger stackLogger) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("trying to authenticate using : " + algorithm + ", " + + username_value + ", " + realm_value + ", " + + (passwd != null && passwd.trim().length() > 0) + ", " + nonce_value + ", " + + nc_value + ", " + cnonce_value + ", " + method + ", " + digest_uri_value + + ", " + entity_body + ", " + qop_value); + } + + if (username_value == null || realm_value == null || passwd == null || method == null + || digest_uri_value == null || nonce_value == null) + throw new NullPointerException( + "Null parameter to MessageDigestAlgorithm.calculateResponse()"); + + // The following follows closely the algorithm for generating a response + // digest as specified by rfc2617 + String A1 = null; + + if (algorithm == null || algorithm.trim().length() == 0 + || algorithm.trim().equalsIgnoreCase("MD5")) { + A1 = username_value + ":" + realm_value + ":" + passwd; + } else { + if (cnonce_value == null || cnonce_value.length() == 0) + throw new NullPointerException( + "cnonce_value may not be absent for MD5-Sess algorithm."); + + A1 = H(username_value + ":" + realm_value + ":" + passwd) + ":" + nonce_value + ":" + + cnonce_value; + } + + String A2 = null; + if (qop_value == null || qop_value.trim().length() == 0 + || qop_value.trim().equalsIgnoreCase("auth")) { + A2 = method + ":" + digest_uri_value; + } else { + if (entity_body == null) + entity_body = ""; + A2 = method + ":" + digest_uri_value + ":" + H(entity_body); + } + + String request_digest = null; + + if (cnonce_value != null && qop_value != null && nc_value != null + && (qop_value.equalsIgnoreCase("auth") || qop_value.equalsIgnoreCase("auth-int"))) + + { + request_digest = KD(H(A1), nonce_value + ":" + nc_value + ":" + cnonce_value + ":" + + qop_value + ":" + H(A2)); + + } else { + request_digest = KD(H(A1), nonce_value + ":" + H(A2)); + } + + return request_digest; + } + + /** + * Defined in rfc 2617 as H(data) = MD5(data); + * + * @param data data + * @return MD5(data) + */ + private static String H(String data) { + try { + MessageDigest digest = MessageDigest.getInstance("MD5"); + + return toHexString(digest.digest(data.getBytes())); + } catch (NoSuchAlgorithmException ex) { + // shouldn't happen + throw new RuntimeException("Failed to instantiate an MD5 algorithm", ex); + } + } + + /** + * Defined in rfc 2617 as KD(secret, data) = H(concat(secret, ":", data)) + * + * @param data data + * @param secret secret + * @return H(concat(secret, ":", data)); + */ + private static String KD(String secret, String data) { + return H(secret + ":" + data); + } + + // the following code was copied from the NIST-SIP instant + // messenger (its author is Olivier Deruelle). Thanks for making it public! + /** + * to hex converter + */ + private static final char[] toHex = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + /** + * Converts b[] to hex string. + * + * @param b the bte array to convert + * @return a Hex representation of b. + */ + private static String toHexString(byte b[]) { + int pos = 0; + char[] c = new char[b.length * 2]; + for (int i = 0; i < b.length; i++) { + c[pos++] = toHex[(b[i] >> 4) & 0x0F]; + c[pos++] = toHex[b[i] & 0x0f]; + } + return new String(c); + } +} diff --git a/java/gov/nist/javax/sip/clientauthutils/SecureAccountManager.java b/java/gov/nist/javax/sip/clientauthutils/SecureAccountManager.java new file mode 100644 index 0000000..df2522b --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/SecureAccountManager.java @@ -0,0 +1,19 @@ +package gov.nist.javax.sip.clientauthutils; + +import javax.sip.ClientTransaction; + +public interface SecureAccountManager { + /** + * Returns the user credentials for a given SIP Domain. + * You can implement any desired method (such as popping up a dialog for example ) + * to retrieve the credentials. + * + * @param challengedTransaction - the transaction that is being challenged. + * @param realm - the realm that is being challenged for which a credential should be + * returned. + * @return -- the user credentials associated with the domain. + */ + + UserCredentialHash getCredentialHash(ClientTransaction challengedTransaction, String realm); + +} diff --git a/java/gov/nist/javax/sip/clientauthutils/UserCredentialHash.java b/java/gov/nist/javax/sip/clientauthutils/UserCredentialHash.java new file mode 100644 index 0000000..bb4ea31 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/UserCredentialHash.java @@ -0,0 +1,36 @@ +package gov.nist.javax.sip.clientauthutils; + +/** + * Interface for those clients that only supply + * hash(user:domain:password). This is more secure than simply supplying + * password because the password cannot be extracted. Implementations + * tend to prefer to store information in user accounts using such a + * hash rather than plain text passwords because it offers better security. + * + */ +public interface UserCredentialHash { + + /** + * Get the user name. + * + * @return userName + */ + public String getUserName(); + + + /** + * Get the SipDomain. + * + * @return the SIP Domain. + */ + public String getSipDomain(); + + + /** + * Get the MD5(userName:sipdomain:password) + * + * @return the MD5 hash of userName:sipDomain:password. + */ + public String getHashUserDomainPassword(); + +} diff --git a/java/gov/nist/javax/sip/clientauthutils/UserCredentials.java b/java/gov/nist/javax/sip/clientauthutils/UserCredentials.java new file mode 100644 index 0000000..0343dd6 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/UserCredentials.java @@ -0,0 +1,41 @@ +package gov.nist.javax.sip.clientauthutils; + +/** +* The class is used whenever user credentials for a particular realm (site +* server or service) are necessary +* @author Emil Ivov <emcho@dev.java.net> +* @author M. Ranganathan <mranga@dev.java.net> +* @version 1.0 +*/ + +public interface UserCredentials +{ + + + /** + * Returns the name of the user that these credentials relate to. + * @return the user name. + */ + public String getUserName(); + + + /** + * Returns a password associated with this set of credentials. + * + * @return a password associated with this set of credentials. + */ + public String getPassword(); + + + /** + * Returns the SIP Domain for this username password combination. + * + * @return the sip domain + */ + public String getSipDomain(); + + + +} + + diff --git a/java/gov/nist/javax/sip/clientauthutils/package.html b/java/gov/nist/javax/sip/clientauthutils/package.html new file mode 100644 index 0000000..b770a31 --- /dev/null +++ b/java/gov/nist/javax/sip/clientauthutils/package.html @@ -0,0 +1,10 @@ +<body> +This package contains a set of utilities for client side Authentication Challenge handling. It has been +adapted from the SIP communicator project and generously dontated to the JAIN-SIP project +It is not part of the standard JAIN-SIP implementation at this point but is being considered for +addition as this is an operation that is commonly required by all SIP clients; it is hence a good capability +to include in a library such as JAIN-SIP. + +<p/> Primary authors of this code are Emil Ivov with corrections from Jeroen van Bemmel. + +</body>
\ No newline at end of file diff --git a/java/gov/nist/javax/sip/header/Accept.java b/java/gov/nist/javax/sip/header/Accept.java new file mode 100644 index 0000000..546b981 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Accept.java @@ -0,0 +1,201 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; + +/** + * Accept header : The top level header is actually AcceptList which is a list of + * Accept headers. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:24 $ + * + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + * + */ +public final class Accept + extends ParametersHeader + implements javax.sip.header.AcceptHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -7866187924308658151L; + + /** mediaRange field + */ + protected MediaRange mediaRange; + + /** default constructor + */ + public Accept() { + super(NAME); + } + + /** returns true if this header allows all ContentTypes, + * false otherwise. + * @return Boolean + */ + public boolean allowsAllContentTypes() { + if (mediaRange == null) + return false; + else + return mediaRange.type.compareTo(STAR) == 0; + } + + /** + * returns true if this header allows all ContentSubTypes, + * false otherwise. + * @return boolean + */ + public boolean allowsAllContentSubTypes() { + if (mediaRange == null) { + return false; + } else + return mediaRange.getSubtype().compareTo(STAR) == 0; + } + + /** Encode the value of this header into cannonical form. + *@return encoded value of the header as a string. + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (mediaRange != null) + mediaRange.encode(buffer); + if (parameters != null && !parameters.isEmpty()) { + buffer.append(';'); + parameters.encode(buffer); + } + return buffer; + } + + /** get the MediaRange field + * @return MediaRange + */ + public MediaRange getMediaRange() { + return mediaRange; + } + + /** get the contentType field + * @return String + */ + public String getContentType() { + if (mediaRange == null) + return null; + else + return mediaRange.getType(); + } + + /** get the ContentSubType fiels + * @return String + */ + public String getContentSubType() { + if (mediaRange == null) + return null; + else + return mediaRange.getSubtype(); + } + + /** + * Get the q value. + * @return float + */ + public float getQValue() { + return getParameterAsFloat(ParameterNames.Q); + } + + /** + * Return true if the q value has been set. + * @return boolean + */ + public boolean hasQValue() { + return super.hasParameter(ParameterNames.Q); + + } + + /** + *Remove the q value. + */ + public void removeQValue() { + super.removeParameter(ParameterNames.Q); + } + + /** set the ContentSubType field + * @param subtype String to set + */ + public void setContentSubType(String subtype) { + if (mediaRange == null) + mediaRange = new MediaRange(); + mediaRange.setSubtype(subtype); + } + + /** set the ContentType field + * @param type String to set + */ + public void setContentType(String type) { + if (mediaRange == null) + mediaRange = new MediaRange(); + mediaRange.setType(type); + } + + /** + * Set the q value + * @param qValue float to set + * @throws IllegalArgumentException if qValue is <0.0 or >1.0 + */ + public void setQValue(float qValue) throws InvalidArgumentException { + if (qValue == -1) + super.removeParameter(ParameterNames.Q); + super.setParameter(ParameterNames.Q, qValue); + + } + + /** + * Set the mediaRange member + * @param m MediaRange field + */ + public void setMediaRange(MediaRange m) { + mediaRange = m; + } + + public Object clone() { + Accept retval = (Accept) super.clone(); + if (this.mediaRange != null) + retval.mediaRange = (MediaRange) this.mediaRange.clone(); + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/header/AcceptEncoding.java b/java/gov/nist/javax/sip/header/AcceptEncoding.java new file mode 100644 index 0000000..708c276 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AcceptEncoding.java @@ -0,0 +1,153 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.*; +import java.text.ParseException; + +/** + * Accept-Encoding SIP (HTTP) Header. + * + * @author M. Ranganathan + * @author Olivier Deruelle <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:24 $ + * @since 1.1 + * + * <pre> + * From HTTP RFC 2616 + * + * + * The Accept-Encoding request-header field is similar to Accept, but + * restricts the content-codings (section 3.5) that are acceptable in + * the response. + * + * + * Accept-Encoding = "Accept-Encoding" ":" + * + * + * 1#( codings [ ";" "q" "=" qvalue ] ) + * codings = ( content-coding | "*" ) + * + * Examples of its use are: + * + * Accept-Encoding: compress, gzip + * Accept-Encoding: + * Accept-Encoding: * + * Accept-Encoding: compress;q=0.5, gzip;q=1.0 + * Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 + * </pre> + * + */ +public final class AcceptEncoding extends ParametersHeader implements + AcceptEncodingHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1476807565552873525L; + + /** + * contentEncoding field + */ + protected String contentCoding; + + /** + * default constructor + */ + public AcceptEncoding() { + super(NAME); + } + + /** + * Encode the value of this header. + * + * @return the value of this header encoded into a string. + */ + protected String encodeBody() { + return encode(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (contentCoding != null) { + buffer.append(contentCoding); + } + if (parameters != null && !parameters.isEmpty()) { + buffer.append(SEMICOLON).append(parameters.encode()); + } + return buffer; + } + + /** + * get QValue field + * + * @return float + */ + public float getQValue() { + return getParameterAsFloat("q"); + } + + /** + * get ContentEncoding field + * + * @return String + */ + public String getEncoding() { + return contentCoding; + } + + /** + * Set the qvalue member + * + * @param q + * double to set + */ + public void setQValue(float q) throws InvalidArgumentException { + if (q < 0.0 || q > 1.0) + throw new InvalidArgumentException("qvalue out of range!"); + super.setParameter("q", q); + } + + /** + * Sets the encoding of an EncodingHeader. + * + * @param encoding - + * the new string value defining the encoding. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the encoding value. + */ + + public void setEncoding(String encoding) throws ParseException { + if (encoding == null) + throw new NullPointerException(" encoding parameter is null"); + contentCoding = encoding; + } + +} diff --git a/java/gov/nist/javax/sip/header/AcceptEncodingList.java b/java/gov/nist/javax/sip/header/AcceptEncodingList.java new file mode 100644 index 0000000..cc0dadc --- /dev/null +++ b/java/gov/nist/javax/sip/header/AcceptEncodingList.java @@ -0,0 +1,55 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * AcceptEncodingList of AccepEncoding headers. + * + *@author M. Ranganathan + *@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:25 $ + *@since 1.1 + * + * + */ +public class AcceptEncodingList extends SIPHeaderList<AcceptEncoding>{ + + @Override + public Object clone() { + AcceptEncodingList retval = new AcceptEncodingList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** default constructor + */ + public AcceptEncodingList() { + super(AcceptEncoding.class, AcceptEncodingHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/AcceptLanguage.java b/java/gov/nist/javax/sip/header/AcceptLanguage.java new file mode 100644 index 0000000..60d1af1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AcceptLanguage.java @@ -0,0 +1,197 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + /**************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ****************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.core.*; +import javax.sip.header.AcceptLanguageHeader; +import javax.sip.InvalidArgumentException; +import java.util.Locale; + +/** + * Accept Language body. + * + * @author M. Ranganathan + * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:32 $ + * @since 1.1 + * + * + * <pre> + * HTTP RFC 2616 Section 14.4 + * Accept-Language = "Accept-Language" ":" + * 1#( language-range [ ";" "q" "=" qvalue ] ) + * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) + * + * </pre> + * + * @see AcceptLanguageList + */ +public final class AcceptLanguage + extends ParametersHeader + implements AcceptLanguageHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4473982069737324919L; + /** languageRange field + */ + protected String languageRange; + + /** default constructor + */ + public AcceptLanguage() { + super(NAME); + } + + /** Encode the value of this header to a string. + *@return encoded header as a string. + */ + protected String encodeBody() { + StringBuffer encoding = new StringBuffer(); + if (languageRange != null) { + encoding.append(languageRange); + } + if (!parameters.isEmpty()) { + encoding.append(SEMICOLON).append(parameters.encode()); + } + return encoding.toString(); + } + + /** get the LanguageRange field + * @return String + */ + public String getLanguageRange() { + return languageRange; + } + + /** get the QValue field. Return -1 if the parameter has not been + * set. + * @return float + */ + + public float getQValue() { + if (!hasParameter("q")) + return -1; + return ((Float) parameters.getValue("q")).floatValue(); + } + + /** + * Return true if the q value has been set. + * @since 1.0 + * @return boolean + */ + public boolean hasQValue() { + return hasParameter("q"); + } + + /** + * Remove the q value. + * @since 1.0 + */ + public void removeQValue() { + removeParameter("q"); + } + + /** + * Set the languageRange. + * + * @param languageRange is the language range to set. + * + */ + public void setLanguageRange(String languageRange) { + this.languageRange = languageRange.trim(); + } + + /** + * Sets q-value for media-range in AcceptLanguageHeader. Q-values allow the + * + * user to indicate the relative degree of preference for that media-range, + * + * using the qvalue scale from 0 to 1. If no q-value is present, the + * + * media-range should be treated as having a q-value of 1. + * + * + * + * @param q The new float value of the q-value, a value of -1 resets + * the qValue. + * + * @throws InvalidArgumentException if the q parameter value is not + * + * <code>-1</code> or between <code>0 and 1</code>. + * + */ + public void setQValue(float q) throws InvalidArgumentException { + if (q < 0.0 || q > 1.0) + throw new InvalidArgumentException("qvalue out of range!"); + if (q == -1) + this.removeParameter("q"); + else + this.setParameter(new NameValue("q", Float.valueOf(q))); + } + + /** + * Gets the language value of the AcceptLanguageHeader. + * + * + * + * @return the language Locale value of this AcceptLanguageHeader + * + */ + public Locale getAcceptLanguage() { + if (this.languageRange == null) + return null; + else { + int dash = languageRange.indexOf('-'); + if (dash>=0) { + return new Locale( languageRange.substring(0,dash), languageRange.substring(dash+1) ); + } else return new Locale( this.languageRange ); + } + } + + /** + * Sets the language parameter of this AcceptLanguageHeader. + * + * + * + * @param language - the new Locale value of the language of + * + * AcceptLanguageHeader + * + * + */ + public void setAcceptLanguage(Locale language) { + // JvB: need to take sub-tag into account + if ( "".equals(language.getCountry())) { + this.languageRange = language.getLanguage(); + } else { + this.languageRange = language.getLanguage() + '-' + language.getCountry(); + } + } + +} diff --git a/java/gov/nist/javax/sip/header/AcceptLanguageList.java b/java/gov/nist/javax/sip/header/AcceptLanguageList.java new file mode 100644 index 0000000..b2c9b31 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AcceptLanguageList.java @@ -0,0 +1,71 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * AcceptLanguageList: Strings together a list of AcceptLanguage SIPHeaders. + * @author M. Ranganathan + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:25 $ + * @since 1.1 + * + * + */ +public class AcceptLanguageList extends SIPHeaderList<AcceptLanguage> { + + + private static final long serialVersionUID = -3289606805203488840L; + + @Override + public Object clone() { + AcceptLanguageList retval = new AcceptLanguageList(); + retval.clonehlist(this.hlist); + return retval; + } + + public AcceptLanguageList() { + super(AcceptLanguage.class, AcceptLanguageHeader.NAME); + } + + public AcceptLanguage getFirst() { + AcceptLanguage retval = (AcceptLanguage) super.getFirst(); + if (retval != null) + return retval; + else + return new AcceptLanguage(); + } + + public AcceptLanguage getLast() { + AcceptLanguage retval = (AcceptLanguage) super.getLast(); + if (retval != null) + return retval; + else + return new AcceptLanguage(); + } +} diff --git a/java/gov/nist/javax/sip/header/AcceptList.java b/java/gov/nist/javax/sip/header/AcceptList.java new file mode 100644 index 0000000..541befb --- /dev/null +++ b/java/gov/nist/javax/sip/header/AcceptList.java @@ -0,0 +1,61 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * Accept List of SIP headers. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:25 $ + * + * @since 1.1 + * + * @see Accept + */ +public class AcceptList extends SIPHeaderList<Accept> { + + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1800813338560484831L; + + @Override + public Object clone() { + AcceptList retval = new AcceptList(); + retval.clonehlist(this.hlist); + return retval; + } + /** + * Default constructor + */ + public AcceptList() { + super(Accept.class, AcceptHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/AddressParameters.java b/java/gov/nist/javax/sip/header/AddressParameters.java new file mode 100644 index 0000000..3023132 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AddressParameters.java @@ -0,0 +1,30 @@ +package gov.nist.javax.sip.header; + +import java.util.Map; +import java.util.Map.Entry; + +import javax.sip.address.Address; +import javax.sip.header.Parameters; + +public interface AddressParameters extends Parameters { + + /** + * get the Address field + * @return the imbedded Address + */ + public abstract Address getAddress(); + + /** + * set the Address field + * @param address Address to set + */ + public abstract void setAddress(Address address); + + /** + * Get the parameters map. + * + */ + public abstract Map<String,Entry<String,String>> getParameters(); + + +} diff --git a/java/gov/nist/javax/sip/header/AddressParametersHeader.java b/java/gov/nist/javax/sip/header/AddressParametersHeader.java new file mode 100644 index 0000000..c76b4a8 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AddressParametersHeader.java @@ -0,0 +1,106 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +package gov.nist.javax.sip.header; + +import javax.sip.address.*; +import javax.sip.header.FromHeader; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + +import gov.nist.javax.sip.address.*; + +/** An abstract class for headers that take an address and parameters. + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:25 $ + * + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + * + * + */ +public abstract class AddressParametersHeader extends ParametersHeader implements Parameters { + + protected AddressImpl address; + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AddressParameters#getAddress() + */ + public Address getAddress() { + return address; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AddressParameters#setAddress(javax.sip.address.Address) + */ + public void setAddress(Address address) { + this.address = (AddressImpl) address; + } + + /** + * Constructor given the name of the header. + */ + protected AddressParametersHeader(String name) { + super(name); + } + + /** + * Constructor given a synch flag. + * + * @param name + * @param sync + */ + + protected AddressParametersHeader(String name, boolean sync) { + super(name,sync); + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AddressParameters#clone() + */ + public Object clone() { + AddressParametersHeader retval = (AddressParametersHeader) super.clone(); + if (this.address != null) + retval.address = (AddressImpl) this.address.clone(); + return retval; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AddressParameters#equals(java.lang.Object) + */ + public boolean equals(Object other) { + if (this==other) return true; + + + + if (other instanceof HeaderAddress && other instanceof Parameters) { + final HeaderAddress o = (HeaderAddress) other; + return this.getAddress().equals( o.getAddress() ) && this.equalParameters( (Parameters) o ); + } + return false; + } + +} diff --git a/java/gov/nist/javax/sip/header/AlertInfo.java b/java/gov/nist/javax/sip/header/AlertInfo.java new file mode 100644 index 0000000..257f935 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AlertInfo.java @@ -0,0 +1,128 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +import gov.nist.javax.sip.address.*; +import javax.sip.address.*; + +/** + * AlertInfo SIP Header. + * + * @author M. Ranganathan <br/> + * + * @since 1.1 + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:25 $ + * + * + */ +public final class AlertInfo + extends ParametersHeader + implements javax.sip.header.AlertInfoHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 4159657362051508719L; + /** URI field + */ + protected GenericURI uri; + /** String field + */ + protected String string; + + /** Constructor + */ + public AlertInfo() { + super(NAME); + } + + /** + * Return value encoding in canonical form. + * @return The value of the header in canonical encoding. + */ + protected String encodeBody() { + StringBuffer encoding = new StringBuffer(); + if (uri != null) { + encoding.append(LESS_THAN).append(uri.encode()).append(GREATER_THAN); + } else if (string != null) { + encoding.append(string); + } + if (!parameters.isEmpty()) { + encoding.append(SEMICOLON).append(parameters.encode()); + } + return encoding.toString(); + } + + /** + * Set the uri member + * @param uri URI to set + */ + public void setAlertInfo(URI uri) { + this.uri = (GenericURI) uri; + } + + /** + * Set the string member + * @param string String to set + */ + public void setAlertInfo(String string) { + this.string = string; + } + + /** + * Returns the AlertInfo value of this AlertInfoHeader. + * @return the URI representing the AlertInfo. + */ + public URI getAlertInfo() { + URI alertInfoUri = null; + + if (this.uri != null) { + alertInfoUri = (URI) this.uri; + } else { + try { + alertInfoUri = (URI) new GenericURI(string); + } catch (ParseException e) { + ; // Eat the exception. + } + } + + return alertInfoUri; + } + + public Object clone() { + AlertInfo retval = (AlertInfo) super.clone(); + if (this.uri != null) { + retval.uri = (GenericURI) this.uri.clone(); + } else if (this.string != null) { + retval.string = this.string; + } + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/AlertInfoList.java b/java/gov/nist/javax/sip/header/AlertInfoList.java new file mode 100644 index 0000000..03a85ae --- /dev/null +++ b/java/gov/nist/javax/sip/header/AlertInfoList.java @@ -0,0 +1,59 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** +* AlertInfo SIPHeader - there can be several AlertInfo headers. +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public class AlertInfoList extends SIPHeaderList<AlertInfo> { + + + + private static final long serialVersionUID = 1L; + + + public Object clone() { + AlertInfoList retval = new AlertInfoList(); + retval.clonehlist(this.hlist); + return retval; + } + + + /** default constructor + */ + public AlertInfoList() { + super( AlertInfo.class,AlertInfoHeader.NAME); + } + + +} diff --git a/java/gov/nist/javax/sip/header/Allow.java b/java/gov/nist/javax/sip/header/Allow.java new file mode 100644 index 0000000..5502856 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Allow.java @@ -0,0 +1,90 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +/** + * Allow SIPHeader. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:26 $ + * @since 1.1 + * + * + */ +public final class Allow extends + SIPHeader implements javax.sip.header.AllowHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3105079479020693930L; + /** method field + */ + protected String method; + + /** default constructor + */ + public Allow() { + super(ALLOW); + } + + /** constructor + * @param m String to set + */ + public Allow(String m) { + super(ALLOW); + method = m; + } + + /** get the method field + * @return String + */ + public String getMethod() { + return method; + } + + /** + * Set the method member + * @param method method to set. + */ + public void setMethod(String method) throws ParseException { + if (method == null) + throw new NullPointerException( + "JAIN-SIP Exception" + + ", Allow, setMethod(), the method parameter is null."); + this.method = method; + } + + /** Return body encoded in canonical form. + * @return body encoded as a string. + */ + protected String encodeBody() { + return method; + } +} diff --git a/java/gov/nist/javax/sip/header/AllowEvents.java b/java/gov/nist/javax/sip/header/AllowEvents.java new file mode 100644 index 0000000..c50e427 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AllowEvents.java @@ -0,0 +1,100 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +/** + * AllowEvents SIPHeader. + * + * @author M. Ranganathan NIST/ITL ANTD. <br/> + * @author Olivier Deruelle <br/> + * + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $ + * @since 1.1 + */ +public final class AllowEvents + extends SIPHeader + implements javax.sip.header.AllowEventsHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 617962431813193114L; + /** method field + */ + protected String eventType; + + /** default constructor + */ + public AllowEvents() { + super(ALLOW_EVENTS); + } + + /** constructor + * @param m String to set + */ + public AllowEvents(String m) { + super(ALLOW_EVENTS); + eventType = m; + } + + /** + * Sets the eventType defined in this AllowEventsHeader. + * + * @param eventType - the String defining the method supported + * in this AllowEventsHeader + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the Strings defining the eventType supported + */ + public void setEventType(String eventType) throws ParseException { + if (eventType == null) + throw new NullPointerException( + "JAIN-SIP Exception," + + "AllowEvents, setEventType(), the eventType parameter is null"); + this.eventType = eventType; + } + + /** + * Gets the eventType of the AllowEventsHeader. + * + * @return the String object identifing the eventTypes of AllowEventsHeader. + */ + public String getEventType() { + return eventType; + } + + /** Return body encoded in canonical form. + * @return body encoded as a string. + */ + protected String encodeBody() { + return eventType; + } +} diff --git a/java/gov/nist/javax/sip/header/AllowEventsList.java b/java/gov/nist/javax/sip/header/AllowEventsList.java new file mode 100644 index 0000000..666267c --- /dev/null +++ b/java/gov/nist/javax/sip/header/AllowEventsList.java @@ -0,0 +1,111 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.*; +import java.text.ParseException; +import javax.sip.header.*; + +/** + * List of AllowEvents headers. + * The sip message can have multiple AllowEvents headers which are strung + * together in a list. + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $ + * @since 1.1 + * + */ +public class AllowEventsList extends SIPHeaderList<AllowEvents> { + + private static final long serialVersionUID = -684763195336212992L; + + public Object clone() { + AllowEventsList retval = new AllowEventsList(); + retval.clonehlist(this.hlist); + return retval; + } + + + /** default constructor + */ + public AllowEventsList() { + super(AllowEvents.class, AllowEventsHeader.NAME); + } + + /** + * Gets an Iterator of all the methods of the AllowEventsHeader. Returns an empty + * + * Iterator if no methods are defined in this AllowEvents Header. + * + * + * + * @return Iterator of String objects each identifing the methods of + * + * AllowEventsHeader. + * + * + */ + public ListIterator<String> getMethods() { + ListIterator<AllowEvents> li = super.hlist.listIterator(); + LinkedList<String> ll = new LinkedList<String> (); + while (li.hasNext()) { + AllowEvents allowEvents = (AllowEvents) li.next(); + ll.add(allowEvents.getEventType()); + } + return ll.listIterator(); + } + + /** + * Sets the methods supported defined by this AllowEventsHeader. + * + * + * + * @param methods - the Iterator of Strings defining the methods supported + * + * in this AllowEventsHeader + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the Strings defining the methods supported. + * + * + */ + public void setMethods(List<String> methods) throws ParseException { + ListIterator<String> it = methods.listIterator(); + while (it.hasNext()) { + AllowEvents allowEvents = new AllowEvents(); + allowEvents.setEventType((String) it.next()); + this.add(allowEvents); + } + } +} diff --git a/java/gov/nist/javax/sip/header/AllowList.java b/java/gov/nist/javax/sip/header/AllowList.java new file mode 100644 index 0000000..376f6d4 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AllowList.java @@ -0,0 +1,113 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.*; +import java.text.ParseException; +import javax.sip.header.*; + +/** + * List of ALLOW headers. The sip message can have multiple Allow headers + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $ + * @since 1.1 + * + */ +public class AllowList extends SIPHeaderList<Allow> { + + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4699795429662562358L; + + + public Object clone() { + AllowList retval = new AllowList(); + retval.clonehlist(this.hlist); + return retval; + } + + + /** default constructor + */ + public AllowList() { + super(Allow.class, AllowHeader.NAME); + } + + /** + * Gets an Iterator of all the methods of the AllowHeader. Returns an empty + * + * Iterator if no methods are defined in this Allow Header. + * + * + * + * @return Iterator of String objects each identifing the methods of + * + * AllowHeader. + * + * + */ + public ListIterator<String> getMethods() { + + LinkedList<String> ll = new LinkedList<String> (); + + for ( Iterator<Allow> it = this.hlist.iterator(); it.hasNext();) { + Allow a = (Allow)it.next(); + ll.add(a.getMethod()); + } + + return ll.listIterator(); + } + + /** + * Sets the methods supported defined by this AllowHeader. + * + * + * + * @param methods - the Iterator of Strings defining the methods supported + * + * in this AllowHeader + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the Strings defining the methods supported. + * + * + */ + public void setMethods(List<String> methods) throws ParseException { + ListIterator<String> it = methods.listIterator(); + while (it.hasNext()) { + Allow allow = new Allow(); + allow.setMethod((String) it.next()); + this.add(allow); + } + } +} diff --git a/java/gov/nist/javax/sip/header/AuthenticationHeader.java b/java/gov/nist/javax/sip/header/AuthenticationHeader.java new file mode 100644 index 0000000..760a03a --- /dev/null +++ b/java/gov/nist/javax/sip/header/AuthenticationHeader.java @@ -0,0 +1,553 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/***************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.*; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; + +import java.text.ParseException; + /* + * 2005/06/12: geir.hedemark@telio.no: Changed behaviour of qop parameter in + * Authorization header - removed quoting of string according to + * RFC3261, BNF element "message-qop" (as opposed to "qop-options", + * which is quoted. + */ + +/** + * The generic AuthenticationHeader + * + * @author Olivier Deruelle + * @author M. Ranganathan <br/> + * @since 1.1 + * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/18 13:46:32 $ + * + * + */ +public abstract class AuthenticationHeader extends ParametersHeader { + + public static final String DOMAIN = ParameterNames.DOMAIN; + + public static final String REALM = ParameterNames.REALM; + + public static final String OPAQUE = ParameterNames.OPAQUE; + + public static final String ALGORITHM = ParameterNames.ALGORITHM; + + public static final String QOP = ParameterNames.QOP; + + public static final String STALE = ParameterNames.STALE; + + public static final String SIGNATURE = ParameterNames.SIGNATURE; + + public static final String RESPONSE = ParameterNames.RESPONSE; + + public static final String SIGNED_BY = ParameterNames.SIGNED_BY; + + public static final String NC = ParameterNames.NC; + + public static final String URI = ParameterNames.URI; + + public static final String USERNAME = ParameterNames.USERNAME; + + public static final String CNONCE = ParameterNames.CNONCE; + + public static final String NONCE = ParameterNames.NONCE; + + public static final String IK = ParameterNamesIms.IK; + public static final String CK = ParameterNamesIms.CK; + public static final String INTEGRITY_PROTECTED = ParameterNamesIms.INTEGRITY_PROTECTED; + + protected String scheme; + + public AuthenticationHeader(String name) { + super(name); + parameters.setSeparator(Separators.COMMA); // oddball + this.scheme = ParameterNames.DIGEST; + } + + public AuthenticationHeader() { + super(); + parameters.setSeparator(Separators.COMMA); + } + + /** + * set the specified parameter. Bug reported by Dominic Sparks. + * + * @param name -- + * name of the parameter + * @param value -- + * value of the parameter. + */ + public void setParameter(String name, String value) throws ParseException { + NameValue nv = super.parameters.getNameValue(name.toLowerCase()); + if (nv == null) { + nv = new NameValue(name, value); + if (name.equalsIgnoreCase(ParameterNames.QOP) + || name.equalsIgnoreCase(ParameterNames.REALM) + || name.equalsIgnoreCase(ParameterNames.CNONCE) + || name.equalsIgnoreCase(ParameterNames.NONCE) + || name.equalsIgnoreCase(ParameterNames.USERNAME) + || name.equalsIgnoreCase(ParameterNames.DOMAIN) + || name.equalsIgnoreCase(ParameterNames.OPAQUE) + || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE) + || name.equalsIgnoreCase(ParameterNames.URI) + || name.equalsIgnoreCase(ParameterNames.RESPONSE ) + ||name.equalsIgnoreCase(ParameterNamesIms.IK) + || name.equalsIgnoreCase(ParameterNamesIms.CK) + || name.equalsIgnoreCase(ParameterNamesIms.INTEGRITY_PROTECTED)) { + if (((this instanceof Authorization) || (this instanceof ProxyAuthorization)) + && name.equalsIgnoreCase(ParameterNames.QOP)) { + // NOP, QOP not quoted in authorization headers + } else { + nv.setQuotedValue(); + } + if (value == null) + throw new NullPointerException("null value"); + if (value.startsWith(Separators.DOUBLE_QUOTE)) + throw new ParseException(value + + " : Unexpected DOUBLE_QUOTE", 0); + } + super.setParameter(nv); + } else + nv.setValueAsObject(value); + + } + + /** + * This is only used for the parser interface. + * + * @param challenge -- + * the challenge from which the parameters are extracted. + */ + public void setChallenge(Challenge challenge) { + this.scheme = challenge.scheme; + super.parameters = challenge.authParams; + } + + /** + * Encode in canonical form. + * + * @return canonical string. + */ + public String encodeBody() { + this.parameters.setSeparator(Separators.COMMA); + return this.scheme + SP + parameters.encode(); + } + + /** + * Sets the scheme of the challenge information for this + * AuthenticationHeaderHeader. For example, Digest. + * + * @param scheme - + * the new string value that identifies the challenge information + * scheme. + */ + public void setScheme(String scheme) { + this.scheme = scheme; + } + + /** + * Returns the scheme of the challenge information for this + * AuthenticationHeaderHeader. + * + * @return the string value of the challenge information. + */ + public String getScheme() { + return scheme; + } + + /** + * Sets the Realm of the WWWAuthenicateHeader to the <var>realm</var> + * parameter value. Realm strings MUST be globally unique. It is RECOMMENDED + * that a realm string contain a hostname or domain name. Realm strings + * SHOULD present a human-readable identifier that can be rendered to a + * user. + * + * @param realm + * the new Realm String of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the realm. + */ + public void setRealm(String realm) throws ParseException { + if (realm == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " AuthenticationHeader, setRealm(), The realm parameter is null"); + setParameter(ParameterNames.REALM, realm); + } + + /** + * Returns the Realm value of this WWWAuthenicateHeader. This convenience + * method returns only the realm of the complete Challenge. + * + * @return the String representing the Realm information, null if value is + * not set. + * @since v1.1 + */ + public String getRealm() { + return getParameter(ParameterNames.REALM); + } + + /** + * Sets the Nonce of the WWWAuthenicateHeader to the <var>nonce</var> + * parameter value. + * + * @param nonce - + * the new nonce String of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the nonce value. + * @since v1.1 + */ + public void setNonce(String nonce) throws ParseException { + if (nonce == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " AuthenticationHeader, setNonce(), The nonce parameter is null"); + setParameter(NONCE, nonce); + } + + /** + * Returns the Nonce value of this WWWAuthenicateHeader. + * + * @return the String representing the nonce information, null if value is + * not set. + * @since v1.1 + */ + public String getNonce() { + return getParameter(ParameterNames.NONCE); + } + + /** + * Sets the URI of the WWWAuthenicateHeader to the <var>uri</var> parameter + * value. + * + * @param uri - + * the new URI of this AuthenicationHeader. + * @since v1.1 + * + * Note that since 1.2 this is no longer applicable to the WWW-Authenticate + * and Proxy-Authenticate headers + */ + public void setURI(javax.sip.address.URI uri) { + if (uri != null) { + NameValue nv = new NameValue(ParameterNames.URI, uri); + nv.setQuotedValue(); + super.parameters.set(nv); + } else { + throw new NullPointerException("Null URI"); + } + } + + /** + * Returns the URI value of this WWWAuthenicateHeader, for example + * DigestURI. + * + * @return the URI representing the URI information, null if value is not + * set. + * @since v1.1 + * + * Note that since 1.2 this is no longer applicable to the WWW-Authenticate + * and Proxy-Authenticate headers + */ + public javax.sip.address.URI getURI() { + return getParameterAsURI(ParameterNames.URI); + } + + /** + * Sets the Algorithm of the WWWAuthenicateHeader to the new <var>algorithm</var> + * parameter value. + * + * @param algorithm - + * the new algorithm String of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the algorithm value. + * @since v1.1 + */ + public void setAlgorithm(String algorithm) throws ParseException { + if (algorithm == null) + throw new NullPointerException("null arg"); + setParameter(ParameterNames.ALGORITHM, algorithm); + } + + /** + * Returns the Algorithm value of this WWWAuthenicateHeader. + * + * @return the String representing the Algorithm information, null if the + * value is not set. + * @since v1.1 + */ + public String getAlgorithm() { + return getParameter(ParameterNames.ALGORITHM); + } + + /** + * Sets the Qop value of the WWWAuthenicateHeader to the new <var>qop</var> + * parameter value. + * + * @param qop - + * the new Qop string of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the Qop value. + * @since v1.1 + */ + public void setQop(String qop) throws ParseException { + if (qop == null) + throw new NullPointerException("null arg"); + setParameter(ParameterNames.QOP, qop); + } + + /** + * Returns the Qop value of this WWWAuthenicateHeader. + * + * @return the string representing the Qop information, null if the value is + * not set. + * @since v1.1 + */ + public String getQop() { + return getParameter(ParameterNames.QOP); + } + + /** + * Sets the Opaque value of the WWWAuthenicateHeader to the new <var>opaque</var> + * parameter value. + * + * @param opaque - + * the new Opaque string of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the opaque value. + * @since v1.1 + */ + public void setOpaque(String opaque) throws ParseException { + if (opaque == null) + throw new NullPointerException("null arg"); + setParameter(ParameterNames.OPAQUE, opaque); + } + + /** + * Returns the Opaque value of this WWWAuthenicateHeader. + * + * @return the String representing the Opaque information, null if the value + * is not set. + * @since v1.1 + */ + public String getOpaque() { + return getParameter(ParameterNames.OPAQUE); + } + + /** + * Sets the Domain of the WWWAuthenicateHeader to the <var>domain</var> + * parameter value. + * + * @param domain - + * the new Domain string of this WWWAuthenicateHeader. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the domain. + * @since v1.1 + */ + public void setDomain(String domain) throws ParseException { + if (domain == null) + throw new NullPointerException("null arg"); + setParameter(ParameterNames.DOMAIN, domain); + } + + /** + * Returns the Domain value of this WWWAuthenicateHeader. + * + * @return the String representing the Domain information, null if value is + * not set. + * @since v1.1 + */ + public String getDomain() { + return getParameter(ParameterNames.DOMAIN); + } + + /** + * Sets the value of the stale parameter of the WWWAuthenicateHeader to the + * <var>stale</var> parameter value. + * + * @param stale - + * the Boolean.valueOf value of the stale parameter. + * @since v1.1 + */ + public void setStale(boolean stale) { + setParameter(new NameValue(ParameterNames.STALE, Boolean.valueOf(stale))); + } + + /** + * Returns the boolean value of the state paramater of this + * WWWAuthenicateHeader. + * + * @return the boolean representing if the challenge is stale. + * @since v1.1 + */ + public boolean isStale() { + return this.getParameterAsBoolean(ParameterNames.STALE); + } + + /** + * Set the CNonce. + * + * @param cnonce -- + * a nonce string. + */ + public void setCNonce(String cnonce) throws ParseException { + this.setParameter(ParameterNames.CNONCE, cnonce); + } + + /** + * Get the CNonce. + * + * @return the cnonce value. + */ + public String getCNonce() { + return getParameter(ParameterNames.CNONCE); + } + + public int getNonceCount() { + return this.getParameterAsHexInt(ParameterNames.NC); + + } + + /** + * Set the nonce count pakrameter. Bug fix sent in by Andreas Bystr�m + */ + + public void setNonceCount(int param) throws java.text.ParseException { + if (param < 0) + throw new ParseException("bad value", 0); + + String nc = Integer.toHexString(param); + + String base = "00000000"; + nc = base.substring(0, 8 - nc.length()) + nc; + this.setParameter(ParameterNames.NC, nc); + + } + + /** + * Get the RESPONSE value (or null if it does not exist). + * + * @return String response parameter value. + */ + public String getResponse() { + return (String) getParameterValue(ParameterNames.RESPONSE); + } + + /** + * Set the Response. + * + * @param response + * to set. + */ + public void setResponse(String response) throws ParseException { + if (response == null) + throw new NullPointerException("Null parameter"); + // Bug fix from Andreas Bystr�m + this.setParameter(RESPONSE, response); + } + + /** + * Returns the Username value of this AuthorizationHeader. This convenience + * method returns only the username of the complete Response. + * + * @return the String representing the Username information, null if value + * is not set. + * + * + * + */ + public String getUsername() { + return (String) getParameter(ParameterNames.USERNAME); + } + + /** + * Sets the Username of the AuthorizationHeader to the <var>username</var> + * parameter value. + * + * @param username + * the new Username String of this AuthorizationHeader. + * + * @throws ParseException + * which signals that an error has been reached + * + * unexpectedly while parsing the username. + * + * + * + */ + public void setUsername(String username) throws ParseException { + this.setParameter(ParameterNames.USERNAME, username); + } + + public void setIK(String ik) throws ParseException { + if (ik == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " AuthenticationHeader, setIk(), The auth-param IK parameter is null"); + setParameter(IK, ik); + } + + public String getIK() { + return getParameter(ParameterNamesIms.IK); + } + + public void setCK(String ck) throws ParseException { + if (ck == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " AuthenticationHeader, setCk(), The auth-param CK parameter is null"); + setParameter(CK, ck); + } + + public String getCK() { + return getParameter(ParameterNamesIms.CK); + } + + + public void setIntegrityProtected(String integrityProtected) throws ParseException + { + if (integrityProtected == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " AuthenticationHeader, setIntegrityProtected(), The integrity-protected parameter is null"); + + setParameter(INTEGRITY_PROTECTED, integrityProtected); + } + + + + public String getIntegrityProtected() { + return getParameter(ParameterNamesIms.INTEGRITY_PROTECTED); + } + +} diff --git a/java/gov/nist/javax/sip/header/AuthenticationInfo.java b/java/gov/nist/javax/sip/header/AuthenticationInfo.java new file mode 100644 index 0000000..fadd7ba --- /dev/null +++ b/java/gov/nist/javax/sip/header/AuthenticationInfo.java @@ -0,0 +1,235 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +package gov.nist.javax.sip.header; + +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Authentication info SIP Header. + * + * @author M. Ranganathan NIST/ITL/ANTD + * @since 1.1 + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:27 $ + * + * + */ +public final class AuthenticationInfo + extends ParametersHeader + implements javax.sip.header.AuthenticationInfoHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4371927900917127057L; + + /** Default contstructor. + */ + public AuthenticationInfo() { + super(NAME); + parameters.setSeparator(COMMA); // Odd ball. + } + + public void add(NameValue nv) { + parameters.set(nv); + } + + /** Value of header encoded in canonical form. + */ + + protected String encodeBody() { + return parameters.encode(); + + } + + /** Get the name value pair for a given authentication info parameter. + * + *@param name is the name for which we want to retrieve the name value + * list. + */ + + public NameValue getAuthInfo(String name) { + return parameters.getNameValue(name); + } + + /** + * Returns the AuthenticationInfo value of this AuthenticationInfoHeader. + * + * + * + * @return the String representing the AuthenticationInfo + * + * + * + */ + public String getAuthenticationInfo() { + return this.encodeBody(); + } + + /** Returns the CNonce value of this AuthenticationInfoHeader. + * + * @return the String representing the cNonce information, null if value is + * not set. + * @since v1.1 + */ + public String getCNonce() { + return this.getParameter(ParameterNames.CNONCE); + } + + /** Returns the nextNonce value of this AuthenticationInfoHeader. + * + * @return the String representing the nextNonce + * information, null if value is not set. + * @since v1.1 + */ + public String getNextNonce() { + return this.getParameter(ParameterNames.NEXT_NONCE); + } + + /** Returns the Nonce Count value of this AuthenticationInfoHeader. + * + * @return the integer representing the nonceCount information, -1 if value is + * not set. + * @since v1.1 + */ + public int getNonceCount() { + return this.getParameterAsInt(ParameterNames.NONCE_COUNT); + } + + /** Returns the messageQop value of this AuthenticationInfoHeader. + * + * @return the string representing the messageQop information, null if the + * value is not set. + * @since v1.1 + */ + public String getQop() { + return this.getParameter(ParameterNames.QOP); + } + + /** Returns the Response value of this AuthenticationInfoHeader. + * + * @return the String representing the Response information. + * @since v1.1 + */ + public String getResponse() { + return this.getParameter(ParameterNames.RESPONSE_AUTH); + } + + /** Sets the CNonce of the AuthenticationInfoHeader to the <var>cNonce</var> + * parameter value. + * + * @param cNonce - the new cNonce String of this AuthenticationInfoHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the cNonce value. + * @since v1.1 + */ + public void setCNonce(String cNonce) throws ParseException { + this.setParameter(ParameterNames.CNONCE, cNonce); + } + + /** Sets the NextNonce of the AuthenticationInfoHeader to the <var>nextNonce</var> + * parameter value. + * + * @param nextNonce - the new nextNonce String of this AuthenticationInfoHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the nextNonce value. + * @since v1.1 + */ + public void setNextNonce(String nextNonce) throws ParseException { + this.setParameter(ParameterNames.NEXT_NONCE, nextNonce); + } + + /** Sets the Nonce Count of the AuthenticationInfoHeader to the <var>nonceCount</var> + * parameter value. + * + * @param nonceCount - the new nonceCount integer of this AuthenticationInfoHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the nonceCount value. + * @since v1.1 + */ + public void setNonceCount(int nonceCount) throws ParseException { + if (nonceCount < 0) + throw new ParseException("bad value", 0); + String nc = Integer.toHexString(nonceCount); + + String base = "00000000"; + nc = base.substring(0, 8 - nc.length()) + nc; + this.setParameter(ParameterNames.NC, nc); + } + + /** Sets the Qop value of the AuthenticationInfoHeader to the new + * <var>qop</var> parameter value. + * + * @param qop - the new Qop string of this AuthenticationInfoHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the Qop value. + * @since v1.1 + */ + public void setQop(String qop) throws ParseException { + this.setParameter(ParameterNames.QOP, qop); + } + + /** Sets the Response of the + * AuthenticationInfoHeader to the new <var>response</var> + * parameter value. + * + * @param response - the new response String of this + * AuthenticationInfoHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the Response. + * @since v1.1 + */ + public void setResponse(String response) throws ParseException { + this.setParameter(ParameterNames.RESPONSE_AUTH, response); + } + + public void setParameter(String name, String value) throws ParseException { + if (name == null) + throw new NullPointerException("null name"); + NameValue nv = super.parameters.getNameValue(name.toLowerCase()); + if (nv == null) { + nv = new NameValue(name, value); + if (name.equalsIgnoreCase(ParameterNames.QOP) + || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE) + || name.equalsIgnoreCase(ParameterNames.REALM) + || name.equalsIgnoreCase(ParameterNames.CNONCE) + || name.equalsIgnoreCase(ParameterNames.NONCE) + || name.equalsIgnoreCase(ParameterNames.OPAQUE) + || name.equalsIgnoreCase(ParameterNames.USERNAME) + || name.equalsIgnoreCase(ParameterNames.DOMAIN) + || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE) + || name.equalsIgnoreCase(ParameterNames.RESPONSE_AUTH)) { + if (value == null) + throw new NullPointerException("null value"); + if (value.startsWith(Separators.DOUBLE_QUOTE)) + throw new ParseException( + value + " : Unexpected DOUBLE_QUOTE", + 0); + nv.setQuotedValue(); + } + super.setParameter(nv); + } else + nv.setValueAsObject(value); + } +} diff --git a/java/gov/nist/javax/sip/header/AuthenticationInfoList.java b/java/gov/nist/javax/sip/header/AuthenticationInfoList.java new file mode 100644 index 0000000..01f24b3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/AuthenticationInfoList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + + +/** +* A list of AuthenticationInfo headers (there can be multiple in a message). +* +*@author M. Ranganathan <br/> +* +*/ +public class AuthenticationInfoList extends SIPHeaderList<AuthenticationInfo> { + + private static final long serialVersionUID = 1L; + + + public Object clone() { + AuthenticationInfoList retval = new AuthenticationInfoList(); + retval.clonehlist(this.hlist); + return retval; + } + + + /** Creates a new instance of AuthenticationList */ + public AuthenticationInfoList() { + super( AuthenticationInfo.class, AuthenticationInfoHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/Authorization.java b/java/gov/nist/javax/sip/header/Authorization.java new file mode 100644 index 0000000..636e4c9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Authorization.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.header.ims.AuthorizationHeaderIms; + +import javax.sip.header.*; + +/** + * Authorization SIP header. + * + * @see ProxyAuthorization + * + * @author M. Ranganathan NIST/ITL/ANTD <br/> + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:27 $ + * + * + */ +public class Authorization + extends gov.nist.javax.sip.header.AuthenticationHeader + implements javax.sip.header.AuthorizationHeader, AuthorizationHeaderIms { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -8897770321892281348L; + + /** Default constructor. + */ + public Authorization() { + super(AuthorizationHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/AuthorizationList.java b/java/gov/nist/javax/sip/header/AuthorizationList.java new file mode 100644 index 0000000..1f7b73b --- /dev/null +++ b/java/gov/nist/javax/sip/header/AuthorizationList.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +/** + * WWWAuthenticate SIPHeader (of which there can be several?) + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:27 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class AuthorizationList extends SIPHeaderList<Authorization> { + + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1L; + + + public Object clone() { + AuthorizationList retval = new AuthorizationList(); + retval.clonehlist(this.hlist); + return retval; + } + /** + * constructor. + */ + public AuthorizationList() { + super(Authorization.class, Authorization.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/CSeq.java b/java/gov/nist/javax/sip/header/CSeq.java new file mode 100644 index 0000000..3909b34 --- /dev/null +++ b/java/gov/nist/javax/sip/header/CSeq.java @@ -0,0 +1,184 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.message.SIPRequest; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.CSeqHeader; +import java.text.ParseException; + +/** + * CSeq SIP Header. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.10 $ $Date: 2009/10/18 13:46:33 $ + * @since 1.1 + * + */ + +public class CSeq extends SIPHeader implements javax.sip.header.CSeqHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -5405798080040422910L; + + /** + * seqno field + */ + protected Long seqno; + + /** + * method field + */ + protected String method; + + /** + * Constructor. + */ + public CSeq() { + super(CSEQ); + } + + /** + * Constructor given the sequence number and method. + * + * @param seqno is the sequence number to assign. + * @param method is the method string. + */ + public CSeq(long seqno, String method) { + this(); + this.seqno = Long.valueOf(seqno); + this.method = SIPRequest.getCannonicalName(method); + } + + /** + * Compare two cseq headers for equality. + * @param other Object to compare against. + * @return true if the two cseq headers are equals, false + * otherwise. + */ + public boolean equals(Object other) { + + if (other instanceof CSeqHeader) { + final CSeqHeader o = (CSeqHeader) other; + return this.getSeqNumber() == o.getSeqNumber() + && this.getMethod().equals( o.getMethod() ); + } + return false; + } + + /** + * Return canonical encoded header. + * @return String with canonical encoded header. + */ + public String encode() { + return headerName + COLON + SP + encodeBody() + NEWLINE; + } + + /** + * Return canonical header content. (encoded header except headerName:) + * + * @return encoded string. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + return buffer.append(seqno).append(SP).append(method.toUpperCase()); + } + + /** + * Get the method. + * @return String the method. + */ + public String getMethod() { + return method; + } + + /* + * (non-Javadoc) + * @see javax.sip.header.CSeqHeader#setSequenceNumber(long) + */ + public void setSeqNumber(long sequenceNumber) + throws InvalidArgumentException { + if (sequenceNumber < 0 ) + throw new InvalidArgumentException( + "JAIN-SIP Exception, CSeq, setSequenceNumber(), " + + "the sequence number parameter is < 0 : " + sequenceNumber); + else if ( sequenceNumber > ((long)1)<<32 - 1) + throw new InvalidArgumentException( + "JAIN-SIP Exception, CSeq, setSequenceNumber(), " + + "the sequence number parameter is too large : " + sequenceNumber); + + seqno = Long.valueOf(sequenceNumber); + } + + /** + * For backwards compatibility + */ + public void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException { + this.setSeqNumber( (long) sequenceNumber ); + } + + /* + * (non-Javadoc) + * @see javax.sip.header.CSeqHeader#setMethod(java.lang.String) + */ + public void setMethod(String meth) throws ParseException { + if (meth == null) + throw new NullPointerException( + "JAIN-SIP Exception, CSeq" + + ", setMethod(), the meth parameter is null"); + this.method = SIPRequest.getCannonicalName(meth); + } + + /* + * (non-Javadoc) + * @see javax.sip.header.CSeqHeader#getSequenceNumber() + */ + public int getSequenceNumber() { + if (this.seqno == null) + return 0; + else + return this.seqno.intValue(); + } + + + + + public long getSeqNumber() { + return this.seqno.longValue(); + } + + +} + diff --git a/java/gov/nist/javax/sip/header/CallID.java b/java/gov/nist/javax/sip/header/CallID.java new file mode 100644 index 0000000..2edae09 --- /dev/null +++ b/java/gov/nist/javax/sip/header/CallID.java @@ -0,0 +1,147 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.CallIdHeader; +import java.text.ParseException; + +/** + * Call ID SIPHeader. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:27 $ + * @since 1.1 + */ +public class CallID + extends SIPHeader + implements javax.sip.header.CallIdHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6463630258703731156L; + /** + * callIdentifier field + */ + protected CallIdentifier callIdentifier; + + /** + * Default constructor + */ + public CallID() { + super(NAME); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + * + * CallIDs are compared case-insensitively + */ + public boolean equals( Object other ) { + + if (this==other) return true; + + if (other instanceof CallIdHeader) { + final CallIdHeader o = (CallIdHeader) other; + return this.getCallId().equalsIgnoreCase( o.getCallId() ); + } + return false; + } + + + /** + * Encode the body part of this header (i.e. leave out the hdrName). + *@return String encoded body part of the header. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (callIdentifier != null) + callIdentifier.encode(buffer); + + return buffer; + } + + /** + * get the CallId field. This does the same thing as + * encodeBody + * @return String the encoded body part of the + */ + public String getCallId() { + return encodeBody(); + } + + /** + * get the call Identifer member. + * @return CallIdentifier + */ + public CallIdentifier getCallIdentifer() { + return callIdentifier; + } + + /** + * set the CallId field + * @param cid String to set. This is the body part of the Call-Id + * header. It must have the form localId@host or localId. + * @throws IllegalArgumentException if cid is null, not a token, or is + * not a token@token. + */ + public void setCallId(String cid) throws ParseException { + try { + callIdentifier = new CallIdentifier(cid); + } catch (IllegalArgumentException ex) { + throw new ParseException(cid, 0); + } + } + + /** + * Set the callIdentifier member. + * @param cid CallIdentifier to set (localId@host). + */ + public void setCallIdentifier(CallIdentifier cid) { + callIdentifier = cid; + } + + /** Constructor given the call Identifier. + *@param callId string call identifier (should be localid@host) + *@throws IllegalArgumentException if call identifier is bad. + */ + public CallID(String callId) throws IllegalArgumentException { + super(NAME); + this.callIdentifier = new CallIdentifier(callId); + } + + public Object clone() { + CallID retval = (CallID) super.clone(); + if (this.callIdentifier != null) + retval.callIdentifier = (CallIdentifier) this.callIdentifier.clone(); + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/CallIdentifier.java b/java/gov/nist/javax/sip/header/CallIdentifier.java new file mode 100644 index 0000000..86025b0 --- /dev/null +++ b/java/gov/nist/javax/sip/header/CallIdentifier.java @@ -0,0 +1,183 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +/** + * The call identifer that goes into a callID header and a in-reply-to header. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/12/16 02:38:35 $ + * @see CallID + * @see InReplyTo + * @since 1.1 + */ +public final class CallIdentifier extends SIPObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 7314773655675451377L; + + /** + * localId field + */ + protected String localId; + + /** + * host field + */ + protected String host; + + /** + * Default constructor + */ + public CallIdentifier() { + } + + /** + * Constructor + * @param localId id is the local id. + * @param host is the host. + */ + public CallIdentifier(String localId, String host) { + this.localId = localId; + this.host = host; + } + + /** + * constructor + * @param cid String to set + * @throws IllegalArgumentException if cid is null or is not a token, + * or token@token + */ + public CallIdentifier(String cid) throws IllegalArgumentException { + setCallID(cid); + } + + /** + * Get the encoded version of this id. + * @return String to set + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + buffer.append(localId); + if (host != null) { + buffer.append(AT).append(host); + } + return buffer; + } + + /** + * Compare two call identifiers for equality. + * @param other Object to set + * @return true if the two call identifiers are equals, false + * otherwise + */ + public boolean equals(Object other) { + if (other == null ) return false; + if (!other.getClass().equals(this.getClass())) { + return false; + } + CallIdentifier that = (CallIdentifier) other; + if (this.localId.compareTo(that.localId) != 0) { + return false; + } + if (this.host == that.host) + return true; + if ((this.host == null && that.host != null) + || (this.host != null && that.host == null)) + return false; + if (host.compareToIgnoreCase(that.host) != 0) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (this.localId == null ) { + throw new UnsupportedOperationException("Hash code called before id is set"); + } + return this.localId.hashCode(); + } + + /** get the LocalId field + * @return String + */ + public String getLocalId() { + return localId; + } + + /** get the host field + * @return host member String + */ + public String getHost() { + return host; + } + + /** + * Set the localId member + * @param localId String to set + */ + public void setLocalId(String localId) { + this.localId = localId; + } + + /** set the callId field + * @param cid Strimg to set + * @throws IllegalArgumentException if cid is null or is not a token or + * token@token + */ + public void setCallID(String cid) throws IllegalArgumentException { + if (cid == null) + throw new IllegalArgumentException("NULL!"); + int index = cid.indexOf('@'); + if (index == -1) { + localId = cid; + host = null; + } else { + localId = cid.substring(0, index); + host = cid.substring(index + 1, cid.length()); + if (localId == null || host == null) { + throw new IllegalArgumentException("CallID must be token@token or token"); + } + } + } + + /** + * Set the host member + * @param host String to set + */ + public void setHost(String host) { + this.host = host; + } +} diff --git a/java/gov/nist/javax/sip/header/CallInfo.java b/java/gov/nist/javax/sip/header/CallInfo.java new file mode 100644 index 0000000..7c9c539 --- /dev/null +++ b/java/gov/nist/javax/sip/header/CallInfo.java @@ -0,0 +1,123 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.javax.sip.address.*; +import java.text.ParseException; + +/** + * CallInfo SIPHeader. + * + * + * @author "M. Ranganathan" <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $ + * @since 1.1 + */ +public final class CallInfo + extends ParametersHeader + implements javax.sip.header.CallInfoHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -8179246487696752928L; + + protected GenericURI info; + + /** + * Default constructor + */ + public CallInfo() { + super(CALL_INFO); + } + + /** + * Return canonical representation. + * @return String + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + buffer.append(LESS_THAN); + info.encode(buffer); + buffer.append(GREATER_THAN); + + if (parameters != null && !parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + + return buffer; + } + + /** + * get the purpose field + * @return String + */ + public String getPurpose() { + return this.getParameter("purpose"); + } + + /** + * get the URI field + * @return URI + */ + public javax.sip.address.URI getInfo() { + return info; + } + + /** + * set the purpose field + * @param purpose is the purpose field. + */ + public void setPurpose(String purpose) { + if (purpose == null) + throw new NullPointerException("null arg"); + try { + this.setParameter("purpose", purpose); + } catch (ParseException ex) { + } + } + + /** + * set the URI field + * @param info is the URI to set. + */ + public void setInfo(javax.sip.address.URI info) { + this.info = (GenericURI) info; + } + + public Object clone() { + CallInfo retval = (CallInfo) super.clone(); + if (this.info != null) + retval.info = (GenericURI) this.info.clone(); + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/CallInfoList.java b/java/gov/nist/javax/sip/header/CallInfoList.java new file mode 100644 index 0000000..2d7e3e7 --- /dev/null +++ b/java/gov/nist/javax/sip/header/CallInfoList.java @@ -0,0 +1,59 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * A list of CallInfo headers (there can be multiple in a message). + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:28 $ + * @since 1.1 + * + */ +public class CallInfoList extends SIPHeaderList<CallInfo> { + + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4949850334388806423L; + + public Object clone() { + CallInfoList retval = new CallInfoList (); + retval.clonehlist(this.hlist); + return retval; + } + /** + * Default constructor + */ + public CallInfoList() { + super(CallInfo.class, CallInfoHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/Challenge.java b/java/gov/nist/javax/sip/header/Challenge.java new file mode 100644 index 0000000..a6078ca --- /dev/null +++ b/java/gov/nist/javax/sip/header/Challenge.java @@ -0,0 +1,257 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.*; + +/** + * Challenge part of the Auth header. This is only used by the parser interface + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $ + * @since 1.1 + * +*/ +public class Challenge extends SIPObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 5944455875924336L; + + private static String DOMAIN = ParameterNames.DOMAIN; + private static String REALM = ParameterNames.REALM; + private static String OPAQUE = ParameterNames.OPAQUE; + private static String ALGORITHM = ParameterNames.ALGORITHM; + private static String QOP = ParameterNames.QOP; + private static String STALE = ParameterNames.STALE; + private static String SIGNATURE = ParameterNames.SIGNATURE; + private static String RESPONSE = ParameterNames.RESPONSE; + private static String SIGNED_BY = ParameterNames.SIGNED_BY; + private static String URI = ParameterNames.URI; + + /** + * scheme field + */ + protected String scheme; + + /** + * authParms list + */ + protected NameValueList authParams; + + /** + * Default constructor + */ + public Challenge() { + authParams = new NameValueList(); + authParams.setSeparator(COMMA); + } + + /** + * Encode the challenge in canonical form. + * @return String + */ + public String encode() { + return new StringBuffer(scheme) + .append(SP) + .append(authParams.encode()) + .toString(); + } + + /** + * get the scheme field + * @return String + */ + public String getScheme() { + return scheme; + } + + /** + * get AuthParms list. + * @return NameValueList + */ + public NameValueList getAuthParams() { + return authParams; + } + + /** + * get the domain + * @return String + */ + public String getDomain() { + return (String) authParams.getValue(DOMAIN); + } + + /** + * get the URI field + * @return String + */ + public String getURI() { + return (String) authParams.getValue(URI); + } + + /** + * get the Opaque field + * @return String + */ + public String getOpaque() { + return (String) authParams.getValue(OPAQUE); + } + + /** + * get QOP value + * @return String + */ + public String getQOP() { + return (String) authParams.getValue(QOP); + } + + /** + * get the Algorithm value. + * @return String + */ + public String getAlgorithm() { + return (String) authParams.getValue(ALGORITHM); + } + + /** + * get the State value. + * @return String + */ + public String getStale() { + return (String) authParams.getValue(STALE); + } + + /** + * get the Signature value. + * @return String + */ + public String getSignature() { + return (String) authParams.getValue(SIGNATURE); + } + + /** + * get the signedBy value. + * @return String + */ + public String getSignedBy() { + return (String) authParams.getValue(SIGNED_BY); + } + + /** + * get the Response value. + * @return String + */ + public String getResponse() { + return (String) authParams.getValue(RESPONSE); + } + + /** + * get the realm value. + * @return String. + */ + public String getRealm() { + return (String) authParams.getValue(REALM); + } + + /** + * get the specified parameter + * @param name String to set + * @return String to set + */ + public String getParameter(String name) { + return (String) authParams.getValue(name); + } + + /** + * boolean function + * @param name String to set + * @return true if this header has the specified parameter, false otherwise. + */ + public boolean hasParameter(String name) { + return authParams.getNameValue(name) != null; + } + + /** + * Boolean function + * @return true if this header has some parameters. + */ + public boolean hasParameters() { + return authParams.size() != 0; + } + + /** + * delete the specified parameter + * @param name String + * @return true if the specified parameter has been removed, false + * otherwise. + */ + public boolean removeParameter(String name) { + return authParams.delete(name); + } + + /** + * remove all parameters + */ + public void removeParameters() { + authParams = new NameValueList(); + } + + /** + * set the specified parameter + * @param nv NameValue to set + */ + public void setParameter(NameValue nv) { + authParams.set(nv); + } + + /** + * Set the scheme member + * @param s String to set + */ + public void setScheme(String s) { + scheme = s; + } + + /** + * Set the authParams member + * @param a NameValueList to set + */ + public void setAuthParams(NameValueList a) { + authParams = a; + } + + public Object clone() { + Challenge retval = (Challenge) super.clone(); + if (this.authParams != null) + retval.authParams = (NameValueList) this.authParams.clone(); + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/Contact.java b/java/gov/nist/javax/sip/header/Contact.java new file mode 100644 index 0000000..1b3bf54 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Contact.java @@ -0,0 +1,293 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * Bug reports contributed by Joao Paulo, Stephen Jones, + * John Zeng and Alstair Cole. + * + */ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.NameValue; +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.address.AddressImpl; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.ContactHeader; +import java.text.ParseException; + +/** + * Contact Item. + * + * @see gov.nist.javax.sip.header.ContactList + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/18 13:46:31 $ + * @since 1.1 + * + * + */ +public final class Contact + extends AddressParametersHeader + implements javax.sip.header.ContactHeader { + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1677294871695706288L; + public static final String ACTION = ParameterNames.ACTION; + public static final String PROXY = ParameterNames.PROXY; + public static final String REDIRECT = ParameterNames.REDIRECT; + public static final String EXPIRES = ParameterNames.EXPIRES; + public static final String Q = ParameterNames.Q; + + // This must be private or the toString will go for a loop! + private ContactList contactList; + + /** wildCardFlag field. + */ + protected boolean wildCardFlag; + + /** Default constructor. + */ + public Contact() { + super(NAME); + } + + /** Set a parameter. + */ + public void setParameter(String name, String value) throws ParseException { + NameValue nv = parameters.getNameValue(name); + if (nv != null) { + nv.setValueAsObject(value); + } else { + nv = new NameValue(name, value); + if (name.equalsIgnoreCase("methods")) + nv.setQuotedValue(); + this.parameters.set(nv); + } + } + + /** + * Encode body of the header into a cannonical String. + * @return string encoding of the header value. + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (wildCardFlag) { + buffer.append('*'); + } + else { + // Bug report by Joao Paulo + if (address.getAddressType() == AddressImpl.NAME_ADDR) { + address.encode(buffer); + } else { + // Encoding in canonical form must have <> around address. + buffer.append('<'); + address.encode(buffer); + buffer.append('>'); + } + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + } + + return buffer; + } + + /** get the Contact list. + * @return ContactList + */ + public ContactList getContactList() { + return contactList; + } + + /** get the WildCardFlag field + * @return boolean + */ + public boolean getWildCardFlag() { + return wildCardFlag; + } + + /** get the address field. + * @return Address + */ + public javax.sip.address.Address getAddress() { + // JAIN-SIP stores the wild card as an address! + return address; + } + + /** get the parameters List + * @return NameValueList + */ + public NameValueList getContactParms() { + return parameters; + } + + /** get Expires parameter. + * @return the Expires parameter. + */ + public int getExpires() { + return getParameterAsInt(EXPIRES); + } + + /** Set the expiry time in seconds. + *@param expiryDeltaSeconds exipry time. + */ + + public void setExpires(int expiryDeltaSeconds) { + Integer deltaSeconds = Integer.valueOf(expiryDeltaSeconds); + this.parameters.set(EXPIRES, deltaSeconds); + } + + /** get the Q-value + * @return float + */ + public float getQValue() { + return getParameterAsFloat(Q); + } + + /** set the Contact List + * @param cl ContactList to set + */ + public void setContactList(ContactList cl) { + contactList = cl; + } + + /** + * Set the wildCardFlag member + * @param w boolean to set + */ + public void setWildCardFlag(boolean w) { + this.wildCardFlag = true; + this.address = new AddressImpl(); + this.address.setWildCardFlag(); + } + + /** + * Set the address member + * + * @param address Address to set + */ + public void setAddress(javax.sip.address.Address address) { + // Canonical form must have <> around the address. + if (address == null) + throw new NullPointerException("null address"); + this.address = (AddressImpl) address; + this.wildCardFlag = false; + } + + /** + * set the Q-value parameter + * @param qValue float to set + */ + public void setQValue(float qValue) throws InvalidArgumentException { + if (qValue != -1 && (qValue < 0 || qValue > 1)) + throw new InvalidArgumentException( + "JAIN-SIP Exception, Contact, setQValue(), " + + "the qValue is not between 0 and 1"); + this.parameters.set(Q, Float.valueOf(qValue)); + } + + public Object clone() { + Contact retval = (Contact) super.clone(); + if (this.contactList != null) + retval.contactList = (ContactList) this.contactList.clone(); + return retval; + } + + /* (non-Javadoc) + * @see javax.sip.header.ContactHeader#setWildCard() + */ + public void setWildCard() { + this.setWildCardFlag(true); + + } + + /* (non-Javadoc) + * @see javax.sip.header.ContactHeader#isWildCard() + */ + public boolean isWildCard() { + + return this.address.isWildcard(); + } + + public boolean equals(Object other) { + return (other instanceof ContactHeader) && super.equals(other); + } + + public void removeSipInstanceParam() { + if (parameters != null) + parameters.delete(ParameterNames.SIP_INSTANCE); + } + + public String getSipInstanceParam() { + return (String) parameters.getValue(ParameterNames.SIP_INSTANCE); + } + + public void setSipInstanceParam(String value) { + this.parameters.set(ParameterNames.SIP_INSTANCE, value); + } + + /** + *remove the pub-gruu value from the parameter list if it exists. + */ + public void removePubGruuParam() { + if (parameters != null) + parameters.delete(ParameterNames.PUB_GRUU); + } + + public String getPubGruuParam() { + return (String) parameters.getValue(ParameterNames.PUB_GRUU); + } + + public void setPubGruuParam(String value) + { + this.parameters.set(ParameterNames.PUB_GRUU, value); + } + + /** + *remove the pub-gruu value from the parameter list if it exists. + */ + public void removeTempGruuParam() { + if (parameters != null) + parameters.delete(ParameterNames.TEMP_GRUU); + } + + public String getTempGruuParam() { + return (String) parameters.getValue(ParameterNames.TEMP_GRUU); + } + + public void setTempGruuParam(String value) + { + this.parameters.set(ParameterNames.TEMP_GRUU, value); + } +} diff --git a/java/gov/nist/javax/sip/header/ContactList.java b/java/gov/nist/javax/sip/header/ContactList.java new file mode 100644 index 0000000..e9a5bf3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContactList.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +import java.util.ListIterator; + +/** + * List of contact headers.ContactLists are also maintained in a hashtable + * for quick lookup. + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $ + * @since 1.1 + */ +public class ContactList extends SIPHeaderList<Contact> { + + private static final long serialVersionUID = 1224806837758986814L; + + public Object clone() { + ContactList retval = new ContactList(); + retval.clonehlist(this.hlist); + return retval; + } + /** + * Constructor. + */ + public ContactList() { + super(Contact.class, ContactHeader.NAME); + + } + + + + +} diff --git a/java/gov/nist/javax/sip/header/ContentDisposition.java b/java/gov/nist/javax/sip/header/ContentDisposition.java new file mode 100644 index 0000000..ca3443e --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentDisposition.java @@ -0,0 +1,187 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.*; + +/** + * Content Dispositon SIP Header. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:29 $ + * @since 1.1 + * + */ +public final class ContentDisposition + extends ParametersHeader + implements javax.sip.header.ContentDispositionHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 835596496276127003L; + /** + * DispositionType field. + */ + protected String dispositionType; + + /** + * Default constructor. + */ + public ContentDisposition() { + super(NAME); + } + + /** + * Encode value of header into canonical string. + * @return encoded value of header. + * + */ + public String encodeBody() { + StringBuffer encoding = new StringBuffer(dispositionType); + if (!this.parameters.isEmpty()) { + encoding.append(SEMICOLON).append(parameters.encode()); + } + return encoding.toString(); + } + + /** + * Set the disposition type. + * @param dispositionType type. + */ + public void setDispositionType(String dispositionType) + throws ParseException { + if (dispositionType == null) + throw new NullPointerException( + "JAIN-SIP Exception" + + ", ContentDisposition, setDispositionType(), the dispositionType parameter is null"); + this.dispositionType = dispositionType; + } + + /** + * Get the disposition type. + * @return Disposition Type + */ + public String getDispositionType() { + return this.dispositionType; + } + + /** + * Get the dispositionType field. + * @return String + */ + public String getHandling() { + return this.getParameter("handling"); + } + + /** set the dispositionType field. + * @param handling String to set. + */ + public void setHandling(String handling) throws ParseException { + if (handling == null) + throw new NullPointerException( + "JAIN-SIP Exception" + + ", ContentDisposition, setHandling(), the handling parameter is null"); + this.setParameter("handling", handling); + } + + /** + * Gets the interpretation of the message body or message body part of + * this ContentDispositionHeader. + * + * @return interpretation of the message body or message body part + */ + public String getContentDisposition() { + return this.encodeBody(); + } +} +/* + * $Log: ContentDisposition.java,v $ + * Revision 1.5 2009/07/17 18:57:29 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:06 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:34 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ContentEncoding.java b/java/gov/nist/javax/sip/header/ContentEncoding.java new file mode 100644 index 0000000..13bdefa --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentEncoding.java @@ -0,0 +1,135 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +/** + * Content encoding part of a content encoding header list. + * @see ContentEncodingList + *<pre> + * From HTTP RFC 2616 + *14.11 Content-Encoding + * + * The Content-Encoding entity-header field is used as a modifier to the + * media-type. When present, its value indicates what additional content + * codings have been applied to the entity-body, and thus what decoding + * mechanisms must be applied in order to obtain the media-type + * referenced by the Content-Type header field. Content-Encoding is + * primarily used to allow a document to be compressed without losing + * the identity of its underlying media type. + * + * Content-Encoding = "Content-Encoding" ":" 1#content-coding + * + * Content codings are defined in section 3.5. An example of its use is + * + * Content-Encoding: gzip + * + * The content-coding is a characteristic of the entity identified by + * the Request-URI. Typically, the entity-body is stored with this + * encoding and is only decoded before rendering or analogous usage. + * However, a non-transparent proxy MAY modify the content-coding if the + * new coding is known to be acceptable to the recipient, unless the + * "no-transform" cache-control directive is present in the message. + * + * If the content-coding of an entity is not "identity", then the + * response MUST include a Content-Encoding entity-header (section + * 14.11) that lists the non-identity content-coding(s) used. + * + * If the content-coding of an entity in a request message is not + * acceptable to the origin server, the server SHOULD respond with a + * status code of 415 (Unsupported Media Type). + * + * If multiple encodings have been applied to an entity, the content + * codings MUST be listed in the order in which they were applied. + * Additional information about the encoding parameters MAY be provided + * by other entity-header fields not defined by this specification. + *</pre> + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:29 $ + * @since 1.1 + */ +public class ContentEncoding + extends SIPHeader + implements javax.sip.header.ContentEncodingHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 2034230276579558857L; + /** + * ContentEncoding field. + */ + protected String contentEncoding; + + /** + * Default constructor. + */ + public ContentEncoding() { + super(CONTENT_ENCODING); + } + + /** + * Constructor. + * @param enc String to set. + */ + public ContentEncoding(String enc) { + super(CONTENT_ENCODING); + contentEncoding = enc; + } + + /** + * Canonical encoding of body of the header. + * @return encoded body of the header. + */ + public String encodeBody() { + return contentEncoding; + } + + /** + * Get the ContentEncoding field. + * @return String + */ + public String getEncoding() { + return contentEncoding; + } + + /** + * Set the ConentEncoding field. + * @param encoding String to set + */ + public void setEncoding(String encoding) throws ParseException { + if (encoding == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + " encoding is null"); + contentEncoding = encoding; + } +} diff --git a/java/gov/nist/javax/sip/header/ContentEncodingList.java b/java/gov/nist/javax/sip/header/ContentEncodingList.java new file mode 100644 index 0000000..c5f6bbd --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentEncodingList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** +* Content Encoding SIP header List. Keeps a list of ContentEncoding headers. +* +*@author M. Rangananthan +*@version 1.2 +*@since 1.1 +*/ +public final class ContentEncodingList extends SIPHeaderList<ContentEncoding> { + + private static final long serialVersionUID = 7365216146576273970L; + + + public Object clone() { + ContentEncodingList retval = new ContentEncodingList(); + retval.clonehlist(this.hlist); + return retval; + } + + + /** Default constructor. + */ + public ContentEncodingList () { + super( ContentEncoding.class, + ContentEncodingHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/ContentLanguage.java b/java/gov/nist/javax/sip/header/ContentLanguage.java new file mode 100644 index 0000000..ddb0e55 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentLanguage.java @@ -0,0 +1,170 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.Locale; + +/** +* ContentLanguage header +* <pre> +*Fielding, et al. Standards Track [Page 118] +*RFC 2616 HTTP/1.1 June 1999 +* +* 14.12 Content-Language +* +* The Content-Language entity-header field describes the natural +* language(s) of the intended audience for the enclosed entity. Note +* that this might not be equivalent to all the languages used within +* the entity-body. +* +* Content-Language = "Content-Language" ":" 1#language-tag +* +* Language tags are defined in section 3.10. The primary purpose of +* Content-Language is to allow a user to identify and differentiate +* entities according to the user's own preferred language. Thus, if the +* body content is intended only for a Danish-literate audience, the +* appropriate field is +* +* Content-Language: da +* +* If no Content-Language is specified, the default is that the content +* is intended for all language audiences. This might mean that the +* sender does not consider it to be specific to any natural language, +* or that the sender does not know for which language it is intended. +* +* Multiple languages MAY be listed for content that is intended for +* multiple audiences. For example, a rendition of the "Treaty of +* Waitangi," presented simultaneously in the original Maori and English +* versions, would call for +* +* Content-Language: mi, en +* +* However, just because multiple languages are present within an entity +* does not mean that it is intended for multiple linguistic audiences. +* An example would be a beginner's language primer, such as "A First +* Lesson in Latin," which is clearly intended to be used by an +* English-literate audience. In this case, the Content-Language would +* properly only include "en". +* +* Content-Language MAY be applied to any media type -- it is not +* limited to textual documents. +*</pre> +* @author M. Ranganathan +* @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:29 $ +* @since 1.1 +*/ +public class ContentLanguage + extends SIPHeader + implements javax.sip.header.ContentLanguageHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -5195728427134181070L; + /** languageTag field. + */ + protected Locale locale; + + public ContentLanguage() { + super(CONTENT_LANGUAGE); + } + + /** + * Default constructor. + * @param languageTag String to set + */ + public ContentLanguage(String languageTag) { + super(CONTENT_LANGUAGE); + this.setLanguageTag( languageTag ); + } + + /** + * Canonical encoding of the value of the header. + * @return encoded body of header. + */ + public String encodeBody() { + return this.getLanguageTag(); + } + + /** get the languageTag field. + * @return String + */ + public String getLanguageTag() { + // JvB: Need to take sub-tags into account + if ( "".equals(locale.getCountry())) { + return locale.getLanguage(); + } else { + return locale.getLanguage() + '-' + locale.getCountry(); + } + } + + /** set the languageTag field + * @param languageTag -- language tag to set. + */ + public void setLanguageTag(String languageTag) { + + final int slash = languageTag.indexOf('-'); + if (slash>=0) { + this.locale = new Locale(languageTag.substring(0,slash), languageTag.substring(slash+1) ); + } else { + this.locale = new Locale(languageTag); + } + } + + /** + * Gets the language value of the ContentLanguageHeader. + * + * + * + * @return the Locale value of this ContentLanguageHeader + * + */ + public Locale getContentLanguage() { + return locale; + } + + /** + * Sets the language parameter of this ContentLanguageHeader. + * + * @param language - the new Locale value of the language of + * + * ContentLanguageHeader + * + */ + public void setContentLanguage(Locale language) { + this.locale = language; + } + + public Object clone() { + ContentLanguage retval = (ContentLanguage) super.clone(); + if (this.locale != null) + retval.locale = (Locale) this.locale.clone(); + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/ContentLanguageList.java b/java/gov/nist/javax/sip/header/ContentLanguageList.java new file mode 100644 index 0000000..c1563be --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentLanguageList.java @@ -0,0 +1,54 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** +* ContentLanguage list of headers. +* +*@since 1.1 +*@version 1.2 +*@author M. Ranganathan +*/ +public final class ContentLanguageList extends SIPHeaderList<ContentLanguage> { + + private static final long serialVersionUID = -5302265987802886465L; + public Object clone() { + ContentLanguageList retval = new ContentLanguageList(); + retval.clonehlist(this.hlist); + return retval; + } + /** Default constructor + */ + public ContentLanguageList () { + super(ContentLanguage.class, + ContentLanguageHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/ContentLength.java b/java/gov/nist/javax/sip/header/ContentLength.java new file mode 100644 index 0000000..fda74ac --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentLength.java @@ -0,0 +1,157 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.*; +import javax.sip.header.ContentLengthHeader; + +/** +* ContentLength SIPHeader (of which there can be only one in a SIPMessage). +*<pre> +*Fielding, et al. Standards Track [Page 119] +*RFC 2616 HTTP/1.1 June 1999 +* +* +* 14.13 Content-Length +* +* The Content-Length entity-header field indicates the size of the +* entity-body, in decimal number of OCTETs, sent to the recipient or, +* in the case of the HEAD method, the size of the entity-body that +* would have been sent had the request been a GET. +* +* Content-Length = "Content-Length" ":" 1*DIGIT +* +* An example is +* +* Content-Length: 3495 +* +* Applications SHOULD use this field to indicate the transfer-length of +* the message-body, unless this is prohibited by the rules in section +* 4.4. +* +* Any Content-Length greater than or equal to zero is a valid value. +* Section 4.4 describes how to determine the length of a message-body +* if a Content-Length is not given. +* +* Note that the meaning of this field is significantly different from +* the corresponding definition in MIME, where it is an optional field +* used within the "message/external-body" content-type. In HTTP, it +* SHOULD be sent whenever the message's length can be determined prior +* to being transferred, unless this is prohibited by the rules in +* section 4.4. +* </pre> +* +*@author M. Ranganathan <br/> +*@author Olivier Deruelle <br/> +*@version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:34 $ +*@since 1.1 +*/ +public class ContentLength + extends SIPHeader + implements javax.sip.header.ContentLengthHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1187190542411037027L; + /** + * contentLength field. + */ + protected Integer contentLength; + + /** + * Default constructor. + */ + public ContentLength() { + super(NAME); + } + + /** + * Constructor given a length. + */ + public ContentLength(int length) { + super(NAME); + this.contentLength = Integer.valueOf(length); + } + + /** + * get the ContentLength field. + * @return int + */ + public int getContentLength() { + return contentLength.intValue(); + } + + /** + * Set the contentLength member + * @param contentLength int to set + */ + public void setContentLength(int contentLength) + throws InvalidArgumentException { + if (contentLength < 0) + throw new InvalidArgumentException( + "JAIN-SIP Exception" + + ", ContentLength, setContentLength(), the contentLength parameter is <0"); + this.contentLength = Integer.valueOf(contentLength); + } + + /** + * Encode into a canonical string. + * @return String + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (contentLength == null) + buffer.append("0"); + else + buffer.append(contentLength.toString()); + return buffer; + } + + /** + * Pattern matcher ignores content length. + */ + public boolean match(Object other) { + if (other instanceof ContentLength) + return true; + else + return false; + } + + public boolean equals(Object other) { + if (other instanceof ContentLengthHeader) { + final ContentLengthHeader o = (ContentLengthHeader) other; + return this.getContentLength() == o.getContentLength(); + } + return false; + } +} diff --git a/java/gov/nist/javax/sip/header/ContentType.java b/java/gov/nist/javax/sip/header/ContentType.java new file mode 100644 index 0000000..522dd51 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ContentType.java @@ -0,0 +1,222 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.ContentTypeHeader; +import java.text.ParseException; + +/** +* ContentType SIP Header +* <pre> +*14.17 Content-Type +* +* The Content-Type entity-header field indicates the media type of the +* entity-body sent to the recipient or, in the case of the HEAD method, +* the media type that would have been sent had the request been a GET. +* +* Content-Type = "Content-Type" ":" media-type +* +* Media types are defined in section 3.7. An example of the field is +* +* Content-Type: text/html; charset=ISO-8859-4 +* +* Further discussion of methods for identifying the media type of an +* entity is provided in section 7.2.1. +* +* From HTTP RFC 2616 +* </pre> +* +* +*@version 1.2 +* +*@author M. Ranganathan <br/> +*@author Olivier Deruelle <br/> +*@version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:29 $ +*@since 1.1 +* +*/ +public class ContentType + extends ParametersHeader + implements javax.sip.header.ContentTypeHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 8475682204373446610L; + /** mediaRange field. + */ + protected MediaRange mediaRange; + + /** Default constructor. + */ + public ContentType() { + super(CONTENT_TYPE); + } + + /** Constructor given a content type and subtype. + *@param contentType is the content type. + *@param contentSubtype is the content subtype + */ + public ContentType(String contentType, String contentSubtype) { + this(); + this.setContentType(contentType, contentSubtype); + } + + /** compare two MediaRange headers. + * @param media String to set + * @return int. + */ + public int compareMediaRange(String media) { + return ( + mediaRange.type + "/" + mediaRange.subtype).compareToIgnoreCase( + media); + } + + /** + * Encode into a canonical string. + * @return String. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + mediaRange.encode(buffer); + if (hasParameters()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + return buffer; + } + + /** get the mediaRange field. + * @return MediaRange. + */ + public MediaRange getMediaRange() { + return mediaRange; + } + + /** get the Media Type. + * @return String. + */ + public String getMediaType() { + return mediaRange.type; + } + + /** get the MediaSubType field. + * @return String. + */ + public String getMediaSubType() { + return mediaRange.subtype; + } + + /** Get the content subtype. + *@return the content subtype string (or null if not set). + */ + public String getContentSubType() { + return mediaRange == null ? null : mediaRange.getSubtype(); + } + + /** Get the content subtype. + *@return the content tyep string (or null if not set). + */ + + public String getContentType() { + return mediaRange == null ? null : mediaRange.getType(); + } + + /** Get the charset parameter. + */ + public String getCharset() { + return this.getParameter("charset"); + } + + /** + * Set the mediaRange member + * @param m mediaRange field. + */ + public void setMediaRange(MediaRange m) { + mediaRange = m; + } + + /** + * set the content type and subtype. + *@param contentType Content type string. + *@param contentSubType content subtype string + */ + public void setContentType(String contentType, String contentSubType) { + if (mediaRange == null) + mediaRange = new MediaRange(); + mediaRange.setType(contentType); + mediaRange.setSubtype(contentSubType); + } + + /** + * set the content type. + *@param contentType Content type string. + */ + + public void setContentType(String contentType) throws ParseException { + if (contentType == null) + throw new NullPointerException("null arg"); + if (mediaRange == null) + mediaRange = new MediaRange(); + mediaRange.setType(contentType); + + } + + /** Set the content subtype. + * @param contentType String to set + */ + public void setContentSubType(String contentType) throws ParseException { + if (contentType == null) + throw new NullPointerException("null arg"); + if (mediaRange == null) + mediaRange = new MediaRange(); + mediaRange.setSubtype(contentType); + } + + public Object clone() { + ContentType retval = (ContentType) super.clone(); + if (this.mediaRange != null) + retval.mediaRange = (MediaRange) this.mediaRange.clone(); + return retval; + } + + public boolean equals(Object other) { + if (other instanceof ContentTypeHeader) { + final ContentTypeHeader o = (ContentTypeHeader) other; + return this.getContentType().equalsIgnoreCase( o.getContentType() ) + && this.getContentSubType().equalsIgnoreCase( o.getContentSubType() ) + && equalParameters( o ); + } + return false; + } +} + diff --git a/java/gov/nist/javax/sip/header/Credentials.java b/java/gov/nist/javax/sip/header/Credentials.java new file mode 100644 index 0000000..7935a95 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Credentials.java @@ -0,0 +1,135 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.core.*; + +/** + * Credentials that are used in authentication and authorization headers. + * @author M. Ranganathan + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:30 $ + * @since 1.1 + */ +public class Credentials extends SIPObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6335592791505451524L; + + private static String DOMAIN = ParameterNames.DOMAIN; + private static String REALM = ParameterNames.REALM; + private static String OPAQUE = ParameterNames.OPAQUE; + private static String RESPONSE = ParameterNames.RESPONSE; + private static String URI = ParameterNames.URI; + private static String NONCE = ParameterNames.NONCE; + private static String CNONCE = ParameterNames.CNONCE; + private static String USERNAME = ParameterNames.USERNAME; + + protected String scheme; + + /** + * parameters list. + */ + protected NameValueList parameters; + + /** + * Default constructor + */ + public Credentials() { + parameters = new NameValueList(); + parameters.setSeparator(COMMA); + } + + /** + * get the parameters list. + * @return NameValueList + */ + public NameValueList getCredentials() { + return parameters; + } + + /** + * get the scheme field. + * @return String. + */ + public String getScheme() { + return scheme; + } + + /** + * Set the scheme member + * @param s String to set + */ + public void setScheme(String s) { + scheme = s; + } + + /** + * Set the parameters member + * @param c NameValueList to set. + */ + public void setCredentials(NameValueList c) { + parameters = c; + } + + public String encode() { + String retval = scheme; + if (!parameters.isEmpty()) { + retval += SP + parameters.encode(); + } + return retval; + } + + /*public void setCredential(NameValue nameValue) { + if (nameValue.getName().compareToIgnoreCase(URI) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(NONCE) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(REALM) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(CNONCE) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(RESPONSE) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(OPAQUE) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(USERNAME) == 0) + nameValue.setQuotedValue(); + else if (nameValue.getName().compareToIgnoreCase(DOMAIN) == 0) + nameValue.setQuotedValue(); + parameters.set(nameValue); + }*/ + + public Object clone() { + Credentials retval = (Credentials) super.clone(); + if (this.parameters != null) + retval.parameters = (NameValueList) this.parameters.clone(); + return retval; + } +} diff --git a/java/gov/nist/javax/sip/header/ErrorInfo.java b/java/gov/nist/javax/sip/header/ErrorInfo.java new file mode 100644 index 0000000..4dbd7ee --- /dev/null +++ b/java/gov/nist/javax/sip/header/ErrorInfo.java @@ -0,0 +1,140 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.address.*; +import javax.sip.header.*; +import javax.sip.address.*; +import java.text.ParseException; + +/** + * ErrorInfo SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + */ +public final class ErrorInfo + extends ParametersHeader + implements ErrorInfoHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6347702901964436362L; + + protected GenericURI errorInfo; + + /** + * Default constructor. + */ + public ErrorInfo() { + super(NAME); + } + + /** + * Constructor given the error info + * @param errorInfo -- the error information to set. + */ + public ErrorInfo(GenericURI errorInfo) { + this(); + this.errorInfo = errorInfo; + } + + /** + * Encode into canonical form. + * @return String + */ + public String encodeBody() { + StringBuffer retval = + new StringBuffer(LESS_THAN).append(errorInfo.toString()).append( + GREATER_THAN); + if (!parameters.isEmpty()) { + retval.append(SEMICOLON).append(parameters.encode()); + } + return retval.toString(); + } + + /** + * Sets the ErrorInfo of the ErrorInfoHeader to the <var>errorInfo</var> + * parameter value. + * + * @param errorInfo the new ErrorInfo of this ErrorInfoHeader. + */ + public void setErrorInfo(javax.sip.address.URI errorInfo) { + this.errorInfo = (GenericURI) errorInfo; + + } + + /** + * Returns the ErrorInfo value of this ErrorInfoHeader. This message + * may return null if a String message identifies the ErrorInfo. + * + * @return the URI representing the ErrorInfo. + */ + public URI getErrorInfo() { + return errorInfo; + } + + /** + * Sets the Error information message to the new <var>message</var> value + * supplied to this method. + * + * @param message - the new string value that represents the error message. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the error message. + */ + public void setErrorMessage(String message) throws ParseException { + if (message == null) + throw new NullPointerException( + "JAIN-SIP Exception " + + ", ErrorInfoHeader, setErrorMessage(), the message parameter is null"); + setParameter("message", message); + } + + /** + * Get the Error information message of this ErrorInfoHeader. + * + * @return the stringified version of the ErrorInfo header. + */ + public String getErrorMessage() { + return getParameter("message"); + } + + public Object clone() { + ErrorInfo retval = (ErrorInfo) super.clone(); + if (this.errorInfo != null) + retval.errorInfo = (GenericURI) this.errorInfo.clone(); + return retval; + } +} + diff --git a/java/gov/nist/javax/sip/header/ErrorInfoList.java b/java/gov/nist/javax/sip/header/ErrorInfoList.java new file mode 100644 index 0000000..f7ed0e2 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ErrorInfoList.java @@ -0,0 +1,73 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** +* Error Info sip header. +* +*@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $ +* +*@author M. Ranganathan <br/> +*@since 1.1 +*@see ErrorInfoList +*<pre> +* +* 6.24 Error-Info +* +* The Error-Info response header provides a pointer to additional +* information about the error status response. This header field is +* only contained in 3xx, 4xx, 5xx and 6xx responses. +* +* +* +* Error-Info = "Error-Info" ":" # ( "<" URI ">" *( ";" generic-param )) +*</pre> +* +*/ +public class ErrorInfoList extends SIPHeaderList<ErrorInfo>{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + public Object clone() { + ErrorInfoList retval = new ErrorInfoList(); + retval.clonehlist(this.hlist); + return retval; + } + /** + * Default constructor. + */ + public ErrorInfoList() { + super(ErrorInfo.class, ErrorInfoHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/Event.java b/java/gov/nist/javax/sip/header/Event.java new file mode 100644 index 0000000..a949122 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Event.java @@ -0,0 +1,145 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.text.ParseException; + +/** +* Event SIP Header. +* +*@version 1.2 $Revision: 1.7 $ $Date: 2007/06/28 15:08:42 $ +*@since 1.1 +* +*@author M. Ranganathan <br/> +*@author Olivier Deruelle <br/> +* +* +*/ +public class Event extends ParametersHeader implements EventHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6458387810431874841L; + + protected String eventType; + + /** + * Creates a new instance of Event + */ + public Event() { + super(EVENT); + } + + /** + * Sets the eventType to the newly supplied eventType string. + * + * @param eventType - the new string defining the eventType supported + * in this EventHeader + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the eventType value. + */ + public void setEventType(String eventType) throws ParseException { + if (eventType == null) + throw new NullPointerException(" the eventType is null"); + this.eventType = eventType; + } + + /** + * Gets the eventType of the EventHeader. + * + * @return the string object identifing the eventType of EventHeader. + */ + public String getEventType() { + return eventType; + } + + /** + * Sets the id to the newly supplied <var>eventId</var> string. + * + * @param eventId - the new string defining the eventId of this EventHeader + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the eventId value. + */ + public void setEventId(String eventId) throws ParseException { + if (eventId == null) + throw new NullPointerException(" the eventId parameter is null"); + setParameter(ParameterNames.ID, eventId); + } + + /** + * Gets the id of the EventHeader. This method may return null if the + * "eventId" is not set. + * @return the string object identifing the eventId of EventHeader. + */ + public String getEventId() { + return getParameter(ParameterNames.ID); + } + + /** + * Encode in canonical form. + * @return String + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (eventType != null) + buffer.append(eventType); + + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + this.parameters.encode(buffer); + } + return buffer; + } + + /** + * Return true if the given event header matches the supplied one. + * + * @param matchTarget -- event header to match against. + */ + public boolean match(Event matchTarget) { + if (matchTarget.eventType == null && this.eventType != null) + return false; + else if (matchTarget.eventType != null && this.eventType == null) + return false; + else if (this.eventType == null && matchTarget.eventType == null) + return false; + else if (getEventId() == null && matchTarget.getEventId() != null) + return false; + else if (getEventId() != null && matchTarget.getEventId() == null) + return false; + return matchTarget.eventType.equalsIgnoreCase(this.eventType) + && ((this.getEventId() == matchTarget.getEventId()) + || this.getEventId().equalsIgnoreCase(matchTarget.getEventId())); + } +} diff --git a/java/gov/nist/javax/sip/header/Expires.java b/java/gov/nist/javax/sip/header/Expires.java new file mode 100644 index 0000000..3de70b9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Expires.java @@ -0,0 +1,105 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.*; + +/** + * Expires SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public class Expires + extends SIPHeader + implements javax.sip.header.ExpiresHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 3134344915465784267L; + + /** expires field + */ + protected int expires; + + /** default constructor + */ + public Expires() { + super(NAME); + } + + /** + * Return canonical form. + * @return String + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + return buffer.append(expires); + } + + /** + * Gets the expires value of the ExpiresHeader. This expires value is + * + * relative time. + * + * + * + * @return the expires value of the ExpiresHeader. + * + * + */ + public int getExpires() { + return expires; + } + + /** + * Sets the relative expires value of the ExpiresHeader. + * The expires value MUST be greater than zero and MUST be + * less than 2**31. + * + * @param expires - the new expires value of this ExpiresHeader + * + * @throws InvalidArgumentException if supplied value is less than zero. + * + * + */ + public void setExpires(int expires) throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad argument " + expires); + this.expires = expires; + } +} diff --git a/java/gov/nist/javax/sip/header/ExtensionHeaderImpl.java b/java/gov/nist/javax/sip/header/ExtensionHeaderImpl.java new file mode 100644 index 0000000..1f53514 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ExtensionHeaderImpl.java @@ -0,0 +1,123 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +/** + * A generic extension header for the stack. + * The input text of the header gets recorded here. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:30 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public class ExtensionHeaderImpl + extends SIPHeader + implements javax.sip.header.ExtensionHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -8693922839612081849L; + + protected String value; + + /** + * This was added to allow for automatic cloning of headers. + */ + public ExtensionHeaderImpl() { + } + + public ExtensionHeaderImpl(String headerName) { + super(headerName); + } + + /** + * Set the name of the header. + * @param headerName is the name of the header to set. + */ + + public void setName(String headerName) { + this.headerName = headerName; + } + + /** + * Set the value of the header. + */ + public void setValue(String value) { + this.value = value; + } + + /** + * Get the value of the extension header. + * @return the value of the extension header. + */ + public String getHeaderValue() { + if (this.value != null) { + return this.value; + } else { + String encodedHdr = null; + try { + // Bug fix submitted by Lamine Brahimi + encodedHdr = this.encode(); + } catch (Exception ex) { + return null; + } + StringBuffer buffer = new StringBuffer(encodedHdr); + while (buffer.length() > 0 && buffer.charAt(0) != ':') { + buffer.deleteCharAt(0); + } + buffer.deleteCharAt(0); + this.value = buffer.toString().trim(); + return this.value; + } + } + + /** + * Return the canonical encoding of this header. + */ + public String encode() { + return new StringBuffer(this.headerName) + .append(COLON) + .append(SP) + .append(this.value) + .append(NEWLINE) + .toString(); + } + + /** + * Return just the body of this header encoded (leaving out the + * name and the CRLF at the end). + */ + public String encodeBody() { + return this.getHeaderValue(); + } +} diff --git a/java/gov/nist/javax/sip/header/ExtensionHeaderList.java b/java/gov/nist/javax/sip/header/ExtensionHeaderList.java new file mode 100644 index 0000000..8966602 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ExtensionHeaderList.java @@ -0,0 +1,71 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.ListIterator; + +import javax.sip.header.ExtensionHeader; +import javax.sip.header.Header; + +/** + * A generic extension header list. + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:30 $ + * @since 1.1 + */ +public class ExtensionHeaderList extends SIPHeaderList<ExtensionHeaderImpl> { + + + + private static final long serialVersionUID = 4681326807149890197L; + + + public Object clone() { + ExtensionHeaderList retval = new ExtensionHeaderList(headerName); + retval.clonehlist(this.hlist); + return retval; + } + public ExtensionHeaderList(String hName) { + super( ExtensionHeaderImpl.class, hName); + } + + public ExtensionHeaderList() { + super(ExtensionHeaderImpl.class,null); + } + + + public String encode() { + StringBuffer retval = new StringBuffer(); + ListIterator<ExtensionHeaderImpl> it = this.listIterator(); + while(it.hasNext()) { + ExtensionHeaderImpl eh = (ExtensionHeaderImpl) it.next(); + retval.append(eh.encode()); + } + return retval.toString(); + } +} diff --git a/java/gov/nist/javax/sip/header/From.java b/java/gov/nist/javax/sip/header/From.java new file mode 100644 index 0000000..b50814d --- /dev/null +++ b/java/gov/nist/javax/sip/header/From.java @@ -0,0 +1,164 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.HostPort; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.parser.Parser; + +import javax.sip.header.FromHeader; +import java.text.ParseException; + +/** + * From SIP Header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:31 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public final class From + extends AddressParametersHeader + implements javax.sip.header.FromHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6312727234330643892L; + + /** Default constructor + */ + public From() { + super(NAME); + } + + /** Generate a FROM header from a TO header + */ + public From(To to) { + super(NAME); + address = to.address; + parameters = to.parameters; + } + + /** + * Encode the header content into a String. + * + * @return String + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(LESS_THAN); + } + address.encode(buffer); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(GREATER_THAN); + } + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + return buffer; + } + + /** + * Conveniance accessor function to get the hostPort field from the address. + * Warning -- this assumes that the embedded URI is a SipURL. + * + * @return hostport field + */ + public HostPort getHostPort() { + return address.getHostPort(); + } + + /** + * Get the display name from the address. + * @return Display name + */ + public String getDisplayName() { + return address.getDisplayName(); + } + + /** + * Get the tag parameter from the address parm list. + * @return tag field + */ + public String getTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.TAG); + } + + /** Boolean function + * @return true if the Tag exist + */ + public boolean hasTag() { + return hasParameter(ParameterNames.TAG); + } + + /** remove Tag member + */ + public void removeTag() { + parameters.delete(ParameterNames.TAG); + } + + /** + * Set the address member + * @param address Address to set + */ + public void setAddress(javax.sip.address.Address address) { + this.address = (AddressImpl) address; + } + + /** + * Set the tag member + * @param t tag to set. From tags are mandatory. + */ + public void setTag(String t) throws ParseException { + // JvB: check that it is a valid token + Parser.checkToken(t); + this.setParameter(ParameterNames.TAG, t); + } + + /** Get the user@host port string. + */ + public String getUserAtHostPort() { + return address.getUserAtHostPort(); + } + + public boolean equals(Object other) { + return (other instanceof FromHeader) && super.equals(other); + } + +} diff --git a/java/gov/nist/javax/sip/header/HeaderExt.java b/java/gov/nist/javax/sip/header/HeaderExt.java new file mode 100644 index 0000000..3e91338 --- /dev/null +++ b/java/gov/nist/javax/sip/header/HeaderExt.java @@ -0,0 +1,36 @@ +/* + * JBoss, Home of Professional Open Source + * This code has been contributed to the public domain by the author. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip.header; + +import javax.sip.header.Header; + +/** + * Extensions to the Header interface supported by the implementation and + * will be included in the next spec release. + * + * @author jean.deruelle@gmail.com + * + */ +public interface HeaderExt extends Header { + + /** + * Gets the header value (i.e. what follows the name:) as a string + * @return the header value (i.e. what follows the name:) + * @since 2.0 + */ + public String getValue(); +} diff --git a/java/gov/nist/javax/sip/header/HeaderFactoryExt.java b/java/gov/nist/javax/sip/header/HeaderFactoryExt.java new file mode 100644 index 0000000..95e141d --- /dev/null +++ b/java/gov/nist/javax/sip/header/HeaderFactoryExt.java @@ -0,0 +1,277 @@ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.extensions.JoinHeader; +import gov.nist.javax.sip.header.extensions.ReferredByHeader; +import gov.nist.javax.sip.header.extensions.ReplacesHeader; +import gov.nist.javax.sip.header.extensions.SessionExpiresHeader; +import gov.nist.javax.sip.header.ims.PAccessNetworkInfoHeader; +import gov.nist.javax.sip.header.ims.PAssertedIdentityHeader; +import gov.nist.javax.sip.header.ims.PAssertedServiceHeader; +import gov.nist.javax.sip.header.ims.PAssociatedURIHeader; +import gov.nist.javax.sip.header.ims.PCalledPartyIDHeader; +import gov.nist.javax.sip.header.ims.PChargingFunctionAddressesHeader; +import gov.nist.javax.sip.header.ims.PChargingVectorHeader; +import gov.nist.javax.sip.header.ims.PMediaAuthorizationHeader; +import gov.nist.javax.sip.header.ims.PPreferredIdentityHeader; +import gov.nist.javax.sip.header.ims.PPreferredServiceHeader; +import gov.nist.javax.sip.header.ims.PProfileKeyHeader; +import gov.nist.javax.sip.header.ims.PServedUserHeader; +import gov.nist.javax.sip.header.ims.PUserDatabaseHeader; +import gov.nist.javax.sip.header.ims.PVisitedNetworkIDHeader; +import gov.nist.javax.sip.header.ims.PathHeader; +import gov.nist.javax.sip.header.ims.PrivacyHeader; +import gov.nist.javax.sip.header.ims.SecurityClientHeader; +import gov.nist.javax.sip.header.ims.SecurityServerHeader; +import gov.nist.javax.sip.header.ims.SecurityVerifyHeader; +import gov.nist.javax.sip.header.ims.ServiceRouteHeader; + +import javax.sip.InvalidArgumentException; +import javax.sip.address.Address; +import javax.sip.header.Header; +import javax.sip.header.HeaderFactory; + +/** + * Header factory extensions. These will be included in the next release of + * JAIN-SIP. + * + * @since 2.0 + * + */ +public interface HeaderFactoryExt extends HeaderFactory { + + /** + * Create a RequestLine from a String + * @throws ParseException + */ + public SipRequestLine createRequestLine(String requestLine) throws ParseException; + + + /** + * Create a StatusLine from a String. + */ + public SipStatusLine createStatusLine(String statusLine) throws ParseException; + + + /** + * Create a ReferredBy Header. + * + * @param address -- + * address for the header. + * + */ + public ReferredByHeader createReferredByHeader(Address address); + + /** + * + * Create a Replaces header with a call Id, to and from tag. + * + * @param callId - + * the call id to use. + * @param toTag - + * the to tag to use. + * @param fromTag - + * the fromTag to use. + * + */ + public ReplacesHeader createReplacesHeader(String callId, String toTag, + String fromTag) throws ParseException; + + /** + * creates a P-Access-Network-Info header. + * + * @return newly created P-Access-Network-Info header + */ + public PAccessNetworkInfoHeader createPAccessNetworkInfoHeader(); + + /** + * P-Asserted-Identity header + * + * @param address - + * Address + * @return newly created P-Asserted-Identity header + * @throws ParseException + * @throws NullPointerException + */ + public PAssertedIdentityHeader createPAssertedIdentityHeader(Address address) + throws NullPointerException, ParseException; + + /** + * Creates a new P-Associated-URI header based on the supplied address + * + * @param assocURI - + * Address + * @return newly created P-Associated-URI header + * @throws NullPointerException + * if the supplied address is null + * @throws ParseException + */ + public PAssociatedURIHeader createPAssociatedURIHeader(Address assocURI); + + /** + * P-Called-Party-ID header + * + * @param address - + * Address + * @return newly created P-Called-Party-ID header + * @throws NullPointerException + * @throws ParseException + */ + public PCalledPartyIDHeader createPCalledPartyIDHeader(Address address); + + /** + * P-Charging-Function-Addresses header + * + * @return newly created P-Charging-Function-Addresses header + */ + public PChargingFunctionAddressesHeader createPChargingFunctionAddressesHeader(); + + /** + * P-Charging-Vector header + * + * @param icid - + * icid string + * @return newly created P-Charging-Vector header + * @throws NullPointerException + * @throws ParseException + */ + public PChargingVectorHeader createChargingVectorHeader(String icid) throws ParseException; + + /** + * P-Media-Authorization header + * @param token - token string + * @return newly created P-Media-Authorizarion header + * @throws InvalidArgumentException + * @throws ParseException + */ + public PMediaAuthorizationHeader createPMediaAuthorizationHeader(String token) + throws InvalidArgumentException, ParseException; + + /** + * P-Preferred-Identity header + * @param address - Address + * @return newly created P-Preferred-Identity header + * @throws NullPointerException + */ + public PPreferredIdentityHeader createPPreferredIdentityHeader(Address address); + + /** + * P-Visited-Network-ID header + * @return newly created P-Visited-Network-ID header + */ + public PVisitedNetworkIDHeader createPVisitedNetworkIDHeader(); + + /** + * PATH header + * @param address - Address + * @return newly created Path header + * @throws NullPointerException + * @throws ParseException + */ + public PathHeader createPathHeader(Address address); + + /** + * Privacy header + * @param privacyType - privacy type string + * @return newly created Privacy header + * @throws NullPointerException + */ + public PrivacyHeader createPrivacyHeader(String privacyType); + + + /** + * Service-Route header + * @param address - Address + * @return newly created Service-Route header + * @throws NullPointerException + */ + public ServiceRouteHeader createServiceRouteHeader(Address address); + + /** + * Security-Server header + * @return newly created Security-Server header + */ + public SecurityServerHeader createSecurityServerHeader(); + + /** + * Security-Client header + * @return newly created Security-Client header + */ + public SecurityClientHeader createSecurityClientHeader(); + + + /** + * Security-Verify header + * @return newly created Security-Verify header + */ + public SecurityVerifyHeader createSecurityVerifyHeader(); + + + /** + * Creates a new SessionExpiresHeader based on the newly supplied expires value. + * + * @param expires - the new integer value of the expires. + * @throws InvalidArgumentException if supplied expires is less + * than zero. + * @return the newly created SessionExpiresHeader object. + * + */ + public SessionExpiresHeader createSessionExpiresHeader(int expires) throws InvalidArgumentException ; + + /** + * + * Create a Join header with a call Id, to and from tag. + * + * @param callId - + * the call id to use. + * @param toTag - + * the to tag to use. + * @param fromTag - + * the fromTag to use. + * + */ + public JoinHeader createJoinHeader(String callId, String toTag, + String fromTag) throws ParseException; + + /** + * + * @return the newly created P-User-Database header + * @param the database name, that may be an IP:port or a domain name. + */ + public PUserDatabaseHeader createPUserDatabaseHeader(String databaseName); + + + /** + * + * @param address + * @return The newly created P-Profile-Key header + */ + public PProfileKeyHeader createPProfileKeyHeader(Address address); + + /** + * @param address of the served user. + * @return The newly created P-Served-User Header. + */ + public PServedUserHeader createPServedUserHeader(Address address); + + /** + * + * @return The newly created P-Preferred-Service Header. + */ + public PPreferredServiceHeader createPPreferredServiceHeader(); + + /** + * + * @return The newly created P-Asserted-Service Header. + */ + public PAssertedServiceHeader createPAssertedServiceHeader(); + + /** + * Create a header from a string. The string is assumed to be in the + * name:value format. The trailing CRLF (if any ) will be stripped + * before parsing this. The header should be a singleton. + */ + public Header createHeader(String header) throws ParseException; + +} diff --git a/java/gov/nist/javax/sip/header/HeaderFactoryImpl.java b/java/gov/nist/javax/sip/header/HeaderFactoryImpl.java new file mode 100644 index 0000000..a4e68c1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/HeaderFactoryImpl.java @@ -0,0 +1,1706 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.javax.sip.header.ims.*; /* IMS headers - issued by Miguel Freitas */ +import gov.nist.javax.sip.header.extensions.*; // extension headers - pmusgrave +import javax.sip.header.*; + +import gov.nist.javax.sip.parser.*; +import gov.nist.javax.sip.parser.extensions.ReferencesParser; + +import javax.sip.address.*; +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import java.util.*; +import gov.nist.javax.sip.address.*; + +/* +* This file contains enhancements contributed by Alexandre Silva Santos +* (PT-Inovacao) and Miguel Freitas +*/ + +/** Implementation of the JAIN SIP HeaderFactory +* +* @version 1.2 $Revision: 1.22 $ $Date: 2010/01/12 18:58:48 $ +* @since 1.1 +* +*@author M. Ranganathan <br/> +*@author Olivier Deruelle <br/> +* +* +*/ +public class HeaderFactoryImpl implements HeaderFactory , HeaderFactoryExt { + + /** + * Determines whether or not we should tolerate and strip address scope + * zones from IPv6 addresses. Address scope zones are sometimes returned + * at the end of IPv6 addresses generated by InetAddress.getHostAddress(). + * They are however not part of the SIP semantics so basically this method + * determines whether or not the parser should be stripping them (as + * opposed simply being blunt and throwing an exception). + */ + private boolean stripAddressScopeZones = false; + + /** + * Set pretty encoding on / off. + * This splits up via headers into multiple lines for readability ( better for + * debugging ). + * + */ + public void setPrettyEncoding(boolean flag) { + SIPHeaderList.setPrettyEncode(flag); + } + + /** + * Creates a new AcceptEncodingHeader based on the newly supplied encoding + * value. + * + * @param encoding - the new string containing the encoding value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the encoding value. + * @return the newly created AcceptEncodingHeader object. + */ + public AcceptEncodingHeader createAcceptEncodingHeader(String encoding) + throws ParseException { + if (encoding == null) + throw new NullPointerException("the encoding parameter is null"); + AcceptEncoding acceptEncoding = new AcceptEncoding(); + acceptEncoding.setEncoding(encoding); + return acceptEncoding; + } + + /** + * Creates a new AcceptHeader based on the newly supplied contentType and + * contentSubType values. + * + * @param contentType The new string content type value. + * @param contentSubType The new string content sub-type value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the content type or content subtype value. + * @return the newly created AcceptHeader object. + */ + public AcceptHeader createAcceptHeader( + String contentType, + String contentSubType) + throws ParseException { + if (contentType == null || contentSubType == null) + throw new NullPointerException("contentType or subtype is null "); + Accept accept = new Accept(); + accept.setContentType(contentType); + accept.setContentSubType(contentSubType); + + return accept; + } + + /** + * Creates a new AcceptLanguageHeader based on the newly supplied + * language value. + * + * @param language - the new Locale value of the language + * @return the newly created AcceptLanguageHeader object. + */ + public AcceptLanguageHeader createAcceptLanguageHeader(Locale language) { + if (language == null) + throw new NullPointerException("null arg"); + AcceptLanguage acceptLanguage = new AcceptLanguage(); + acceptLanguage.setAcceptLanguage(language); + + return acceptLanguage; + } + + /** + * Creates a new AlertInfoHeader based on the newly supplied alertInfo value. + * + * @param alertInfo - the new URI value of the alertInfo + * @return the newly created AlertInfoHeader object. + * @since v1.1 + */ + public AlertInfoHeader createAlertInfoHeader(URI alertInfo) { + if (alertInfo == null) + throw new NullPointerException("null arg alertInfo"); + AlertInfo a = new AlertInfo(); + a.setAlertInfo(alertInfo); + return a; + } + + /** + * Creates a new AllowEventsHeader based on the newly supplied event type + * value. + * + * @param eventType - the new string containing the eventType value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the eventType value. + * @return the newly created AllowEventsHeader object. + * @since v1.1 + */ + public AllowEventsHeader createAllowEventsHeader(String eventType) + throws ParseException { + if (eventType == null) + throw new NullPointerException("null arg eventType"); + AllowEvents allowEvents = new AllowEvents(); + allowEvents.setEventType(eventType); + return allowEvents; + } + + /** + * Creates a new AllowHeader based on the newly supplied method value. + * + * @param method - the new string containing the method value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the method value. + * @return the newly created AllowHeader object. + */ + public AllowHeader createAllowHeader(String method) throws ParseException { + if (method == null) + throw new NullPointerException("null arg method"); + Allow allow = new Allow(); + allow.setMethod(method); + + return allow; + } + + /** + * Creates a new AuthenticationInfoHeader based on the newly supplied + * response value. + * + * @param response - the new string value of the response. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the response value. + * @return the newly created AuthenticationInfoHeader object. + * @since v1.1 + */ + public AuthenticationInfoHeader createAuthenticationInfoHeader(String response) + throws ParseException { + if (response == null) + throw new NullPointerException("null arg response"); + AuthenticationInfo auth = new AuthenticationInfo(); + auth.setResponse(response); + + return auth; + } + + /** + * Creates a new AuthorizationHeader based on the newly supplied + * scheme value. + * + * @param scheme - the new string value of the scheme. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the scheme value. + * @return the newly created AuthorizationHeader object. + */ + public AuthorizationHeader createAuthorizationHeader(String scheme) + throws ParseException { + if (scheme == null) + throw new NullPointerException("null arg scheme "); + Authorization auth = new Authorization(); + auth.setScheme(scheme); + + return auth; + } + + /** + * Creates a new CSeqHeader based on the newly supplied sequence number and + * method values. + * + * @param sequenceNumber - the new integer value of the sequence number. + * @param method - the new string value of the method. + * @throws InvalidArgumentException if supplied sequence number is less + * than zero. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the method value. + * @return the newly created CSeqHeader object. + */ + public CSeqHeader createCSeqHeader( long sequenceNumber, String method) + throws ParseException, InvalidArgumentException { + if (sequenceNumber < 0) + throw new InvalidArgumentException("bad arg " + sequenceNumber); + if (method == null) + throw new NullPointerException("null arg method"); + CSeq cseq = new CSeq(); + cseq.setMethod(method); + cseq.setSeqNumber(sequenceNumber); + + return cseq; + } + + /** + * For backwards compatibility, also accept int + * @deprecated + */ + public CSeqHeader createCSeqHeader( int sequenceNumber, String method) + throws ParseException, InvalidArgumentException { + return this.createCSeqHeader( (long) sequenceNumber, method ); + } + + /** + * Creates a new CallIdHeader based on the newly supplied callId value. + * + * @param callId - the new string value of the call-id. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the callId value. + * @return the newly created CallIdHeader object. + */ + public CallIdHeader createCallIdHeader(String callId) + throws ParseException { + if (callId == null) + throw new NullPointerException("null arg callId"); + CallID c = new CallID(); + c.setCallId(callId); + return c; + } + + /** + * Creates a new CallInfoHeader based on the newly supplied callInfo value. + * + * @param callInfo The new string value of the callInfo. + * @return the newly created CallInfoHeader object. + */ + public CallInfoHeader createCallInfoHeader(URI callInfo) { + if (callInfo == null) + throw new NullPointerException("null arg callInfo"); + + CallInfo c = new CallInfo(); + c.setInfo(callInfo); + return c; + } + + /** + * Creates a new ContactHeader based on the newly supplied address value. + * + * @param address - the new Address value of the address. + * @return the newly created ContactHeader object. + */ + public ContactHeader createContactHeader(Address address) { + if (address == null) + throw new NullPointerException("null arg address"); + Contact contact = new Contact(); + contact.setAddress(address); + + return contact; + } + + /** + * Creates a new wildcard ContactHeader. This is used in Register requests + * to indicate to the server that it should remove all locations the + * at which the user is currently available. This implies that the + * following conditions are met: + * <ul> + * <li><code>ContactHeader.getAddress.getAddress.getUserInfo() == *;</code> + * <li><code>ContactHeader.getAddress.getAddress.isWildCard() == true;</code> + * <li><code>ContactHeader.getExpires() == 0;</code> + * </ul> + * + * @return the newly created wildcard ContactHeader. + */ + public ContactHeader createContactHeader() { + Contact contact = new Contact(); + contact.setWildCardFlag(true); + contact.setExpires(0); + + return contact; + } + + /** + * Creates a new ContentDispositionHeader based on the newly supplied + * contentDisposition value. + * + * @param contentDisposition - the new string value of the contentDisposition. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the contentDisposition value. + * @return the newly created ContentDispositionHeader object. + * @since v1.1 + */ + public ContentDispositionHeader createContentDispositionHeader(String contentDisposition) + throws ParseException { + if (contentDisposition == null) + throw new NullPointerException("null arg contentDisposition"); + ContentDisposition c = new ContentDisposition(); + c.setDispositionType(contentDisposition); + + return c; + } + + /** + * Creates a new ContentEncodingHeader based on the newly supplied encoding + * value. + * + * @param encoding - the new string containing the encoding value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the encoding value. + * @return the newly created ContentEncodingHeader object. + */ + public ContentEncodingHeader createContentEncodingHeader(String encoding) + throws ParseException { + if (encoding == null) + throw new NullPointerException("null encoding"); + ContentEncoding c = new ContentEncoding(); + c.setEncoding(encoding); + + return c; + } + + /** + * Creates a new ContentLanguageHeader based on the newly supplied + * contentLanguage value. + * + * @param contentLanguage - the new Locale value of the contentLanguage. + * @return the newly created ContentLanguageHeader object. + * @since v1.1 + */ + public ContentLanguageHeader createContentLanguageHeader(Locale contentLanguage) { + if (contentLanguage == null) + throw new NullPointerException("null arg contentLanguage"); + ContentLanguage c = new ContentLanguage(); + c.setContentLanguage(contentLanguage); + + return c; + } + + /** + * Creates a new CSeqHeader based on the newly supplied contentLength value. + * + * @param contentLength - the new integer value of the contentLength. + * @throws InvalidArgumentException if supplied contentLength is less + * than zero. + * @return the newly created ContentLengthHeader object. + */ + public ContentLengthHeader createContentLengthHeader(int contentLength) + throws InvalidArgumentException { + if (contentLength < 0) + throw new InvalidArgumentException("bad contentLength"); + ContentLength c = new ContentLength(); + c.setContentLength(contentLength); + + return c; + } + + /** + * Creates a new ContentTypeHeader based on the newly supplied contentType and + * contentSubType values. + * + * @param contentType - the new string content type value. + * @param contentSubType - the new string content sub-type value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the content type or content subtype value. + * @return the newly created ContentTypeHeader object. + */ + public ContentTypeHeader createContentTypeHeader( + String contentType, + String contentSubType) + throws ParseException { + if (contentType == null || contentSubType == null) + throw new NullPointerException("null contentType or subType"); + ContentType c = new ContentType(); + c.setContentType(contentType); + c.setContentSubType(contentSubType); + return c; + } + + /** + * Creates a new DateHeader based on the newly supplied date value. + * + * @param date - the new Calender value of the date. + * @return the newly created DateHeader object. + */ + public DateHeader createDateHeader(Calendar date) { + SIPDateHeader d = new SIPDateHeader(); + if (date == null) + throw new NullPointerException("null date"); + d.setDate(date); + + return d; + } + + /** + * Creates a new EventHeader based on the newly supplied eventType value. + * + * @param eventType - the new string value of the eventType. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the eventType value. + * @return the newly created EventHeader object. + * @since v1.1 + */ + public EventHeader createEventHeader(String eventType) + throws ParseException { + if (eventType == null) + throw new NullPointerException("null eventType"); + Event event = new Event(); + event.setEventType(eventType); + + return event; + } + + /** + * Creates a new ExpiresHeader based on the newly supplied expires value. + * + * @param expires - the new integer value of the expires. + * @throws InvalidArgumentException if supplied expires is less + * than zero. + * @return the newly created ExpiresHeader object. + */ + public ExpiresHeader createExpiresHeader(int expires) + throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad value " + expires); + Expires e = new Expires(); + e.setExpires(expires); + + return e; + } + + /** + * Creates a new ExtensionHeader based on the newly supplied name and + * value values. + * + * @param name - the new string name of the ExtensionHeader value. + * @param value - the new string value of the ExtensionHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the name or value values. + * @return the newly created ExtensionHeader object. + */ + public javax.sip.header.ExtensionHeader createExtensionHeader( + String name, + String value) + throws ParseException { + if (name == null) + throw new NullPointerException("bad name"); + + gov.nist.javax.sip.header.ExtensionHeaderImpl ext = + new gov.nist.javax.sip.header.ExtensionHeaderImpl(); + ext.setName(name); + ext.setValue(value); + + return ext; + } + + /** + * Creates a new FromHeader based on the newly supplied address and + * tag values. + * + * @param address - the new Address object of the address. + * @param tag - the new string value of the tag. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the tag value. + * @return the newly created FromHeader object. + */ + public FromHeader createFromHeader(Address address, String tag) + throws ParseException { + if (address == null) + throw new NullPointerException("null address arg"); + From from = new From(); + from.setAddress(address); + if (tag != null) + from.setTag(tag); + + return from; + } + + /** + * Creates a new InReplyToHeader based on the newly supplied callId + * value. + * + * @param callId - the new string containing the callId value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the callId value. + * @return the newly created InReplyToHeader object. + * @since v1.1 + */ + public InReplyToHeader createInReplyToHeader(String callId) + throws ParseException { + if (callId == null) + throw new NullPointerException("null callId arg"); + InReplyTo inReplyTo = new InReplyTo(); + inReplyTo.setCallId(callId); + + return inReplyTo; + } + /** + * Creates a new MaxForwardsHeader based on the newly + * supplied maxForwards value. + * + * @param maxForwards The new integer value of the maxForwards. + * @throws InvalidArgumentException if supplied maxForwards is less + * than zero or greater than 255. + * @return the newly created MaxForwardsHeader object. + */ + public MaxForwardsHeader createMaxForwardsHeader(int maxForwards) + throws InvalidArgumentException { + if (maxForwards < 0 || maxForwards > 255) + throw new InvalidArgumentException( + "bad maxForwards arg " + maxForwards); + MaxForwards m = new MaxForwards(); + m.setMaxForwards(maxForwards); + + return m; + } + + /** + * Creates a new MimeVersionHeader based on the newly + * supplied mimeVersion value. + * + * @param majorVersion - the new integer value of the majorVersion. + * @param minorVersion - the new integer value of the minorVersion. + * @throws InvalidArgumentException if supplied mimeVersion is less + * than zero. + * @return the newly created MimeVersionHeader object. + * @since v1.1 + */ + public MimeVersionHeader createMimeVersionHeader( + int majorVersion, + int minorVersion) + throws InvalidArgumentException { + if (majorVersion < 0 || minorVersion < 0) + throw new javax.sip.InvalidArgumentException( + "bad major/minor version"); + MimeVersion m = new MimeVersion(); + m.setMajorVersion(majorVersion); + m.setMinorVersion(minorVersion); + + return m; + } + + /** + * Creates a new MinExpiresHeader based on the newly supplied minExpires value. + * + * @param minExpires - the new integer value of the minExpires. + * @throws InvalidArgumentException if supplied minExpires is less + * than zero. + * @return the newly created MinExpiresHeader object. + * @since v1.1 + */ + public MinExpiresHeader createMinExpiresHeader(int minExpires) + throws InvalidArgumentException { + if (minExpires < 0) + throw new InvalidArgumentException("bad minExpires " + minExpires); + MinExpires min = new MinExpires(); + min.setExpires(minExpires); + + return min; + } + + /** + * Creates a new MinSEHeader based on the newly supplied expires value. + * + * @param expires - the new integer value of the expires. + * @throws InvalidArgumentException if supplied expires is less + * than zero. + * @return the newly created ExpiresHeader object. + * + * TODO: Once interfaces are in javax, change the type to MinSEHeader + * and add to HeaderFactory. - pmusgrave + * + * pmusgrave + */ + public ExtensionHeader createMinSEHeader(int expires) + throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad value " + expires); + MinSE e = new MinSE(); + e.setExpires(expires); + + return e; + } + + /** + * Creates a new OrganizationHeader based on the newly supplied + * organization value. + * + * @param organization - the new string value of the organization. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the organization value. + * @return the newly created OrganizationHeader object. + */ + public OrganizationHeader createOrganizationHeader(String organization) + throws ParseException { + if (organization == null) + throw new NullPointerException("bad organization arg"); + Organization o = new Organization(); + o.setOrganization(organization); + + return o; + } + + /** + * Creates a new PriorityHeader based on the newly supplied priority value. + * + * @param priority - the new string value of the priority. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the priority value. + * @return the newly created PriorityHeader object. + */ + public PriorityHeader createPriorityHeader(String priority) + throws ParseException { + if (priority == null) + throw new NullPointerException("bad priority arg"); + Priority p = new Priority(); + p.setPriority(priority); + + return p; + } + + /** + * Creates a new ProxyAuthenticateHeader based on the newly supplied + * scheme value. + * + * @param scheme - the new string value of the scheme. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the scheme value. + * @return the newly created ProxyAuthenticateHeader object. + */ + public ProxyAuthenticateHeader createProxyAuthenticateHeader(String scheme) + throws ParseException { + if (scheme == null) + throw new NullPointerException("bad scheme arg"); + ProxyAuthenticate p = new ProxyAuthenticate(); + p.setScheme(scheme); + + return p; + } + + /** + * Creates a new ProxyAuthorizationHeader based on the newly supplied + * scheme value. + * + * @param scheme - the new string value of the scheme. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the scheme value. + * @return the newly created ProxyAuthorizationHeader object. + */ + public ProxyAuthorizationHeader createProxyAuthorizationHeader(String scheme) + throws ParseException { + if (scheme == null) + throw new NullPointerException("bad scheme arg"); + ProxyAuthorization p = new ProxyAuthorization(); + p.setScheme(scheme); + + return p; + } + + /** + * Creates a new ProxyRequireHeader based on the newly supplied optionTag + * value. + * + * @param optionTag - the new string OptionTag value. + * @return the newly created ProxyRequireHeader object. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the optionTag value. + */ + public ProxyRequireHeader createProxyRequireHeader(String optionTag) + throws ParseException { + if (optionTag == null) + throw new NullPointerException("bad optionTag arg"); + ProxyRequire p = new ProxyRequire(); + p.setOptionTag(optionTag); + + return p; + } + + /** + * Creates a new RAckHeader based on the newly supplied rSeqNumber, + * cSeqNumber and method values. + * + * @param rSeqNumber - the new integer value of the rSeqNumber. + * @param cSeqNumber - the new integer value of the cSeqNumber. + * @param method - the new string value of the method. + * @throws InvalidArgumentException if supplied rSeqNumber or cSeqNumber is + * less than zero or greater than than 2**31-1. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the method value. + * @return the newly created RAckHeader object. + * @since v1.1 + */ + public RAckHeader createRAckHeader( + long rSeqNumber, + long cSeqNumber, + String method) + throws InvalidArgumentException, ParseException { + if (method == null) + throw new NullPointerException("Bad method"); + if (cSeqNumber < 0 || rSeqNumber < 0) + throw new InvalidArgumentException("bad cseq/rseq arg"); + RAck rack = new RAck(); + rack.setMethod(method); + rack.setCSequenceNumber(cSeqNumber); + rack.setRSequenceNumber(rSeqNumber); + + return rack; + } + + /** + * @deprecated + * @see javax.sip.header.HeaderFactory#createRAckHeader(int, int, java.lang.String) + */ + public RAckHeader createRAckHeader(int rSeqNumber, int cSeqNumber, String method) throws InvalidArgumentException, ParseException { + + return createRAckHeader((long)rSeqNumber, (long)cSeqNumber, method); + } + + + /** + * @deprecated + * @see javax.sip.header.HeaderFactory#createRSeqHeader(int) + */ + public RSeqHeader createRSeqHeader(int sequenceNumber) throws InvalidArgumentException { + + return createRSeqHeader((long) sequenceNumber) ; + } + + /** + * Creates a new RSeqHeader based on the newly supplied sequenceNumber value. + * + * @param sequenceNumber - the new integer value of the sequenceNumber. + * @throws InvalidArgumentException if supplied sequenceNumber is + * less than zero or greater than than 2**31-1. + * @return the newly created RSeqHeader object. + * @since v1.1 + */ + public RSeqHeader createRSeqHeader(long sequenceNumber) + throws InvalidArgumentException { + if (sequenceNumber < 0) + throw new InvalidArgumentException( + "invalid sequenceNumber arg " + sequenceNumber); + RSeq rseq = new RSeq(); + rseq.setSeqNumber(sequenceNumber); + + return rseq; + } + + /** + * Creates a new ReasonHeader based on the newly supplied reason value. + * + * @param protocol - the new string value of the protocol. + * @param cause - the new integer value of the cause. + * @param text - the new string value of the text. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the protocol, cause or text value. + * @return the newly created ReasonHeader object. + * @since v1.1 + */ + public ReasonHeader createReasonHeader( + String protocol, + int cause, + String text) + throws InvalidArgumentException, ParseException { + if (protocol == null) + throw new NullPointerException("bad protocol arg"); + if (cause < 0) + throw new InvalidArgumentException("bad cause"); + Reason reason = new Reason(); + reason.setProtocol(protocol); + reason.setCause(cause); + reason.setText(text); + + return reason; + } + + /** + * Creates a new RecordRouteHeader based on the newly supplied address value. + * + * @param address - the new Address object of the address. + * @return the newly created RecordRouteHeader object. + */ + public RecordRouteHeader createRecordRouteHeader(Address address) { + if ( address == null) throw new NullPointerException("Null argument!"); + RecordRoute recordRoute = new RecordRoute(); + recordRoute.setAddress(address); + + return recordRoute; + } + + /** + * Creates a new ReplyToHeader based on the newly supplied address value. + * + * @param address - the new Address object of the address. + * @return the newly created ReplyToHeader object. + * @since v1.1 + */ + public ReplyToHeader createReplyToHeader(Address address) { + if (address == null) + throw new NullPointerException("null address"); + ReplyTo replyTo = new ReplyTo(); + replyTo.setAddress(address); + + return replyTo; + } + + /** + * Creates a new RequireHeader based on the newly supplied optionTag + * value. + * + * @param optionTag - the new string value containing the optionTag value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the List of optionTag value. + * @return the newly created RequireHeader object. + */ + public RequireHeader createRequireHeader(String optionTag) + throws ParseException { + if (optionTag == null) + throw new NullPointerException("null optionTag"); + Require require = new Require(); + require.setOptionTag(optionTag); + + return require; + } + + /** + * Creates a new RetryAfterHeader based on the newly supplied retryAfter + * value. + * + * @param retryAfter - the new integer value of the retryAfter. + * @throws InvalidArgumentException if supplied retryAfter is less + * than zero. + * @return the newly created RetryAfterHeader object. + */ + public RetryAfterHeader createRetryAfterHeader(int retryAfter) + throws InvalidArgumentException { + if (retryAfter < 0) + throw new InvalidArgumentException("bad retryAfter arg"); + RetryAfter r = new RetryAfter(); + r.setRetryAfter(retryAfter); + + return r; + } + + /** + * Creates a new RouteHeader based on the newly supplied address value. + * + * @param address - the new Address object of the address. + * @return the newly created RouteHeader object. + */ + public RouteHeader createRouteHeader(Address address) { + if (address == null) + throw new NullPointerException("null address arg"); + Route route = new Route(); + route.setAddress(address); + + return route; + } + + /** + * Creates a new ServerHeader based on the newly supplied product value. + * + * @param product - the new list value of the product. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the product value. + * @return the newly created ServerHeader object. + */ + public ServerHeader createServerHeader(List product) + throws ParseException { + if (product == null) + throw new NullPointerException("null productList arg"); + Server server = new Server(); + server.setProduct(product); + + return server; + } + + /** + * Creates a new SubjectHeader based on the newly supplied subject value. + * + * @param subject - the new string value of the subject. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the subject value. + * @return the newly created SubjectHeader object. + */ + public SubjectHeader createSubjectHeader(String subject) + throws ParseException { + if (subject == null) + throw new NullPointerException("null subject arg"); + Subject s = new Subject(); + s.setSubject(subject); + + return s; + } + + /** + * Creates a new SubscriptionStateHeader based on the newly supplied + * subscriptionState value. + * + * @param subscriptionState - the new string value of the subscriptionState. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the subscriptionState value. + * @return the newly created SubscriptionStateHeader object. + * @since v1.1 + */ + public SubscriptionStateHeader createSubscriptionStateHeader(String subscriptionState) + throws ParseException { + if (subscriptionState == null) + throw new NullPointerException("null subscriptionState arg"); + SubscriptionState s = new SubscriptionState(); + s.setState(subscriptionState); + + return s; + } + + /** + * Creates a new SupportedHeader based on the newly supplied optionTag + * value. + * + * @param optionTag - the new string containing the optionTag value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the optionTag value. + * @return the newly created SupportedHeader object. + */ + public SupportedHeader createSupportedHeader(String optionTag) + throws ParseException { + if (optionTag == null) + throw new NullPointerException("null optionTag arg"); + Supported supported = new Supported(); + supported.setOptionTag(optionTag); + + return supported; + } + + /** + * Creates a new TimeStampHeader based on the newly supplied timeStamp value. + * + * @param timeStamp - the new float value of the timeStamp. + * @throws InvalidArgumentException if supplied timeStamp is less + * than zero. + * @return the newly created TimeStampHeader object. + */ + public TimeStampHeader createTimeStampHeader(float timeStamp) + throws InvalidArgumentException { + if (timeStamp < 0) + throw new IllegalArgumentException("illegal timeStamp"); + TimeStamp t = new TimeStamp(); + t.setTimeStamp(timeStamp); + + return t; + } + + /** + * Creates a new ToHeader based on the newly supplied address and + * tag values. + * + * @param address - the new Address object of the address. + * @param tag - the new string value of the tag. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the tag value. + * @return the newly created ToHeader object. + */ + public ToHeader createToHeader(Address address, String tag) + throws ParseException { + if (address == null) + throw new NullPointerException("null address"); + To to = new To(); + to.setAddress(address); + if (tag != null) + to.setTag(tag); + + return to; + } + + /** + * Creates a new UnsupportedHeader based on the newly supplied optionTag + * value. + * + * @param optionTag - the new string containing the optionTag value. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the List of optionTag value. + * @return the newly created UnsupportedHeader object. + */ + public UnsupportedHeader createUnsupportedHeader(String optionTag) + throws ParseException { + if (optionTag == null) + throw new NullPointerException(optionTag); + Unsupported unsupported = new Unsupported(); + unsupported.setOptionTag(optionTag); + + return unsupported; + } + + /** + * Creates a new UserAgentHeader based on the newly supplied product value. + * + * @param product - the new list value of the product. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the product value. + * @return the newly created UserAgentHeader object. + */ + public UserAgentHeader createUserAgentHeader(List product) + throws ParseException { + + if (product == null) + throw new NullPointerException("null user agent"); + UserAgent userAgent = new UserAgent(); + userAgent.setProduct(product); + + return userAgent; + } + + /** + * Creates a new ViaHeader based on the newly supplied uri and branch values. + * + * @param host the new host value of uri. + * @param port the new port value of uri. + * @param transport the new transport value of uri. + * @param branch the new string value of the branch. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the branch value. + * @return the newly created ViaHeader object. + */ + public ViaHeader createViaHeader( + String host, + int port, + String transport, + String branch) + throws ParseException, InvalidArgumentException { + // This should be changed. + if (host == null || transport == null) + throw new NullPointerException("null arg"); + Via via = new Via(); + if (branch != null) + via.setBranch(branch); + + // for supporting IPv6 addresses + if(host.indexOf(':') >= 0 + && host.indexOf('[') < 0) + { + //strip address scope zones if any + if(stripAddressScopeZones) + { + int zoneStart = host.indexOf('%'); + if(zoneStart != -1) + host = host.substring(0, zoneStart); + } + host = '[' + host + ']'; + } + + via.setHost(host); + via.setPort(port); + via.setTransport(transport); + + return via; + } + + /** + * Creates a new WWWAuthenticateHeader based on the newly supplied + * scheme value. + * + * @param scheme - the new string value of the scheme. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the scheme values. + * @return the newly created WWWAuthenticateHeader object. + */ + public WWWAuthenticateHeader createWWWAuthenticateHeader(String scheme) + throws ParseException { + if (scheme == null) + throw new NullPointerException("null scheme"); + WWWAuthenticate www = new WWWAuthenticate(); + www.setScheme(scheme); + + return www; + } + + /** + * Creates a new WarningHeader based on the newly supplied + * agent, code and comment values. + * + * @param agent - the new string value of the agent. + * @param code - the new boolean integer of the code. + * @param comment - the new string value of the comment. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the agent or comment values. + * @throws InvalidArgumentException if an invalid integer code is given for + * the WarningHeader. + * @return the newly created WarningHeader object. + */ + public WarningHeader createWarningHeader( + String agent, + int code, + String comment) + throws ParseException, InvalidArgumentException { + if (agent == null) + throw new NullPointerException("null arg"); + Warning warning = new Warning(); + warning.setAgent(agent); + warning.setCode(code); + warning.setText(comment); + + return warning; + } + + /** Creates a new ErrorInfoHeader based on the newly + * supplied errorInfo value. + * + * @param errorInfo - the new URI value of the errorInfo. + * @return the newly created ErrorInfoHeader object. + */ + public ErrorInfoHeader createErrorInfoHeader(URI errorInfo) { + if (errorInfo == null) + throw new NullPointerException("null arg"); + return new ErrorInfo((GenericURI) errorInfo); + } + + /** + * Create a header from the given header text. + * Header should not have the trailng crlf. + * @throws ParseException + */ + public javax.sip.header.Header createHeader(String headerText) throws ParseException { + StringMsgParser smp = new StringMsgParser(); + SIPHeader sipHeader = smp.parseSIPHeader(headerText.trim()); + if (sipHeader instanceof SIPHeaderList) { + if (((SIPHeaderList) sipHeader).size() > 1) { + throw new ParseException( + "Only singleton allowed " + headerText, + 0); + } else if (((SIPHeaderList) sipHeader).size() == 0) { + try { + return (Header) ((SIPHeaderList) sipHeader) + .getMyClass() + .newInstance(); + } catch (InstantiationException ex) { + ex.printStackTrace(); + return null; + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } + } else { + return (Header) ((SIPHeaderList) sipHeader).getFirst(); + } + } else { + return (Header) sipHeader; + } + + } + + /** Create and parse a header. + * + * @param headerName -- header name for the header to parse. + * @param headerValue -- header value for the header to parse. + * @throws ParseException + * @return the parsed sip header + */ + public javax.sip.header.Header createHeader( + String headerName, + String headerValue) + throws java.text.ParseException { + if (headerName == null) + throw new NullPointerException("header name is null"); + String hdrText = + new StringBuffer() + .append(headerName) + .append(":") + .append(headerValue) + .toString(); + return createHeader(hdrText); + + } + + /** Create and return a list of headers. + *@param headers -- list of headers. + *@throws ParseException -- if a parse exception occurs or a List + * of that type of header is not alowed. + *@return a List containing the headers. + */ + public java.util.List createHeaders(String headers) + throws java.text.ParseException { + if (headers == null) + throw new NullPointerException("null arg!"); + StringMsgParser smp = new StringMsgParser(); + SIPHeader shdr = smp.parseSIPHeader(headers); + if (shdr instanceof SIPHeaderList) + return (SIPHeaderList) shdr; + else + throw new ParseException( + "List of headers of this type is not allowed in a message", + 0); + } + + /** Create a ReferTo Header. + *@param address -- address for the header. + */ + public ReferToHeader createReferToHeader(Address address) { + if (address == null) + throw new NullPointerException("null address!"); + ReferTo referTo = new ReferTo(); + referTo.setAddress(address); + return referTo; + } + + /** Create a ReferredBy Header. + * + * pmusgrave + * + *@param address -- address for the header. + * + * TODO: Once interfaces are in javax, change the type to MinSEHeader + * and add to HeaderFactory. - pmusgrave + + */ + public ReferredByHeader createReferredByHeader(Address address) { + if (address == null) + throw new NullPointerException("null address!"); + ReferredBy referredBy = new ReferredBy(); + referredBy.setAddress(address); + return referredBy; + } + + /** + * Create a Replaces header with a call Id, to and from tag. + * + * TODO: Once interfaces are in javax, change the type to MinSEHeader + * and add to HeaderFactory. - pmusgrave + * pmusgrave + */ + public ReplacesHeader createReplacesHeader(String callId, String toTag, + String fromTag) throws ParseException + { + Replaces replaces = new Replaces(); + replaces.setCallId(callId); + replaces.setFromTag(fromTag); + replaces.setToTag(toTag); + + return replaces; + } + + /** + * Create a Join header with a call Id, to and from tag. + * + */ + public JoinHeader createJoinHeader(String callId, String toTag, + String fromTag) throws ParseException + { + Join join = new Join(); + join.setCallId(callId); + join.setFromTag(fromTag); + join.setToTag(toTag); + + return join; + } + + + /* + * (non-Javadoc) + * @see javax.sip.header.HeaderFactory#createSIPETagHeader(java.lang.String) + */ + public SIPETagHeader createSIPETagHeader(String etag) throws ParseException { + return new SIPETag(etag); + } + + /* + * (non-Javadoc) + * @see javax.sip.header.HeaderFactory#createSIPIfMatchHeader(java.lang.String) + */ + public SIPIfMatchHeader createSIPIfMatchHeader(String etag) throws ParseException { + return new SIPIfMatch(etag); + } + + ////////////////////////////////////////////////////////////////////////// + // The following headers are not part of the JSIP spec. + // They are IMS headers + // (contributed by Miguel Freitas - PT Inovacao and Telecommunications Institute) + /////////////////////////////////////////////////////////////////////////// + + /** + * creates a P-Access-Network-Info header + * @return newly created P-Access-Network-Info header + */ + public PAccessNetworkInfoHeader createPAccessNetworkInfoHeader() + { + PAccessNetworkInfo accessNetworkInfo = new PAccessNetworkInfo(); + + return accessNetworkInfo; + } + + + /** + * P-Asserted-Identity header + * @param address - Address + * @return newly created P-Asserted-Identity header + * @throws ParseException + * @throws NullPointerException + */ + public PAssertedIdentityHeader createPAssertedIdentityHeader(Address address) + throws NullPointerException, ParseException + { + if (address == null) + throw new NullPointerException("null address!"); + + PAssertedIdentity assertedIdentity = new PAssertedIdentity(); + assertedIdentity.setAddress(address); + + return assertedIdentity; + + + } + + + /** + * Creates a new P-Associated-URI header based on the supplied address + * @param assocURI - Address + * @return newly created P-Associated-URI header + * @throws NullPointerException if the supplied address is null + * @throws ParseException + */ + public PAssociatedURIHeader createPAssociatedURIHeader(Address assocURI) + { + if (assocURI == null) + throw new NullPointerException("null associatedURI!"); + + PAssociatedURI associatedURI = new PAssociatedURI(); + associatedURI.setAddress(assocURI); + + return associatedURI; + } + + + + + /** + * P-Called-Party-ID header + * @param address - Address + * @return newly created P-Called-Party-ID header + * @throws NullPointerException + * @throws ParseException + */ + public PCalledPartyIDHeader createPCalledPartyIDHeader(Address address) + { + if (address == null) + throw new NullPointerException("null address!"); + + PCalledPartyID calledPartyID = new PCalledPartyID(); + calledPartyID.setAddress(address); + + return calledPartyID; + } + + + + /** + * P-Charging-Function-Addresses header + * @return newly created P-Charging-Function-Addresses header + */ + public PChargingFunctionAddressesHeader createPChargingFunctionAddressesHeader() + { + PChargingFunctionAddresses cfa = new PChargingFunctionAddresses(); + + return cfa; + } + + + /** + * P-Charging-Vector header + * @param icid - icid string + * @return newly created P-Charging-Vector header + * @throws NullPointerException + * @throws ParseException + */ + public PChargingVectorHeader createChargingVectorHeader(String icid) + throws ParseException + { + if (icid == null) + throw new NullPointerException("null icid arg!"); + + PChargingVector chargingVector = new PChargingVector(); + chargingVector.setICID(icid); + + return chargingVector; + + } + + + /** + * P-Media-Authorization header + * @param token - token string + * @return newly created P-Media-Authorizarion header + * @throws InvalidArgumentException + * @throws ParseException + */ + public PMediaAuthorizationHeader createPMediaAuthorizationHeader(String token) + throws InvalidArgumentException, ParseException + { + if (token == null || token == "") + throw new InvalidArgumentException("The Media-Authorization-Token parameter is null or empty"); + + + PMediaAuthorization mediaAuthorization = new PMediaAuthorization(); + mediaAuthorization.setMediaAuthorizationToken(token); + + return mediaAuthorization; + } + + + /** + * P-Preferred-Identity header + * @param address - Address + * @return newly created P-Preferred-Identity header + * @throws NullPointerException + */ + public PPreferredIdentityHeader createPPreferredIdentityHeader(Address address) + { + if (address == null) + throw new NullPointerException("null address!"); + + PPreferredIdentity preferredIdentity = new PPreferredIdentity(); + preferredIdentity.setAddress(address); + + return preferredIdentity; + + } + + /** + * P-Visited-Network-ID header + * @return newly created P-Visited-Network-ID header + */ + public PVisitedNetworkIDHeader createPVisitedNetworkIDHeader() + { + PVisitedNetworkID visitedNetworkID = new PVisitedNetworkID(); + + return visitedNetworkID; + } + + + + /** + * PATH header + * @param address - Address + * @return newly created Path header + * @throws NullPointerException + * @throws ParseException + */ + public PathHeader createPathHeader(Address address) + { + if (address == null) + throw new NullPointerException("null address!"); + + + Path path = new Path(); + path.setAddress(address); + + return path; + } + + + /** + * Privacy header + * @param privacyType - privacy type string + * @return newly created Privacy header + * @throws NullPointerException + */ + public PrivacyHeader createPrivacyHeader(String privacyType) + { + if (privacyType == null) + throw new NullPointerException("null privacyType arg"); + + Privacy privacy = new Privacy(privacyType); + + return privacy; + + } + + + /** + * Service-Route header + * @param address - Address + * @return newly created Service-Route header + * @throws NullPointerException + */ + public ServiceRouteHeader createServiceRouteHeader(Address address) + { + if (address == null) + throw new NullPointerException("null address!"); + + ServiceRoute serviceRoute = new ServiceRoute(); + serviceRoute.setAddress(address); + + return serviceRoute; + + } + + /** + * Security-Server header + * @return newly created Security-Server header + */ + public SecurityServerHeader createSecurityServerHeader() + { + SecurityServer secServer = new SecurityServer(); + return secServer; + } + + /** + * Security-Client header + * @return newly created Security-Client header + */ + public SecurityClientHeader createSecurityClientHeader() + { + SecurityClient secClient = new SecurityClient(); + return secClient; + } + + /** + * Security-Verify header + * @return newly created Security-Verify header + */ + public SecurityVerifyHeader createSecurityVerifyHeader() + { + SecurityVerify secVerify = new SecurityVerify(); + return secVerify; + } + + /** + * @return the newly create P-User-Database header. + * Please note that this is not a SIP/TEL uri. It is a + * DIAMETER AAA URI. + */ + public PUserDatabaseHeader createPUserDatabaseHeader(String databaseName) + { + if((databaseName ==null)||(databaseName.equals(" "))) + throw new NullPointerException("Database name is null"); + + PUserDatabase pUserDatabase = new PUserDatabase(); + pUserDatabase.setDatabaseName(databaseName); + + return pUserDatabase; + } + + + /** + * + * @return The newly created P-Profile-Key header. + * + */ + public PProfileKeyHeader createPProfileKeyHeader(Address address) + { + if (address ==null) + throw new NullPointerException("Address is null"); + PProfileKey pProfileKey = new PProfileKey(); + pProfileKey.setAddress(address); + + return pProfileKey; + } + + /** + * + * @return The newly created P-Served-User header. + */ + public PServedUserHeader createPServedUserHeader(Address address) + { + if(address==null) + throw new NullPointerException("Address is null"); + PServedUser psu = new PServedUser(); + psu.setAddress(address); + + return psu; + } + /** + * @return The newly created P-Preferred-Service header. + */ + public PPreferredServiceHeader createPPreferredServiceHeader() + { + PPreferredService pps = new PPreferredService(); + return pps; + } + + /** + * + * @return The newly created P-Asserted-Service header. + */ + public PAssertedServiceHeader createPAssertedServiceHeader() + { + PAssertedService pas = new PAssertedService(); + return pas; + } + + /** + * Creates a new SessionExpiresHeader based on the newly supplied expires value. + * + * @param expires - the new integer value of the expires. + * @throws InvalidArgumentException if supplied expires is less + * than zero. + * @return the newly created SessionExpiresHeader object. + * + */ + public SessionExpiresHeader createSessionExpiresHeader(int expires) + throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad value " + expires); + SessionExpires s = new SessionExpires(); + s.setExpires(expires); + + return s; + } + + + /** + * Create a new Request Line from a String. + * + */ + public SipRequestLine createRequestLine(String requestLine) throws ParseException { + + RequestLineParser requestLineParser = new RequestLineParser(requestLine); + return (SipRequestLine) requestLineParser.parse(); + } + + /** + * Create a new StatusLine from a String. + */ + public SipStatusLine createStatusLine(String statusLine) throws ParseException { + StatusLineParser statusLineParser = new StatusLineParser(statusLine); + return (SipStatusLine) statusLineParser.parse(); + } + + + + /** + * Create and return a references header. + * + * @param callId + * @param rel + * @return + * @throws ParseException + */ + + public ReferencesHeader createReferencesHeader(String callId, String rel) throws ParseException { + ReferencesHeader retval = new References(); + retval.setCallId(callId); + retval.setRel(rel); + return retval; + } + + + + + ////////////////////////////////////////////////////////// + // Constructor + ////////////////////////////////////////////////////////// + /** + * Default constructor. + */ + public HeaderFactoryImpl() { + stripAddressScopeZones + = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES"); + } + + + + + +} diff --git a/java/gov/nist/javax/sip/header/InReplyTo.java b/java/gov/nist/javax/sip/header/InReplyTo.java new file mode 100644 index 0000000..f11b668 --- /dev/null +++ b/java/gov/nist/javax/sip/header/InReplyTo.java @@ -0,0 +1,110 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.text.ParseException; + +/** + * InReplyTo SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + */ +public class InReplyTo extends SIPHeader implements InReplyToHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1682602905733508890L; + + protected CallIdentifier callId; + + /** Default constructor + */ + public InReplyTo() { + super(IN_REPLY_TO); + } + + /** constructor + * @param cid CallIdentifier to set + */ + public InReplyTo(CallIdentifier cid) { + super(IN_REPLY_TO); + callId = cid; + } + + /** + * Sets the Call-Id of the InReplyToHeader. The CallId parameter uniquely + * identifies a serious of messages within a dialogue. + * + * @param callId - the string value of the Call-Id of this InReplyToHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the callId value. + */ + public void setCallId(String callId) throws ParseException { + try { + this.callId = new CallIdentifier(callId); + } catch (Exception e) { + throw new ParseException(e.getMessage(), 0); + } + } + + /** + * Returns the Call-Id of InReplyToHeader. The CallId parameter uniquely + * identifies a series of messages within a dialogue. + * + * @return the String value of the Call-Id of this InReplyToHeader + */ + public String getCallId() { + if (callId == null) + return null; + return callId.encode(); + } + + /** + * Generate canonical form of the header. + * @return String + */ + public String encodeBody() { + return callId.encode(); + } + + public Object clone() { + InReplyTo retval = (InReplyTo) super.clone(); + if (this.callId != null) + retval.callId = (CallIdentifier) this.callId.clone(); + return retval; + } +} + diff --git a/java/gov/nist/javax/sip/header/InReplyToList.java b/java/gov/nist/javax/sip/header/InReplyToList.java new file mode 100644 index 0000000..cc69db9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/InReplyToList.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** +* In-Reply-To SIP header. Keeps a list of InReplyToHeader +* +* @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $ +* @since 1.1 +* +*@author M. Ranganathan <br/> +* +* +* +*/ +public final class InReplyToList extends SIPHeaderList<InReplyTo> { + + + private static final long serialVersionUID = -7993498496830999237L; + + public Object clone() { + InReplyToList retval = new InReplyToList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default constructor + */ + public InReplyToList() { + super(InReplyTo.class, InReplyToHeader.NAME); + } + +} diff --git a/java/gov/nist/javax/sip/header/Indentation.java b/java/gov/nist/javax/sip/header/Indentation.java new file mode 100644 index 0000000..5d11f8e --- /dev/null +++ b/java/gov/nist/javax/sip/header/Indentation.java @@ -0,0 +1,103 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +/** + * Internal utility class for pretty printing and header formatting. + * + * @author M. Ranganathan + * @author O. Deruelle + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $ + */ +class Indentation { + + private int indentation; + + /** + * Default constructor + */ + protected Indentation() { + indentation = 0; + } + + /** + * Constructor + * + * @param initval + * int to set + */ + protected Indentation(int initval) { + indentation = initval; + } + + /** + * set the indentation field + * + * @param initval + * int to set + */ + protected void setIndentation(int initval) { + indentation = initval; + } + + /** + * get the number of indentation. + * + * @return int + */ + protected int getCount() { + return indentation; + } + + /** + * increment the indentation field + */ + protected void increment() { + indentation++; + } + + /** + * decrement the indentation field + */ + protected void decrement() { + indentation--; + } + + /** + * get the indentation + * + * @return String + */ + protected String getIndentation() { + char[] chars = new char[indentation]; + java.util.Arrays.fill(chars, ' '); + return new String(chars); + } + +} + diff --git a/java/gov/nist/javax/sip/header/MaxForwards.java b/java/gov/nist/javax/sip/header/MaxForwards.java new file mode 100644 index 0000000..8e24afd --- /dev/null +++ b/java/gov/nist/javax/sip/header/MaxForwards.java @@ -0,0 +1,118 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; +import javax.sip.InvalidArgumentException; + +/** + * MaxForwards SIPHeader + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:32 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + */ +public class MaxForwards extends SIPHeader implements MaxForwardsHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3096874323347175943L; + /** maxForwards field. + */ + protected int maxForwards; + + /** Default constructor. + */ + public MaxForwards() { + super(NAME); + } + + public MaxForwards( int m ) throws InvalidArgumentException { + super(NAME); + this.setMaxForwards( m ); + } + + /** get the MaxForwards field. + * @return the maxForwards member. + */ + public int getMaxForwards() { + return maxForwards; + } + + /** + * Set the maxForwards member + * @param maxForwards maxForwards parameter to set + */ + public void setMaxForwards(int maxForwards) + throws InvalidArgumentException { + if (maxForwards < 0 || maxForwards > 255) + throw new InvalidArgumentException( + "bad max forwards value " + maxForwards); + this.maxForwards = maxForwards; + } + + /** + * Encode into a string. + * @return encoded string. + * + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + return buffer.append(maxForwards); + } + + /** Boolean function + * @return true if MaxForwards field reached zero. + */ + public boolean hasReachedZero() { + return maxForwards == 0; + } + + /** decrement MaxForwards field one by one. + */ + public void decrementMaxForwards() throws TooManyHopsException { + if (maxForwards > 0) + maxForwards--; + else throw new TooManyHopsException ("has already reached 0!"); + } + + public boolean equals(Object other) { + if (this==other) return true; + if (other instanceof MaxForwardsHeader) { + final MaxForwardsHeader o = (MaxForwardsHeader) other; + return this.getMaxForwards() == o.getMaxForwards(); + } + return false; + } +} diff --git a/java/gov/nist/javax/sip/header/MediaRange.java b/java/gov/nist/javax/sip/header/MediaRange.java new file mode 100644 index 0000000..c96c362 --- /dev/null +++ b/java/gov/nist/javax/sip/header/MediaRange.java @@ -0,0 +1,117 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +* See ../../../../doc/uncopyright.html for conditions of use. * +* Author: M. Ranganathan (mranga@nist.gov) * +* Modified By: O. Deruelle (deruelle@nist.gov) * +* Questions/Comments: nist-sip-dev@antd.nist.gov * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +/** +* Media Range +* @see Accept +* @since 0.9 +* @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:32 $ +* <pre> +* Revisions: +* +* Version 1.0 +* 1. Added encode method. +* +* media-range = ( "STAR/STAR" +* | ( type "/" STAR ) +* | ( type "/" subtype ) +* ) *( ";" parameter ) +* +* HTTP RFC 2616 Section 14.1 +* </pre> +*/ +public class MediaRange extends SIPObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6297125815438079210L; + + /** type field + */ + protected String type; + + /** subtype field + */ + protected String subtype; + + /** Default constructor + */ + public MediaRange() { + } + + /** get type field + * @return String + */ + public String getType() { + return type; + } + + /** get the subType field. + * @return String + */ + public String getSubtype() { + return subtype; + } + + /** + * Set the type member + * @param t String to set + */ + public void setType(String t) { + type = t; + } + + /** + * Set the subtype member + * @param s String to set + */ + public void setSubtype(String s) { + subtype = s; + } + + /** + * Encode the object. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + return buffer.append(type) + .append(SLASH) + .append(subtype); + } +} diff --git a/java/gov/nist/javax/sip/header/MimeVersion.java b/java/gov/nist/javax/sip/header/MimeVersion.java new file mode 100644 index 0000000..dee7528 --- /dev/null +++ b/java/gov/nist/javax/sip/header/MimeVersion.java @@ -0,0 +1,201 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.*; + +/** + * MimeVersion SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/10/18 13:46:35 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + */ +public class MimeVersion extends SIPHeader implements MimeVersionHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -7951589626435082068L; + + /** + * mimeVersion field + */ + protected int minorVersion; + + /** + * majorVersion field + */ + protected int majorVersion; + + /** + * Default constructor + */ + public MimeVersion() { + super(MIME_VERSION); + } + + /** + * Gets the Minor version value of this MimeVersionHeader. + * + * @return the Minor version of this MimeVersionHeader + */ + public int getMinorVersion() { + return minorVersion; + } + + /** + * Gets the Major version value of this MimeVersionHeader. + * + * @return the Major version of this MimeVersionHeader + */ + public int getMajorVersion() { + return majorVersion; + } + + /** + * Sets the Minor-Version argument of this MimeVersionHeader to the supplied + * <var>minorVersion</var> value. + * + * @param minorVersion - the new integer Minor version + * @throws InvalidArgumentException + */ + public void setMinorVersion(int minorVersion) + throws InvalidArgumentException { + if (minorVersion < 0) + throw new InvalidArgumentException( + "JAIN-SIP Exception" + + ", MimeVersion, setMinorVersion(), the minorVersion parameter is null"); + this.minorVersion = minorVersion; + } + + /** + * Sets the Major-Version argument of this MimeVersionHeader to the supplied + * <var>majorVersion</var> value. + * + * @param majorVersion - the new integer Major version + * @throws InvalidArgumentException + */ + public void setMajorVersion(int majorVersion) + throws InvalidArgumentException { + if (majorVersion < 0) + throw new InvalidArgumentException( + "JAIN-SIP Exception" + + ", MimeVersion, setMajorVersion(), the majorVersion parameter is null"); + this.majorVersion = majorVersion; + } + + /** + * Return canonical form. + * @return String + */ + public String encodeBody() { + return Integer.toString(majorVersion) + + DOT + + Integer.toString(minorVersion); + } + +} +/* + * $Log: MimeVersion.java,v $ + * Revision 1.6 2009/10/18 13:46:35 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.5 2009/07/17 18:57:32 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:33 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:34 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/MinExpires.java b/java/gov/nist/javax/sip/header/MinExpires.java new file mode 100644 index 0000000..ee80722 --- /dev/null +++ b/java/gov/nist/javax/sip/header/MinExpires.java @@ -0,0 +1,171 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.*; +import javax.sip.header.*; + +/** + * MinExpires SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/10/18 13:46:35 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class MinExpires extends SIPHeader implements MinExpiresHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 7001828209606095801L; + /** expires field + */ + protected int expires; + + /** default constructor + */ + public MinExpires() { + super(NAME); + } + + /** + * Return canonical form. + * @return String + */ + public String encodeBody() { + return Integer.toString(expires); + } + + /** + * Gets the expires value of the ExpiresHeader. This expires value is + * relative time. + * + * @return the expires value of the ExpiresHeader. + * + */ + public int getExpires() { + return expires; + } + + /** + * Sets the relative expires value of the ExpiresHeader. + * The expires value MUST be greater than zero and MUST be + * less than 2**31. + * + * @param expires - the new expires value of this ExpiresHeader + * + * @throws InvalidArgumentException if supplied value is less than zero. + * + * + * + */ + public void setExpires(int expires) throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad argument " + expires); + this.expires = expires; + } + +} +/* + * $Log: MinExpires.java,v $ + * Revision 1.6 2009/10/18 13:46:35 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.5 2009/07/17 18:57:32 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:20 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:34 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/NameMap.java b/java/gov/nist/javax/sip/header/NameMap.java new file mode 100644 index 0000000..3d7a2a4 --- /dev/null +++ b/java/gov/nist/javax/sip/header/NameMap.java @@ -0,0 +1,210 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.header; +import gov.nist.core.*; +import gov.nist.javax.sip.header.ims.*; + +import java.util.Hashtable; + +/** + * A mapping class that returns the SIPHeader for a given header name. + * Add new classes to this map if you are implementing new header types if + * you want some of the introspection based methods to work. + * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:32 $ + * @since 1.1 + */ +public class NameMap implements SIPHeaderNames, PackageNames { + static Hashtable nameMap; + static { + initializeNameMap(); + } + + protected static void putNameMap(String headerName, String className) { + nameMap.put( + headerName.toLowerCase(), + className); + } + + public static Class getClassFromName(String headerName) { + String className = (String) nameMap.get(headerName.toLowerCase()); + if (className == null) + return null; + else { + try { + return Class.forName(className); + } catch (ClassNotFoundException ex) { + return null; + } + } + } + + /** add an extension header to this map. + *@param headerName is the extension header name. + *@param className is the fully qualified class name that implements + * the header (does not have to belong to the nist-sip package). + * Use this if you want to use the introspection-based methods. + */ + + public static void addExtensionHeader( + String headerName, + String className) { + nameMap.put(headerName.toLowerCase(), className); + } + + private static void initializeNameMap() { + nameMap = new Hashtable(); + putNameMap(MinExpires.NAME, MinExpires.class.getName()); // 1 + + putNameMap(ErrorInfo.NAME, ErrorInfo.class.getName()); // 2 + + putNameMap(MimeVersion.NAME, MimeVersion.class.getName()); // 3 + + putNameMap(InReplyTo.NAME, InReplyTo.class.getName()); // 4 + + putNameMap(Allow.NAME, Allow.class.getName()); // 5 + + putNameMap(ContentLanguage.NAME, ContentLanguage.class.getName()); // 6 + + putNameMap(CALL_INFO, CallInfo.class.getName()); //7 + + putNameMap(CSEQ, CSeq.class.getName()); //8 + + putNameMap(ALERT_INFO, AlertInfo.class.getName()); //9 + + putNameMap(ACCEPT_ENCODING, AcceptEncoding.class.getName()); //10 + + putNameMap(ACCEPT, Accept.class.getName()); //11 + + putNameMap(ACCEPT_LANGUAGE, AcceptLanguage.class.getName()); //12 + + putNameMap(RECORD_ROUTE, RecordRoute.class.getName()); //13 + + putNameMap(TIMESTAMP, TimeStamp.class.getName()); //14 + + putNameMap(TO, To.class.getName()); //15 + + putNameMap(VIA, Via.class.getName()); //16 + + putNameMap(FROM, From.class.getName()); //17 + + putNameMap(CALL_ID, CallID.class.getName()); //18 + + putNameMap(AUTHORIZATION, Authorization.class.getName()); //19 + + putNameMap(PROXY_AUTHENTICATE, ProxyAuthenticate.class.getName()); //20 + + putNameMap(SERVER, Server.class.getName()); //21 + + putNameMap(UNSUPPORTED, Unsupported.class.getName()); //22 + + putNameMap(RETRY_AFTER, RetryAfter.class.getName()); //23 + + putNameMap(CONTENT_TYPE, ContentType.class.getName()); //24 + + putNameMap(CONTENT_ENCODING, ContentEncoding.class.getName()); //25 + + putNameMap(CONTENT_LENGTH, ContentLength.class.getName()); //26 + + putNameMap(ROUTE, Route.class.getName()); //27 + + putNameMap(CONTACT, Contact.class.getName()); //28 + + putNameMap(WWW_AUTHENTICATE, WWWAuthenticate.class.getName()); //29 + + putNameMap(MAX_FORWARDS, MaxForwards.class.getName()); //30 + + putNameMap(ORGANIZATION, Organization.class.getName()); //31 + + putNameMap(PROXY_AUTHORIZATION, ProxyAuthorization.class.getName()); //32 + + putNameMap(PROXY_REQUIRE, ProxyRequire.class.getName()); //33 + + putNameMap(REQUIRE, Require.class.getName()); //34 + + putNameMap(CONTENT_DISPOSITION, ContentDisposition.class.getName()); //35 + + putNameMap(SUBJECT, Subject.class.getName()); //36 + + putNameMap(USER_AGENT, UserAgent.class.getName()); //37 + + putNameMap(WARNING, Warning.class.getName()); //38 + + putNameMap(PRIORITY, Priority.class.getName()); //39 + + putNameMap(DATE, SIPDateHeader.class.getName()); //40 + + putNameMap(EXPIRES, Expires.class.getName()); //41 + + putNameMap(SUPPORTED, Supported.class.getName()); //42 + + putNameMap(REPLY_TO, ReplyTo.class.getName()); // 43 + + putNameMap(SUBSCRIPTION_STATE, SubscriptionState.class.getName()); //44 + + putNameMap(EVENT, Event.class.getName()); //45 + + putNameMap(ALLOW_EVENTS, AllowEvents.class.getName()); //46 + + + // pmusgrave - extensions + putNameMap(REFERRED_BY, "ReferredBy"); + putNameMap(SESSION_EXPIRES, "SessionExpires"); + putNameMap(MIN_SE, "MinSE"); + putNameMap(REPLACES, "Replaces"); + // jean deruelle + putNameMap(JOIN, "Join"); + + + // IMS Specific headers. + + putNameMap(PAccessNetworkInfoHeader.NAME, PAccessNetworkInfo.class.getName()); + + putNameMap(PAssertedIdentityHeader.NAME, PAssertedIdentity.class.getName()); + + putNameMap(PAssociatedURIHeader.NAME, PAssociatedURI.class.getName()); + + putNameMap(PCalledPartyIDHeader.NAME, PCalledPartyID.class.getName()); + + putNameMap(PChargingFunctionAddressesHeader.NAME, PChargingFunctionAddresses.class.getName()); + + putNameMap(PChargingVectorHeader.NAME,PChargingVector.class.getName()); + + putNameMap(PMediaAuthorizationHeader.NAME,PMediaAuthorization.class.getName()); + + putNameMap(Path.NAME, Path.class.getName()); + + putNameMap(PPreferredIdentity.NAME, PPreferredIdentity.class.getName()); + + putNameMap(Privacy.NAME,Privacy.class.getName()); + + putNameMap(ServiceRoute.NAME, ServiceRoute.class.getName()); + + putNameMap(PVisitedNetworkID.NAME, PVisitedNetworkID.class.getName()); + + + + } +} diff --git a/java/gov/nist/javax/sip/header/Organization.java b/java/gov/nist/javax/sip/header/Organization.java new file mode 100644 index 0000000..c9363fb --- /dev/null +++ b/java/gov/nist/javax/sip/header/Organization.java @@ -0,0 +1,156 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; + +/** + * Organization SIP Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:32 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class Organization extends SIPHeader implements OrganizationHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -2775003113740192712L; + /** + * Organization field + */ + protected String organization; + + /** + * Return encoding of value of the header. + * @return String + */ + public String encodeBody() { + return organization; + } + + /** + * Default constructor + */ + public Organization() { + super(ORGANIZATION); + } + + /** + * Get the organization field. + * @return String + */ + public String getOrganization() { + return organization; + } + + /** + * Set the organization member + * @param o String to set + */ + public void setOrganization(String o) throws ParseException { + if (o == null) + throw new NullPointerException( + "JAIN-SIP Exception," + + " Organization, setOrganization(), the organization parameter is null"); + organization = o; + } +} +/* + * $Log: Organization.java,v $ + * Revision 1.5 2009/07/17 18:57:32 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:15 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:34 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ParameterNames.java b/java/gov/nist/javax/sip/header/ParameterNames.java new file mode 100644 index 0000000..7fcddab --- /dev/null +++ b/java/gov/nist/javax/sip/header/ParameterNames.java @@ -0,0 +1,159 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +package gov.nist.javax.sip.header; + +/** + * A list of commonly occuring parameter names. These are for conveniance so as + * to avoid typo's + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:33 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + * + */ +public interface ParameterNames { + // Issue reported by larryb + public static final String NEXT_NONCE = "nextnonce"; + + public static final String TAG = "tag"; + + public static final String USERNAME = "username"; + + public static final String URI = "uri"; + + public static final String DOMAIN = "domain"; + + public static final String CNONCE = "cnonce"; + + public static final String PASSWORD = "password"; + + public static final String RESPONSE = "response"; + + public static final String RESPONSE_AUTH = "rspauth"; + + public static final String OPAQUE = "opaque"; + + public static final String ALGORITHM = "algorithm"; + + public static final String DIGEST = "Digest"; + + public static final String SIGNED_BY = "signed-by"; + + public static final String SIGNATURE = "signature"; + + public static final String NONCE = "nonce"; + + // Issue reported by larryb + public static final String NONCE_COUNT = "nc"; + + public static final String PUBKEY = "pubkey"; + + public static final String COOKIE = "cookie"; + + public static final String REALM = "realm"; + + public static final String VERSION = "version"; + + public static final String STALE = "stale"; + + public static final String QOP = "qop"; + + public static final String NC = "nc"; + + public static final String PURPOSE = "purpose"; + + public static final String CARD = "card"; + + public static final String INFO = "info"; + + public static final String ACTION = "action"; + + public static final String PROXY = "proxy"; + + public static final String REDIRECT = "redirect"; + + public static final String EXPIRES = "expires"; + + public static final String Q = "q"; + + public static final String RENDER = "render"; + + public static final String SESSION = "session"; + + public static final String ICON = "icon"; + + public static final String ALERT = "alert"; + + public static final String HANDLING = "handling"; + + public static final String REQUIRED = "required"; + + public static final String OPTIONAL = "optional"; + + public static final String EMERGENCY = "emergency"; + + public static final String URGENT = "urgent"; + + public static final String NORMAL = "normal"; + + public static final String NON_URGENT = "non-urgent"; + + public static final String DURATION = "duration"; + + public static final String BRANCH = "branch"; + + public static final String HIDDEN = "hidden"; + + public static final String RECEIVED = "received"; + + public static final String MADDR = "maddr"; + + public static final String TTL = "ttl"; + + public static final String TRANSPORT = "transport"; + + public static final String TEXT = "text"; + + public static final String CAUSE = "cause"; + + public static final String ID = "id"; + + // @@@ hagai + public static final String RPORT = "rport"; + + // Added pmusgrave (Replaces support) + public static final String TO_TAG = "to-tag"; + public static final String FROM_TAG = "from-tag"; + + // pmusgrave (outbound and gruu) + // draft-sip-outbouund-08 + // draft-sip-gruu-12 + public static final String SIP_INSTANCE = "+sip.instance"; + public static final String PUB_GRUU = "pub-gruu"; + public static final String TEMP_GRUU = "temp-gruu"; + public static final String GRUU = "gruu"; +} diff --git a/java/gov/nist/javax/sip/header/ParametersHeader.java b/java/gov/nist/javax/sip/header/ParametersHeader.java new file mode 100644 index 0000000..f84ff37 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ParametersHeader.java @@ -0,0 +1,616 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/**************************************************************************/ +/* Product of NIST Advanced Networking Technologies Division */ +/**************************************************************************/ + +package gov.nist.javax.sip.header; +import gov.nist.core.DuplicateNameValueList; +import gov.nist.core.NameValue; +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.address.GenericURI; + +import java.io.Serializable; +import java.text.ParseException; +import java.util.Iterator; + +import javax.sip.header.Parameters; + +/** + * Parameters header. Suitable for extension by headers that have parameters. + * + * @author M. Ranganathan <br/> + * + * + * @version 1.2 $Revision: 1.15 $ $Date: 2010/01/12 00:05:27 $ + * + */ +public abstract class ParametersHeader + extends SIPHeader + implements javax.sip.header.Parameters, Serializable { + protected NameValueList parameters; + + protected DuplicateNameValueList duplicates; + + protected ParametersHeader() { + this.parameters = new NameValueList(); + this.duplicates = new DuplicateNameValueList(); + } + + protected ParametersHeader(String hdrName) { + super(hdrName); + this.parameters = new NameValueList(); + this.duplicates = new DuplicateNameValueList(); + } + + protected ParametersHeader(String hdrName, boolean sync) { + super(hdrName); + this.parameters = new NameValueList(sync); + this.duplicates = new DuplicateNameValueList(); + } + + /** + * Returns the value of the named parameter, or null if it is not set. A + * zero-length String indicates flag parameter. + * + * @param name name of parameter to retrieve + * @return the value of specified parameter + */ + + public String getParameter(String name) { + return this.parameters.getParameter(name); + + } + + /** + * Return the parameter as an object (dont convert to string). + * + * @param name is the name of the parameter to get. + * @return the object associated with the name. + */ + public Object getParameterValue(String name) { + return this.parameters.getValue(name); + } + + /** + * Returns an Iterator over the names (Strings) of all parameters present + * in this ParametersHeader. + * + * @return an Iterator over all the parameter names + */ + + public Iterator<String> getParameterNames() { + return parameters.getNames(); + } + + /** Return true if you have a parameter and false otherwise. + * + *@return true if the parameters list is non-empty. + */ + + public boolean hasParameters() { + return parameters != null && !parameters.isEmpty(); + } + + /** + * Removes the specified parameter from Parameters of this ParametersHeader. + * This method returns silently if the parameter is not part of the + * ParametersHeader. + * + * @param name - a String specifying the parameter name + */ + + public void removeParameter(String name) { + this.parameters.delete(name); + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. A zero-length String indicates flag + * + * parameter. + * + * + * + * @param name - a String specifying the parameter name + * + * @param value - a String specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + public void setParameter(String name, String value) throws ParseException { + NameValue nv = parameters.getNameValue(name); + if (nv != null) { + nv.setValueAsObject(value); + } else { + nv = new NameValue(name, value); + this.parameters.set(nv); + } + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. A zero-length String indicates flag + * + * parameter. + * + * + * + * @param name - a String specifying the parameter name + * + * @param value - a String specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + public void setQuotedParameter(String name, String value) + throws ParseException { + NameValue nv = parameters.getNameValue(name); + if (nv != null) { + nv.setValueAsObject(value); + nv.setQuotedValue(); + } else { + nv = new NameValue(name, value); + nv.setQuotedValue(); + this.parameters.set(nv); + } + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. + * + * + * @param name - a String specifying the parameter name + * + * @param value - an int specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + protected void setParameter(String name, int value) { + Integer val = Integer.valueOf(value); + this.parameters.set(name,val); + + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. + * + * + * @param name - a String specifying the parameter name + * + * @param value - a boolean specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + protected void setParameter(String name, boolean value) { + Boolean val = Boolean.valueOf(value); + this.parameters.set(name,val); + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. + * + * @param name - a String specifying the parameter name + * + * @param value - a boolean specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + protected void setParameter(String name, float value) { + Float val = Float.valueOf(value); + NameValue nv = parameters.getNameValue(name); + if (nv != null) { + nv.setValueAsObject(val); + } else { + nv = new NameValue(name, val); + this.parameters.set(nv); + } + } + + /** + * Sets the value of the specified parameter. If the parameter already had + * + * a value it will be overwritten. A zero-length String indicates flag + * + * parameter. + * + * + * + * @param name - a String specifying the parameter name + * + * @param value - a String specifying the parameter value + * + * @throws ParseException which signals that an error has been reached + * + * unexpectedly while parsing the parameter name or value. + * + */ + protected void setParameter(String name, Object value) { + this.parameters.set(name,value); + } + + /** + * Return true if has a parameter. + * + * @param parameterName is the name of the parameter. + * + * @return true if the parameter exists and false if not. + */ + public boolean hasParameter(String parameterName) { + return this.parameters.hasNameValue(parameterName); + } + + /** + *Remove all parameters. + */ + public void removeParameters() { + this.parameters = new NameValueList(); + } + + /** + * get the parameter list. + * @return parameter list + */ + public NameValueList getParameters() { + return parameters; + } + + /** Set the parameter given a name and value. + * + * @param nameValue - the name value of the parameter to set. + */ + public void setParameter(NameValue nameValue) { + this.parameters.set(nameValue); + } + + /** + * Set the parameter list. + * + * @param parameters The name value list to set as the parameter list. + */ + public void setParameters(NameValueList parameters) { + this.parameters = parameters; + } + + /** + * Get the parameter as an integer value. + * + * @param parameterName -- the parameter name to fetch. + * + * @return -1 if the parameter is not defined in the header. + */ + protected int getParameterAsInt(String parameterName) { + if (this.getParameterValue(parameterName) != null) { + try { + if (this.getParameterValue(parameterName) instanceof String) { + return Integer.parseInt(this.getParameter(parameterName)); + } else { + return ((Integer) getParameterValue(parameterName)) + .intValue(); + } + } catch (NumberFormatException ex) { + return -1; + } + } else + return -1; + } + + /** Get the parameter as an integer when it is entered as a hex. + * + *@param parameterName -- The parameter name to fetch. + * + *@return -1 if the parameter is not defined in the header. + */ + protected int getParameterAsHexInt(String parameterName) { + if (this.getParameterValue(parameterName) != null) { + try { + if (this.getParameterValue(parameterName) instanceof String) { + return Integer.parseInt( + this.getParameter(parameterName), + 16); + } else { + return ((Integer) getParameterValue(parameterName)) + .intValue(); + } + } catch (NumberFormatException ex) { + return -1; + } + } else + return -1; + } + + /** Get the parameter as a float value. + * + *@param parameterName -- the parameter name to fetch + * + *@return -1 if the parameter is not defined or the parameter as a float. + */ + protected float getParameterAsFloat(String parameterName) { + + if (this.getParameterValue(parameterName) != null) { + try { + if (this.getParameterValue(parameterName) instanceof String) { + return Float.parseFloat(this.getParameter(parameterName)); + } else { + return ((Float) getParameterValue(parameterName)) + .floatValue(); + } + } catch (NumberFormatException ex) { + return -1; + } + } else + return -1; + } + + /** + * Get the parameter as a long value. + * + * @param parameterName -- the parameter name to fetch. + * + * @return -1 if the parameter is not defined or the parameter as a long. + */ + protected long getParameterAsLong(String parameterName) { + if (this.getParameterValue(parameterName) != null) { + try { + if (this.getParameterValue(parameterName) instanceof String) { + return Long.parseLong(this.getParameter(parameterName)); + } else { + return ((Long) getParameterValue(parameterName)) + .longValue(); + } + } catch (NumberFormatException ex) { + return -1; + } + } else + return -1; + } + + /** + * Get the parameter value as a URI. + * + * @param parameterName -- the parameter name + * + * @return value of the parameter as a URI or null if the parameter + * not present. + */ + protected GenericURI getParameterAsURI(String parameterName) { + Object val = getParameterValue(parameterName); + if (val instanceof GenericURI) + return (GenericURI) val; + else { + try { + return new GenericURI((String) val); + } catch (ParseException ex) { + //catch ( URISyntaxException ex) { + return null; + } + } + } + + /** + * Get the parameter value as a boolean. + * + * @param parameterName -- the parameter name + * @return boolean value of the parameter. + */ + protected boolean getParameterAsBoolean(String parameterName) { + Object val = getParameterValue(parameterName); + if (val == null) { + return false; + } else if (val instanceof Boolean) { + return ((Boolean) val).booleanValue(); + } else if (val instanceof String) { + return Boolean.valueOf((String) val).booleanValue(); + } else + return false; + } + + /** + * This is for the benifit of the TCK. + * + * @return the name value pair for the given parameter name. + */ + public NameValue getNameValue(String parameterName) { + return parameters.getNameValue(parameterName); + } + + + public Object clone() { + ParametersHeader retval = (ParametersHeader) super.clone(); + if (this.parameters != null) + retval.parameters = (NameValueList) this.parameters.clone(); + return retval; + } + + //------------------------- + /** + * Introduced specifically for the P-Charging-Function-Addresses Header and + * all other headers that may have multiple header parameters of the same name, but + * with multiple possible values. + * + * Example: P-Charging-Function-Addresses: ccf=[5555::b99:c88:d77:e66]; ccf=[5555::a55:b44:c33:d22]; + * ecf=[5555::1ff:2ee:3dd:4cc]; ecf=[5555::6aa:7bb:8cc:9dd] + * @param name of the parameter + * @param value of the parameter + */ + public void setMultiParameter(String name, String value) + { + NameValue nv = new NameValue(); + nv.setName(name); + nv.setValue(value); + duplicates.set(nv); + } + + /** Set the parameter given a name and value. + * + * @param nameValue - the name value of the parameter to set. + */ + public void setMultiParameter(NameValue nameValue) { + this.duplicates.set(nameValue); + } + + /** + * Returns the parameter name + * @param name + * @return + */ + public String getMultiParameter(String name) { + return this.duplicates.getParameter(name); + + } + + + public DuplicateNameValueList getMultiParameters() { + return duplicates; + } + + + /** + * Return the parameter as an object (dont convert to string). + * + * @param name is the name of the parameter to get. + * @return the object associated with the name. + */ + public Object getMultiParameterValue(String name) { + return this.duplicates.getValue(name); + } + + /** + * Returns an Iterator over the names (Strings) of all parameters present + * in this ParametersHeader. + * + * @return an Iterator over all the parameter names + */ + + public Iterator<String> getMultiParameterNames() { + return duplicates.getNames(); + } + + /** Return true if you have a parameter and false otherwise. + * + *@return true if the parameters list is non-empty. + */ + + public boolean hasMultiParameters() { + return duplicates != null && !duplicates.isEmpty(); + } + + /** + * Removes the specified parameter from Parameters of this ParametersHeader. + * This method returns silently if the parameter is not part of the + * ParametersHeader. + * + * @param name - a String specifying the parameter name + */ + + public void removeMultiParameter(String name) { + this.duplicates.delete(name); + } + + /** + * Return true if has a parameter. + * + * @param parameterName is the name of the parameter. + * + * @return true if the parameter exists and false if not. + */ + public boolean hasMultiParameter(String parameterName) { + return this.duplicates.hasNameValue(parameterName); + } + + /** + *Remove all parameters. + */ + public void removeMultiParameters() { + this.duplicates = new DuplicateNameValueList(); + } + + //------------------------------- + + @SuppressWarnings("unchecked") + protected final boolean equalParameters( Parameters other ) { + if (this==other) return true; + + for ( Iterator i = this.getParameterNames(); i.hasNext();) { + String pname = (String) i.next(); + + String p1 = this.getParameter( pname ); + String p2 = other.getParameter( pname ); + + // getting them based on this.getParameterNames. Note that p1 may be null + // if this is a name-only parameter like rport or lr. + if (p1 == null ^ p2 == null) return false; + else if (p1 != null && !p1.equalsIgnoreCase(p2) ) return false; + } + + // Also compare other's parameters; some duplicate testing here... + for ( Iterator i = other.getParameterNames(); i.hasNext();) { + String pname = (String) i.next(); + + String p1 = other.getParameter( pname ); + String p2 = this.getParameter( pname ); + + // assert( p1 != null ); + // if ( p1 == null ) throw new RuntimeException("Assertion check failed!"); + // if (p2==null) return false; + + // getting them based on this.getParameterNames. Note that p1 may be null + // if this is a name-only parameter like rport or lr. + + if (p1 == null ^ p2 == null) return false; + else if (p1 != null && !p1.equalsIgnoreCase(p2) ) return false; + } + + return true; + } + + + // ----------- Abstract methods -------------- + protected abstract String encodeBody(); + +} diff --git a/java/gov/nist/javax/sip/header/Priority.java b/java/gov/nist/javax/sip/header/Priority.java new file mode 100644 index 0000000..5af72d0 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Priority.java @@ -0,0 +1,102 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.text.ParseException; + +/** + * the Priority header. + * + * @author Olivier Deruelle <br/> + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:33 $ + * + * + * + */ +public class Priority extends SIPHeader implements PriorityHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 3837543366074322106L; + + /** constant EMERGENCY field + */ + public static final String EMERGENCY = ParameterNames.EMERGENCY; + + /** constant URGENT field + */ + public static final String URGENT = ParameterNames.URGENT; + + /** constant NORMAL field + */ + public static final String NORMAL = ParameterNames.NORMAL; + + /** constant NON_URGENT field + */ + public static final String NON_URGENT = ParameterNames.NON_URGENT; + /** priority field + */ + protected String priority; + + /** Default constructor + */ + public Priority() { + super(NAME); + } + + /** + * Encode into canonical form. + * @return String + */ + public String encodeBody() { + return priority; + } + + /** + * get the priority value. + * @return String + */ + public String getPriority() { + return priority; + } + + /** + * Set the priority member + * @param p String to set + */ + public void setPriority(String p) throws ParseException { + if (p == null) + throw new NullPointerException( + "JAIN-SIP Exception," + + "Priority, setPriority(), the priority parameter is null"); + priority = p; + } +} diff --git a/java/gov/nist/javax/sip/header/Protocol.java b/java/gov/nist/javax/sip/header/Protocol.java new file mode 100644 index 0000000..33c3bcb --- /dev/null +++ b/java/gov/nist/javax/sip/header/Protocol.java @@ -0,0 +1,221 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +/** + * Protocol name and version. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:33 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class Protocol extends SIPObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 2216758055974073280L; + + /** protocolName field + */ + protected String protocolName; + + /** protocolVersion field + */ + protected String protocolVersion; + + /** transport field + */ + protected String transport; + + /** + * Return canonical form. + * @return String + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + buffer.append(protocolName.toUpperCase()) + .append(SLASH) + .append(protocolVersion) + .append(SLASH) + .append(transport.toUpperCase()); + + return buffer; + } + + /** get the protocol name + * @return String + */ + public String getProtocolName() { + return protocolName; + } + + /** get the protocol version + * @return String + */ + public String getProtocolVersion() { + return protocolVersion; + } + + /** + * Get the protocol name + version + * JvB: This is what is returned in the ViaHeader interface for 'getProtocol()' + * + * @return String : protocolname + '/' + version + */ + public String getProtocol() { + return protocolName + '/' + protocolVersion; + } + + public void setProtocol( String name_and_version ) throws ParseException { + int slash = name_and_version.indexOf('/'); + if (slash>0) { + this.protocolName = name_and_version.substring(0,slash); + this.protocolVersion = name_and_version.substring( slash+1 ); + } else throw new ParseException( "Missing '/' in protocol", 0 ); + } + + /** get the transport + * @return String + */ + public String getTransport() { + return transport; + } + + /** + * Set the protocolName member + * @param p String to set + */ + public void setProtocolName(String p) { + protocolName = p; + } + + /** + * Set the protocolVersion member + * @param p String to set + */ + public void setProtocolVersion(String p) { + protocolVersion = p; + } + + /** + * Set the transport member + * @param t String to set + */ + public void setTransport(String t) { + transport = t; + } + + /** + * Default constructor. + */ + public Protocol() { + protocolName = "SIP"; + protocolVersion = "2.0"; + transport = "UDP"; + } +} +/* + * $Log: Protocol.java,v $ + * Revision 1.8 2009/07/17 18:57:33 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2007/02/12 15:19:23 belangery + * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase. + * + * Revision 1.6 2006/07/13 09:01:24 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2005/10/09 18:47:53 jeroen + * defined equals() in terms of API calls + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ProxyAuthenticate.java b/java/gov/nist/javax/sip/header/ProxyAuthenticate.java new file mode 100644 index 0000000..047423f --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyAuthenticate.java @@ -0,0 +1,148 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.address.URI; +import javax.sip.header.*; +/** + * Proxy Authenticate SIP (HTTP ) header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:33 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class ProxyAuthenticate + extends AuthenticationHeader + implements ProxyAuthenticateHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 3826145955463251116L; + + /** + * Default Constructor + */ + public ProxyAuthenticate() { + super(NAME); + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AuthenticationHeader#getURI() + * + * @since 1.2 this method is deprecated, uri is not a valid paramter for this header + * Fail silently for backwards compatibility + */ + public URI getURI() { + return null; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AuthenticationHeader#setURI(javax.sip.address.URI) + * + * @since 1.2 this method is deprecated, uri is not a valid paramter for this header + * Fail silently for backwards compatibility + */ + public void setURI(URI uri) { + // empty, fail silently + } + +} +/* + * $Log: ProxyAuthenticate.java,v $ + * Revision 1.5 2009/07/17 18:57:33 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:19 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2005/10/09 10:50:06 jeroen + * get/setURI is deprecated for WWW-Authenticate and Proxy-Authenticate, + * but not for other AAA related headers + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ProxyAuthenticateList.java b/java/gov/nist/javax/sip/header/ProxyAuthenticateList.java new file mode 100644 index 0000000..cc70cf6 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyAuthenticateList.java @@ -0,0 +1,61 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** + * List of ProxyAuthenticate headers. + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ProxyAuthenticateList extends SIPHeaderList<ProxyAuthenticate> { + + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1L; + + public Object clone() { + ProxyAuthenticateList retval = new ProxyAuthenticateList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default constructor + */ + public ProxyAuthenticateList() { + super(ProxyAuthenticate.class, ProxyAuthenticateHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/ProxyAuthorization.java b/java/gov/nist/javax/sip/header/ProxyAuthorization.java new file mode 100644 index 0000000..cb49846 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyAuthorization.java @@ -0,0 +1,123 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** + * ProxyAuthorization Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class ProxyAuthorization + extends AuthenticationHeader + implements ProxyAuthorizationHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6374966905199799098L; + + /** default constructor + */ + public ProxyAuthorization() { + super(PROXY_AUTHORIZATION); + } + +} +/* + * $Log: ProxyAuthorization.java,v $ + * Revision 1.5 2009/07/17 18:57:34 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:46 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ProxyAuthorizationList.java b/java/gov/nist/javax/sip/header/ProxyAuthorizationList.java new file mode 100644 index 0000000..9a9f532 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyAuthorizationList.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** + * List of ProxyAuthorization headers. + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ProxyAuthorizationList extends SIPHeaderList<ProxyAuthorization>{ + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1L; + + public Object clone() { + ProxyAuthorizationList retval = new ProxyAuthorizationList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default constructor + */ + public ProxyAuthorizationList() { + super(ProxyAuthorization.class, ProxyAuthorizationHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/ProxyRequire.java b/java/gov/nist/javax/sip/header/ProxyRequire.java new file mode 100644 index 0000000..70fa30a --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyRequire.java @@ -0,0 +1,165 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; + +/** + * ProxyRequire Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class ProxyRequire extends SIPHeader implements ProxyRequireHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3269274234851067893L; + /** + * Optiontag field + */ + protected String optionTag; + + /** + * Default Constructor + */ + public ProxyRequire() { + super(PROXY_REQUIRE); + } + + /** Constructor + * @param s String to set + */ + public ProxyRequire(String s) { + super(PROXY_REQUIRE); + optionTag = s; + } + + /** + * Encode in canonical form. + * @return String + */ + public String encodeBody() { + return optionTag; + } + + /** + * Sets the option tag value to the new supplied <var>optionTag</var> + * parameter. + * + * @param optionTag - the new string value of the option tag. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the optionTag value. + */ + public void setOptionTag(String optionTag) throws ParseException { + if (optionTag == null) + throw new NullPointerException("JAIN-SIP Exception, ProxyRequire, setOptionTag(), the optionTag parameter is null"); + this.optionTag = optionTag; + } + + /** + * Gets the option tag of this OptionTag class. + * + * @return the string that identifies the option tag value. + */ + public String getOptionTag() { + return optionTag; + } +} +/* + * $Log: ProxyRequire.java,v $ + * Revision 1.5 2009/07/17 18:57:34 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:26 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ProxyRequireList.java b/java/gov/nist/javax/sip/header/ProxyRequireList.java new file mode 100644 index 0000000..a540be9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ProxyRequireList.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * Proxy Require SIPSIPObject (list of option tags) + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ProxyRequireList extends SIPHeaderList<ProxyRequire> { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 5648630649476486042L; + + public Object clone() { + ProxyRequireList retval = new ProxyRequireList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default Constructor + */ + public ProxyRequireList() { + super(ProxyRequire.class, ProxyRequireHeader.NAME); + } + + +} diff --git a/java/gov/nist/javax/sip/header/RAck.java b/java/gov/nist/javax/sip/header/RAck.java new file mode 100644 index 0000000..0c2ceac --- /dev/null +++ b/java/gov/nist/javax/sip/header/RAck.java @@ -0,0 +1,156 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; +import java.text.ParseException; + +/** + * RAck SIP Header implementation + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:34 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class RAck extends SIPHeader implements javax.sip.header.RAckHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 743999286077404118L; + + protected long cSeqNumber; + + protected long rSeqNumber; + + protected String method; + + /** Creates a new instance of RAck */ + public RAck() { + super(NAME); + } + + /** + * Encode the body of this header (the stuff that follows headerName). A.K.A + * headerValue. + * + */ + protected String encodeBody() { + // Bug reported by Bruno Konik - was encoded in + // the wrong order. + return new StringBuffer().append(rSeqNumber).append(SP).append( + cSeqNumber).append(SP).append(method).toString(); + + } + + /** + * Gets the CSeq sequence number of this RAckHeader. + * + * @deprecated + * @return the integer value of the cSeq number of the RAckHeader + */ + public int getCSeqNumber() { + return (int) cSeqNumber; + } + + /** + * Gets the CSeq sequence number of this RAckHeader. + * + * @return the integer value of the cSeq number of the RAckHeader + */ + public long getCSeqNumberLong() { + return cSeqNumber; + } + + /** + * Gets the method of RAckHeader + * + * @return method of RAckHeader + */ + public String getMethod() { + return this.method; + } + + /** + * Gets the RSeq sequence number of this RAckHeader. + * + * @deprecated + * @return the integer value of the RSeq number of the RAckHeader + */ + public int getRSeqNumber() { + return (int) rSeqNumber; + } + + /** + * @deprecated + * @see javax.sip.header.RAckHeader#setCSeqNumber(int) + */ + public void setCSeqNumber(int cSeqNumber) throws InvalidArgumentException { + this.setCSequenceNumber(cSeqNumber); + } + + public void setMethod(String method) throws ParseException { + this.method = method; + } + + + public long getCSequenceNumber() { + return this.cSeqNumber; + } + + public long getRSequenceNumber() { + return this.rSeqNumber; + } + + public void setCSequenceNumber(long cSeqNumber) + throws InvalidArgumentException { + if (cSeqNumber <= 0 || cSeqNumber > ((long) 1) << 32 - 1) + throw new InvalidArgumentException("Bad CSeq # " + cSeqNumber); + this.cSeqNumber = cSeqNumber; + + } + + /** + *@deprecated + * @see javax.sip.header.RAckHeader#setRSeqNumber(int) + */ + public void setRSeqNumber(int rSeqNumber) throws InvalidArgumentException { + this.setRSequenceNumber(rSeqNumber); + } + + + public void setRSequenceNumber(long rSeqNumber) + throws InvalidArgumentException { + if (rSeqNumber <= 0 || cSeqNumber > ((long) 1) << 32 - 1) + throw new InvalidArgumentException("Bad rSeq # " + rSeqNumber); + this.rSeqNumber = rSeqNumber; + } +} diff --git a/java/gov/nist/javax/sip/header/RSeq.java b/java/gov/nist/javax/sip/header/RSeq.java new file mode 100644 index 0000000..05125bc --- /dev/null +++ b/java/gov/nist/javax/sip/header/RSeq.java @@ -0,0 +1,90 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; + +/** + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:35 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class RSeq extends SIPHeader implements javax.sip.header.RSeqHeader { + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 8765762413224043394L; + protected long sequenceNumber; + + /** Creates a new instance of RSeq */ + public RSeq() { + super(NAME); + } + + /** Gets the sequence number of this RSeqHeader. + * @deprecated + * @return the integer value of the Sequence number of the RSeqHeader + */ + public int getSequenceNumber() { + return (int)this.sequenceNumber; + } + + + /** Encode the body of this header (the stuff that follows headerName). + * A.K.A headerValue. + */ + protected String encodeBody() { + return Long.toString(this.sequenceNumber); + } + + public long getSeqNumber() { + return this.sequenceNumber; + } + + public void setSeqNumber(long sequenceNumber) throws InvalidArgumentException { + + if (sequenceNumber <= 0 ||sequenceNumber > ((long)1)<<32 - 1) + throw new InvalidArgumentException( + "Bad seq number " + sequenceNumber); + this.sequenceNumber = sequenceNumber; + + } + + /** + * @deprecated + * @see javax.sip.header.RSeqHeader#setSequenceNumber(int) + */ + public void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException { + this.setSeqNumber(sequenceNumber); + + } + + + +} diff --git a/java/gov/nist/javax/sip/header/Reason.java b/java/gov/nist/javax/sip/header/Reason.java new file mode 100644 index 0000000..c59aae3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Reason.java @@ -0,0 +1,247 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * Reason.java + * Reason = "Reason" HCOLON reason-value *(COMMA reason-value) + * reason-value = protocol *(SEMI reason-params) + * protocol = "SIP" / "Q.850" / token + * reason-params = protocol-cause / reason-text + * / reason-extension + * protocol-cause = "cause" EQUAL cause + * cause = 1*DIGIT + * reason-text = "text" EQUAL quoted-string + * reason-extension = generic-param + */ + +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.Utils; + +import java.text.ParseException; + +/** + * Definition of the Reason SIP Header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:34 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class Reason + extends ParametersHeader + implements javax.sip.header.ReasonHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -8903376965568297388L; + public final String TEXT = ParameterNames.TEXT; + public final String CAUSE = ParameterNames.CAUSE; + + protected String protocol; + + /** Get the cause token. + *@return the cause code. + */ + public int getCause() { + return getParameterAsInt(CAUSE); + } + + /** + * Set the cause. + * + *@param cause - cause to set. + */ + public void setCause(int cause) throws javax.sip.InvalidArgumentException { + this.parameters.set("cause", Integer.valueOf(cause)); + } + + /** Set the protocol + * + *@param protocol - protocol to set. + */ + + public void setProtocol(String protocol) throws ParseException { + this.protocol = protocol; + } + + /** Return the protocol. + * + *@return the protocol. + */ + public String getProtocol() { + return this.protocol; + } + + /** Set the text. + * + *@param text -- string text to set. + */ + public void setText(String text) throws ParseException { + // JvB: MUST be quoted + if ( text.charAt(0) != '"' ) { + text = Utils.getQuotedString(text); + } + this.parameters.set("text", text); + } + + /** Get the text. + * + *@return text parameter. + * + */ + public String getText() { + return this.parameters.getParameter("text"); + } + + /** Set the cause. + + /** Creates a new instance of Reason */ + public Reason() { + super(NAME); + } + + /** Gets the unique string name of this Header. A name constant is defined in + * each individual Header identifying each Header. + * + * @return the name of this specific Header + */ + public String getName() { + return NAME; + + } + + /** + * Encode the body of this header (the stuff that follows headerName). + * A.K.A headerValue. + */ + protected String encodeBody() { + StringBuffer s = new StringBuffer(); + s.append(protocol); + if (parameters != null && !parameters.isEmpty()) + s.append(SEMICOLON).append(parameters.encode()); + return s.toString(); + } + +} +/* + * $Log: Reason.java,v $ + * Revision 1.8 2009/10/18 13:46:34 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.7 2009/07/17 18:57:35 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2008/11/19 10:56:27 jbemmel + * Ensure that reason text is quoted + * + * Revision 1.5 2006/11/01 02:22:56 mranga + * Issue number: 83 + * Obtained from: + * Submitted by: + * Reviewed by: mranga + * fix thread safety issue in NameValueList and clean up some mess. + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/07/13 09:01:19 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ReasonList.java b/java/gov/nist/javax/sip/header/ReasonList.java new file mode 100644 index 0000000..dfa8fb9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ReasonList.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.List; + +import javax.sip.header.*; + +/** + * List of Reason headers. + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public final class ReasonList extends SIPHeaderList<Reason> { + + private static final long serialVersionUID = 7459989997463160670L; + + public Object clone() { + ReasonList retval = new ReasonList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default constructor + */ + public ReasonList() { + super(Reason.class, ReasonHeader.NAME); + } + + +} diff --git a/java/gov/nist/javax/sip/header/RecordRoute.java b/java/gov/nist/javax/sip/header/RecordRoute.java new file mode 100644 index 0000000..0261141 --- /dev/null +++ b/java/gov/nist/javax/sip/header/RecordRoute.java @@ -0,0 +1,92 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.address.*; + +/** + * The Request-Route header is added to a request by any proxy that insists on + * being in the path of subsequent requests for the same call leg. + * + *@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $ + * + *@author M. Ranganathan <br/> + * + * + * + */ +public class RecordRoute + extends AddressParametersHeader + implements javax.sip.header.RecordRouteHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 2388023364181727205L; + + /** + * constructor + * @param address address to set + */ + public RecordRoute(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public RecordRoute() { + super(RECORD_ROUTE); + + } + + /** Encode into canonical form. + *@return String containing the canonicaly encoded header. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(LESS_THAN); + } + address.encode(buffer); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(GREATER_THAN); + } + + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + this.parameters.encode(buffer); + } + return buffer; + } +} diff --git a/java/gov/nist/javax/sip/header/RecordRouteList.java b/java/gov/nist/javax/sip/header/RecordRouteList.java new file mode 100644 index 0000000..ba8dde1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/RecordRouteList.java @@ -0,0 +1,55 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * RecordRoute List of SIP headers (a collection of Addresses) + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class RecordRouteList extends SIPHeaderList<RecordRoute> { + + private static final long serialVersionUID = 1724940469426766691L; + public Object clone() { + RecordRouteList retval = new RecordRouteList(); + retval.clonehlist(this.hlist); + return retval; + } + /** Default constructor + */ + public RecordRouteList() { + super(RecordRoute.class, RecordRouteHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/ReferTo.java b/java/gov/nist/javax/sip/header/ReferTo.java new file mode 100644 index 0000000..b5c5b8f --- /dev/null +++ b/java/gov/nist/javax/sip/header/ReferTo.java @@ -0,0 +1,146 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.address.*; + +/** + * ReferTo SIP Header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public final class ReferTo + extends AddressParametersHeader + implements javax.sip.header.ReferToHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1666700428440034851L; + + /** default Constructor. + */ + public ReferTo() { + super(NAME); + } + + /** + * Encode the header content into a String. + * @return String + */ + protected String encodeBody() { + if (address == null) + return null; + String retval = ""; + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += LESS_THAN; + } + retval += address.encode(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += GREATER_THAN; + } + + if (!parameters.isEmpty()) { + retval += SEMICOLON + parameters.encode(); + } + return retval; + } +} +/* + * $Log: ReferTo.java,v $ + * Revision 1.6 2009/07/17 18:57:35 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.5 2006/07/13 09:01:40 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.3 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/ReplyTo.java b/java/gov/nist/javax/sip/header/ReplyTo.java new file mode 100644 index 0000000..dafc0ae --- /dev/null +++ b/java/gov/nist/javax/sip/header/ReplyTo.java @@ -0,0 +1,177 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.*; +import gov.nist.javax.sip.address.*; +import javax.sip.header.*; + +/** + * ReplyTo Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:36 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public final class ReplyTo + extends AddressParametersHeader + implements ReplyToHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -9103698729465531373L; + + /** Default constructor + */ + public ReplyTo() { + super(NAME); + } + + /** Default constructor given an address. + * + *@param address -- address of this header. + * + */ + public ReplyTo(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * Encode the header into a String. + * @return String + */ + public String encode() { + return headerName + COLON + SP + encodeBody() + NEWLINE; + } + + /** + * Encode the header content into a String. + * @return String + */ + public String encodeBody() { + String retval = ""; + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += LESS_THAN; + } + retval += address.encode(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += GREATER_THAN; + } + if (!parameters.isEmpty()) { + retval += SEMICOLON + parameters.encode(); + } + return retval; + } + + /** + * Conveniance accessor function to get the hostPort field from the address + * @return HostPort + */ + public HostPort getHostPort() { + return address.getHostPort(); + } + + /** + * Get the display name from the address. + * @return String + */ + public String getDisplayName() { + return address.getDisplayName(); + } +} +/* + * $Log: ReplyTo.java,v $ + * Revision 1.5 2009/07/17 18:57:36 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:31 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/RequestLine.java b/java/gov/nist/javax/sip/header/RequestLine.java new file mode 100644 index 0000000..7ef80b5 --- /dev/null +++ b/java/gov/nist/javax/sip/header/RequestLine.java @@ -0,0 +1,289 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.address.URI; + +import gov.nist.javax.sip.address.*; + +/** + * RequestLine of SIP Request. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/09/15 02:55:27 $ + * @author M. Ranganathan + */ +public class RequestLine extends SIPObject implements SipRequestLine { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3286426172326043129L; + + /** uri field. Note that this can be a SIP URI or a generic URI + * like tel URI. + */ + protected GenericURI uri; + + /** method field. + */ + protected String method; + + /** sipVersion field + */ + protected String sipVersion; + + /** Default constructor + */ + public RequestLine() { + sipVersion = "SIP/2.0"; + } + + + /** Encode the request line as a String. + * + * @return requestLine encoded as a string. + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (method != null) { + buffer.append(method); + buffer.append(SP); + } + if (uri != null) { + uri.encode(buffer); + buffer.append(SP); + } + buffer.append(sipVersion); + buffer.append(NEWLINE); + return buffer; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#getUri() + */ + public GenericURI getUri() { + return uri; + } + + /** Constructor given the request URI and the method. + */ + public RequestLine(GenericURI requestURI, String method) { + this.uri = requestURI; + this.method = method; + this.sipVersion = "SIP/2.0"; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#getMethod() + */ + public String getMethod() { + return method; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#getSipVersion() + */ + public String getSipVersion() { + return sipVersion; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#setUri(gov.nist.javax.sip.address.GenericURI) + */ + public void setUri(URI uri) { + this.uri = (GenericURI)uri; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#setMethod(java.lang.String) + */ + public void setMethod(String method) { + this.method = method; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#setSipVersion(java.lang.String) + */ + public void setSipVersion(String version) { + this.sipVersion = version; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#getVersionMajor() + */ + public String getVersionMajor() { + if (sipVersion == null) + return null; + String major = null; + boolean slash = false; + for (int i = 0; i < sipVersion.length(); i++) { + if (sipVersion.charAt(i) == '.') + break; + if (slash) { + if (major == null) + major = "" + sipVersion.charAt(i); + else + major += sipVersion.charAt(i); + } + if (sipVersion.charAt(i) == '/') + slash = true; + } + return major; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipRequestLine#getVersionMinor() + */ + public String getVersionMinor() { + if (sipVersion == null) + return null; + String minor = null; + boolean dot = false; + for (int i = 0; i < sipVersion.length(); i++) { + if (dot) { + if (minor == null) + minor = "" + sipVersion.charAt(i); + else + minor += sipVersion.charAt(i); + } + if (sipVersion.charAt(i) == '.') + dot = true; + } + return minor; + } + + /** + * Compare for equality. + * + *@param other object to compare with. We assume that all fields + * are set. + */ + public boolean equals(Object other) { + boolean retval; + if (!other.getClass().equals(this.getClass())) { + return false; + } + RequestLine that = (RequestLine) other; + try { + retval = + this.method.equals(that.method) + && this.uri.equals(that.uri) + && this.sipVersion.equals(that.sipVersion); + } catch (NullPointerException ex) { + retval = false; + } + return retval; + } + + public Object clone() { + RequestLine retval = (RequestLine) super.clone(); + if (this.uri != null) + retval.uri = (GenericURI) this.uri.clone(); + return retval; + } +} +/* + * $Log: RequestLine.java,v $ + * Revision 1.8 2009/09/15 02:55:27 mranga + * Issue number: 222 + * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String) + * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies + * during call transfer). + * + * Revision 1.7 2009/07/17 18:57:36 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2007/02/12 15:19:23 belangery + * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase. + * + * Revision 1.5 2006/07/13 09:01:26 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.3 2005/04/16 20:38:50 dmuresan + * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/Require.java b/java/gov/nist/javax/sip/header/Require.java new file mode 100644 index 0000000..d22cbed --- /dev/null +++ b/java/gov/nist/javax/sip/header/Require.java @@ -0,0 +1,165 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; +/** + * Require SIP Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:36 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + */ +public class Require extends SIPHeader implements RequireHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3743425404884053281L; + /** optionTag field + */ + protected String optionTag; + + /** + * Default constructor + */ + public Require() { + super(REQUIRE); + } + + /** constructor + * @param s String to set + */ + public Require(String s) { + super(REQUIRE); + optionTag = s; + } + + /** + * Encode in canonical form. + * @return String + */ + public String encodeBody() { + return optionTag; + } + + /** + * Sets the option tag value to the new supplied <var>optionTag</var> + * parameter. + * + * @param optionTag - the new string value of the option tag. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the optionTag value. + */ + public void setOptionTag(String optionTag) throws ParseException { + if (optionTag == null) + throw new NullPointerException( + "JAIN-SIP Exception, Require, " + + "setOptionTag(), the optionTag parameter is null"); + this.optionTag = optionTag; + } + + /** + * Gets the option tag of this OptionTag class. + * + * @return the string that identifies the option tag value. + */ + public String getOptionTag() { + return optionTag; + } +} +/* + * $Log: Require.java,v $ + * Revision 1.5 2009/07/17 18:57:36 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:22 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/RequireList.java b/java/gov/nist/javax/sip/header/RequireList.java new file mode 100644 index 0000000..0f6e08e --- /dev/null +++ b/java/gov/nist/javax/sip/header/RequireList.java @@ -0,0 +1,63 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** + * List of Require headers. + * <pre> + * Require = "Require" ":" 1#option-tag + * </pre> + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:36 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public final class RequireList extends SIPHeaderList<Require> { + + + private static final long serialVersionUID = -1760629092046963213L; + + public Object clone() { + RequireList retval = new RequireList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default constructor + */ + public RequireList() { + super(Require.class, RequireHeader.NAME); + } + + +} diff --git a/java/gov/nist/javax/sip/header/RetryAfter.java b/java/gov/nist/javax/sip/header/RetryAfter.java new file mode 100644 index 0000000..d2a23e3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/RetryAfter.java @@ -0,0 +1,191 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header; + +import javax.sip.*; +import java.text.ParseException; +import javax.sip.header.*; + +/** + * Retry-After SIP Header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/11/04 17:35:55 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + */ +public class RetryAfter extends ParametersHeader implements RetryAfterHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1029458515616146140L; + + /** constant DURATION parameter. + */ + public static final String DURATION = ParameterNames.DURATION; + + /** duration field + */ + protected Integer retryAfter = new Integer(0); + + /** comment field + */ + protected String comment; + + /** Default constructor + */ + public RetryAfter() { + super(NAME); + } + + /** Encode body of this into cannonical form. + * @return encoded body + */ + public String encodeBody() { + StringBuffer s = new StringBuffer(); + + if (retryAfter != null) + s.append(retryAfter); + + if (comment != null) + s.append(SP + LPAREN + comment + RPAREN); + + if (!parameters.isEmpty()) { + s.append(SEMICOLON + parameters.encode()); + } + + return s.toString(); + } + + /** Boolean function + * @return true if comment exist, false otherwise + */ + public boolean hasComment() { + return comment != null; + } + + /** remove comment field + */ + public void removeComment() { + comment = null; + } + + /** remove duration field + */ + public void removeDuration() { + super.removeParameter(DURATION); + } + + /** + * Sets the retry after value of the RetryAfterHeader. + * The retry after value MUST be greater than zero and + * MUST be less than 2**31. + * + * @param retryAfter - the new retry after value of this RetryAfterHeader + * @throws InvalidArgumentException if supplied value is less than zero. + * + */ + + public void setRetryAfter(int retryAfter) throws InvalidArgumentException { + if (retryAfter < 0) + throw new InvalidArgumentException( + "invalid parameter " + retryAfter); + this.retryAfter = Integer.valueOf(retryAfter); + } + + /** + * Gets the retry after value of the RetryAfterHeader. This retry after + * value is relative time. + * + * @return the retry after value of the RetryAfterHeader. + * + */ + + public int getRetryAfter() { + return retryAfter.intValue(); + } + + /** + * Gets the comment of RetryAfterHeader. + * + * @return the comment of this RetryAfterHeader, return null if no comment + * is available. + */ + + public String getComment() { + return comment; + } + + /** + * Sets the comment value of the RetryAfterHeader. + * + * @param comment - the new comment string value of the RetryAfterHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the comment. + */ + + public void setComment(String comment) throws ParseException { + if (comment == null) + throw new NullPointerException("the comment parameter is null"); + this.comment = comment; + } + + /** + * Sets the duration value of the RetryAfterHeader. The retry after value + * MUST be greater than zero and MUST be less than 2**31. + * + * @param duration - the new duration value of this RetryAfterHeader + * @throws InvalidArgumentException if supplied value is less than zero. + * + */ + + public void setDuration(int duration) throws InvalidArgumentException { + if (duration < 0) + throw new InvalidArgumentException("the duration parameter is <0"); + this.setParameter(DURATION, duration); + } + + /** + * Gets the duration value of the RetryAfterHeader. This duration value + * is relative time. + * + * @return the duration value of the RetryAfterHeader, return zero if not + * set. + * + */ + + public int getDuration() { + if (this.getParameter(DURATION) == null) return -1; + else return super.getParameterAsInt(DURATION); + } +} diff --git a/java/gov/nist/javax/sip/header/Route.java b/java/gov/nist/javax/sip/header/Route.java new file mode 100644 index 0000000..257f29b --- /dev/null +++ b/java/gov/nist/javax/sip/header/Route.java @@ -0,0 +1,111 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.address.AddressImpl; + +import javax.sip.header.RouteHeader; + +/** + * Route SIPHeader Object + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:36 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class Route + extends AddressParametersHeader + implements javax.sip.header.RouteHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 5683577362998368846L; + + /** Default constructor + */ + public Route() { + super(NAME); + } + + /** Default constructor given an address. + * + *@param address -- address of this header. + * + */ + + public Route(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * Hashcode so this header can be inserted into a set. + * + *@return the hashcode of the encoded address. + */ + public int hashCode() { + return this.address.getHostPort().encode().toLowerCase().hashCode(); + } + + /** + * Encode into canonical form. + * Acknowledgement: contains a bug fix for a bug reported by + * Laurent Schwizer + * + *@return a canonical encoding of the header. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + boolean addrFlag = address.getAddressType() == AddressImpl.NAME_ADDR; + if (!addrFlag) { + buffer.append('<'); + address.encode(buffer); + buffer.append('>'); + } else { + address.encode(buffer); + } + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + return buffer; + } + + public boolean equals(Object other) { + return (other instanceof RouteHeader) && super.equals(other); + } + +} + diff --git a/java/gov/nist/javax/sip/header/RouteList.java b/java/gov/nist/javax/sip/header/RouteList.java new file mode 100644 index 0000000..a2c0aff --- /dev/null +++ b/java/gov/nist/javax/sip/header/RouteList.java @@ -0,0 +1,89 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.util.*; + +/** + * A list of Route Headers. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:36 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class RouteList extends SIPHeaderList<Route> { + + private static final long serialVersionUID = 3407603519354809748L; + + + /** default constructor + */ + public RouteList() { + super(Route.class, RouteHeader.NAME); + + } + + public Object clone() { + RouteList retval = new RouteList(); + retval.clonehlist(this.hlist); + return retval; + } + + public String encode() { + if ( super.hlist.isEmpty()) return ""; + else return super.encode(); + } + + + /** + * Order is important when comparing route lists. + */ + public boolean equals(Object other) { + if (!(other instanceof RouteList)) + return false; + RouteList that = (RouteList) other; + if (this.size() != that.size()) + return false; + ListIterator<Route> it = this.listIterator(); + ListIterator<Route> it1 = that.listIterator(); + while (it.hasNext()) { + Route route = (Route) it.next(); + Route route1 = (Route) it1.next(); + if (!route.equals(route1)) + return false; + } + return true; + } + + +} diff --git a/java/gov/nist/javax/sip/header/SIPDate.java b/java/gov/nist/javax/sip/header/SIPDate.java new file mode 100644 index 0000000..3668d33 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPDate.java @@ -0,0 +1,612 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.core.*; +import java.util.Calendar; +import java.util.TimeZone; +import java.util.Locale; +import java.util.GregorianCalendar; +import java.io.Serializable; +import java.lang.IllegalArgumentException; + +/** +* Implements a parser class for tracking expiration time +* when specified as a Date value. +*<pre> +* From the HTTP 1.1 spec +*14.18 Date +* +* The Date general-header field represents the date and time at which +* the message was originated, having the same semantics as orig-date in +* RFC 822. The field value is an HTTP-date, as described in section +* 3.3.1; it MUST be sent in RFC 1123 [8]-date format. + +* Date = "Date" ":" HTTP-date +* +* An example is +* +* Date: Tue, 15 Nov 1994 08:12:31 GMT +*</pre> +* +*@version 1.2 $Revision: 1.9 $ $Date: 2009/10/18 13:46:33 $ +* +*@author M. Ranganathan <br/> +* +* +* +* +*/ + +public class SIPDate implements Cloneable,Serializable { + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 8544101899928346909L; + public static final String GMT = "GMT"; + public static final String MON = "Mon"; + public static final String TUE = "Tue"; + public static final String WED = "Wed"; + public static final String THU = "Thu"; + public static final String FRI = "Fri"; + public static final String SAT = "Sat"; + public static final String SUN = "Sun"; + public static final String JAN = "Jan"; + public static final String FEB = "Feb"; + public static final String MAR = "Mar"; + public static final String APR = "Apr"; + public static final String MAY = "May"; + public static final String JUN = "Jun"; + public static final String JUL = "Jul"; + public static final String AUG = "Aug"; + public static final String SEP = "Sep"; + public static final String OCT = "Oct"; + public static final String NOV = "Nov"; + public static final String DEC = "Dec"; + + /** sipWkDay member + */ + protected String sipWkDay; + + /** sipMonth member + */ + protected String sipMonth; + + /** wkday member + */ + protected int wkday; + + /** day member + */ + protected int day; + + /** month member + */ + protected int month; + + /** year member + */ + protected int year; + + /** hour member + */ + protected int hour; + + /** minute member + */ + protected int minute; + + /** second member + */ + protected int second; + + /** javaCal member + */ + private java.util.Calendar javaCal; + + /** equality check. + * + *@return true if the two date fields are equals + */ + public boolean equals(Object that){ + if (that.getClass() != this.getClass())return false; + SIPDate other = (SIPDate)that; + return this.wkday == other.wkday && + this.day == other.day && + this.month == other.month && + this.year == other.year && + this.hour == other.hour && + this.minute == other.minute && + this.second == other.second; + } + + /** + * Initializer, sets all the fields to invalid values. + */ + public SIPDate() { + wkday = -1; + day = -1; + month = -1; + year = -1; + hour = -1; + minute = -1; + second = -1; + javaCal = null; + } + + /** + * Construct a SIP date from the time offset given in miliseconds + * @param timeMillis long to set + */ + public SIPDate(long timeMillis) { + javaCal = + new GregorianCalendar( + TimeZone.getTimeZone("GMT:0"), + Locale.getDefault()); + java.util.Date date = new java.util.Date(timeMillis); + javaCal.setTime(date); + wkday = javaCal.get(Calendar.DAY_OF_WEEK); + switch (wkday) { + case Calendar.MONDAY : + sipWkDay = MON; + break; + case Calendar.TUESDAY : + sipWkDay = TUE; + break; + case Calendar.WEDNESDAY : + sipWkDay = WED; + break; + case Calendar.THURSDAY : + sipWkDay = THU; + break; + case Calendar.FRIDAY : + sipWkDay = FRI; + break; + case Calendar.SATURDAY : + sipWkDay = SAT; + break; + case Calendar.SUNDAY : + sipWkDay = SUN; + break; + default : + InternalErrorHandler.handleException( + "No date map for wkday " + wkday); + } + + day = javaCal.get(Calendar.DAY_OF_MONTH); + month = javaCal.get(Calendar.MONTH); + switch (month) { + case Calendar.JANUARY : + sipMonth = JAN; + break; + case Calendar.FEBRUARY : + sipMonth = FEB; + break; + case Calendar.MARCH : + sipMonth = MAR; + break; + case Calendar.APRIL : + sipMonth = APR; + break; + case Calendar.MAY : + sipMonth = MAY; + break; + case Calendar.JUNE : + sipMonth = JUN; + break; + case Calendar.JULY : + sipMonth = JUL; + break; + case Calendar.AUGUST : + sipMonth = AUG; + break; + case Calendar.SEPTEMBER : + sipMonth = SEP; + break; + case Calendar.OCTOBER : + sipMonth = OCT; + break; + case Calendar.NOVEMBER : + sipMonth = NOV; + break; + case Calendar.DECEMBER : + sipMonth = DEC; + break; + default : + InternalErrorHandler.handleException( + "No date map for month " + month); + } + year = javaCal.get(Calendar.YEAR); + // Bug report by Bruno Konik + hour = javaCal.get(Calendar.HOUR_OF_DAY); + minute = javaCal.get(Calendar.MINUTE); + second = javaCal.get(Calendar.SECOND); + } + + /** + * Get canonical string representation. + * @return String + */ + public String encode() { + + String dayString; + if (day < 10) { + dayString = "0" + day; + } else + dayString = "" + day; + + String hourString; + if (hour < 10) { + hourString = "0" + hour; + } else + hourString = "" + hour; + + String minuteString; + if (minute < 10) { + minuteString = "0" + minute; + } else + minuteString = "" + minute; + + String secondString; + if (second < 10) { + secondString = "0" + second; + } else + secondString = "" + second; + + String encoding = ""; + + if (sipWkDay != null) + encoding += sipWkDay + Separators.COMMA + Separators.SP; + + encoding += dayString + Separators.SP; + + if (sipMonth != null) + encoding += sipMonth + Separators.SP; + + encoding += year + + Separators.SP + + hourString + + Separators.COLON + + minuteString + + Separators.COLON + + secondString + + Separators.SP + + GMT; + + return encoding; + } + + /** + * The only accessor we allow is to the java calendar record. + * All other fields are for this package only. + * @return Calendar + */ + public java.util.Calendar getJavaCal() { + if (javaCal == null) + setJavaCal(); + return javaCal; + } + + /** get the WkDay field + * @return String + */ + public String getWkday() { + return sipWkDay; + } + + /** get the month + * @return String + */ + public String getMonth() { + return sipMonth; + } + + /** get the hour + * @return int + */ + public int getHour() { + return hour; + } + + /** get the minute + * @return int + */ + public int getMinute() { + return minute; + } + + /** get the second + * @return int + */ + public int getSecond() { + return second; + } + + /** + * convert the SIP Date of this structure to a Java Date. + * SIP Dates are forced to be GMT. Stores the converted time + * as a java Calendar class. + */ + private void setJavaCal() { + javaCal = + new GregorianCalendar( + TimeZone.getTimeZone("GMT:0"), + Locale.getDefault()); + if (year != -1) + javaCal.set(Calendar.YEAR, year); + if (day != -1) + javaCal.set(Calendar.DAY_OF_MONTH, day); + if (month != -1) + javaCal.set(Calendar.MONTH, month); + if (wkday != -1) + javaCal.set(Calendar.DAY_OF_WEEK, wkday); + if (hour != -1) + javaCal.set(Calendar.HOUR, hour); + if (minute != -1) + javaCal.set(Calendar.MINUTE, minute); + if (second != -1) + javaCal.set(Calendar.SECOND, second); + } + + /** + * Set the wkday member + * @param w String to set + * @throws IllegalArgumentException if w is not a valid day. + */ + public void setWkday(String w) throws IllegalArgumentException { + sipWkDay = w; + if (sipWkDay.compareToIgnoreCase(MON) == 0) { + wkday = Calendar.MONDAY; + } else if (sipWkDay.compareToIgnoreCase(TUE) == 0) { + wkday = Calendar.TUESDAY; + } else if (sipWkDay.compareToIgnoreCase(WED) == 0) { + wkday = Calendar.WEDNESDAY; + } else if (sipWkDay.compareToIgnoreCase(THU) == 0) { + wkday = Calendar.THURSDAY; + } else if (sipWkDay.compareToIgnoreCase(FRI) == 0) { + wkday = Calendar.FRIDAY; + } else if (sipWkDay.compareToIgnoreCase(SAT) == 0) { + wkday = Calendar.SATURDAY; + } else if (sipWkDay.compareToIgnoreCase(SUN) == 0) { + wkday = Calendar.SUNDAY; + } else { + throw new IllegalArgumentException("Illegal Week day :" + w); + } + } + + /** + * Set the day member + * @param d int to set + * @throws IllegalArgumentException if d is not a valid day + */ + public void setDay(int d) throws IllegalArgumentException { + if (d < 1 || d > 31) + throw new IllegalArgumentException( + "Illegal Day of the month " + Integer.toString(d)); + day = d; + } + + /** + * Set the month member + * @param m String to set. + * @throws IllegalArgumentException if m is not a valid month + */ + public void setMonth(String m) throws IllegalArgumentException { + sipMonth = m; + if (sipMonth.compareToIgnoreCase(JAN) == 0) { + month = Calendar.JANUARY; + } else if (sipMonth.compareToIgnoreCase(FEB) == 0) { + month = Calendar.FEBRUARY; + } else if (sipMonth.compareToIgnoreCase(MAR) == 0) { + month = Calendar.MARCH; + } else if (sipMonth.compareToIgnoreCase(APR) == 0) { + month = Calendar.APRIL; + } else if (sipMonth.compareToIgnoreCase(MAY) == 0) { + month = Calendar.MAY; + } else if (sipMonth.compareToIgnoreCase(JUN) == 0) { + month = Calendar.JUNE; + } else if (sipMonth.compareToIgnoreCase(JUL) == 0) { + month = Calendar.JULY; + } else if (sipMonth.compareToIgnoreCase(AUG) == 0) { + month = Calendar.AUGUST; + } else if (sipMonth.compareToIgnoreCase(SEP) == 0) { + month = Calendar.SEPTEMBER; + } else if (sipMonth.compareToIgnoreCase(OCT) == 0) { + month = Calendar.OCTOBER; + } else if (sipMonth.compareToIgnoreCase(NOV) == 0) { + month = Calendar.NOVEMBER; + } else if (sipMonth.compareToIgnoreCase(DEC) == 0) { + month = Calendar.DECEMBER; + } else { + throw new IllegalArgumentException("Illegal Month :" + m); + } + } + + /** + * Set the year member + * @param y int to set + * @throws IllegalArgumentException if y is not a valid year. + */ + public void setYear(int y) throws IllegalArgumentException { + if (y < 0) + throw new IllegalArgumentException("Illegal year : " + y); + javaCal = null; + year = y; + } + + /** + * Get the year member. + */ + public int getYear() { + return year; + } + + /** + * Set the hour member + * @param h int to set + * @throws IllegalArgumentException if h is not a valid hour. + */ + public void setHour(int h) throws IllegalArgumentException { + if (h < 0 || h > 24) + throw new IllegalArgumentException("Illegal hour : " + h); + javaCal = null; + hour = h; + } + + /** + * Set the minute member + * @param m int to set + * @throws IllegalArgumentException if m is not a valid minute + */ + public void setMinute(int m) throws IllegalArgumentException { + if (m < 0 || m >= 60) + throw new IllegalArgumentException( + "Illegal minute : " + (Integer.toString(m))); + javaCal = null; + minute = m; + } + + /** + * Set the second member + * @param s int to set + * @throws IllegalArgumentException if s is not a valid second + */ + public void setSecond(int s) throws IllegalArgumentException { + if (s < 0 || s >= 60) + throw new IllegalArgumentException( + "Illegal second : " + Integer.toString(s)); + javaCal = null; + second = s; + } + + /** Get the time offset from the current time. + * + *@return offset from the current time. + */ + public int getDeltaSeconds() { + // long ctime = this.getJavaCal().getTimeInMillis(); + long ctime = this.getJavaCal().getTime().getTime(); + return (int) (ctime - System.currentTimeMillis()) / 1000; + } + + public Object clone() { + SIPDate retval; + try { + retval = (SIPDate) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Internal error"); + } + if (javaCal != null) + retval.javaCal = (java.util.Calendar) javaCal.clone(); + return retval; + } +} +/* + * $Log: SIPDate.java,v $ + * Revision 1.9 2009/10/18 13:46:33 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.8 2009/07/17 18:57:37 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:01:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2005/04/16 20:35:10 dmuresan + * SIPDate made cloneable. + * + * Revision 1.4 2004/07/28 14:41:53 mranga + * Submitted by: mranga + * + * fixed equality check for SIPDate. + * + * Revision 1.3 2004/04/05 21:46:08 mranga + * Submitted by: Bruno Konik + * Reviewed by: mranga + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/SIPDateHeader.java b/java/gov/nist/javax/sip/header/SIPDateHeader.java new file mode 100644 index 0000000..ead5e79 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPDateHeader.java @@ -0,0 +1,171 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.*; +import javax.sip.header.*; + +/** +* Date Header. +* +*@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:37 $ +* +*@author M. Ranganathan <br/> +*@author Olivier Deruelle <br/> +* +* +*/ +public class SIPDateHeader extends SIPHeader implements DateHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 1734186339037274664L; + /** date field + */ + protected SIPDate date; + + /** Default constructor. + */ + public SIPDateHeader() { + super(DATE); + } + + /** Encode the header into a String. + * @return String + */ + public String encodeBody() { + return date.encode(); + } + + /** + * Set the date member + * @param d SIPDate to set + */ + public void setDate(SIPDate d) { + date = d; + + } + + /** + * Sets date of DateHeader. The date is repesented by the Calendar object. + * + * @param dat the Calendar object date of this header. + */ + public void setDate(Calendar dat) { + if (dat != null) + date = new SIPDate(dat.getTime().getTime()); + } + + /** + * Gets the date of DateHeader. The date is repesented by the Calender + * object. + * + * @return the Calendar object representing the date of DateHeader + */ + public Calendar getDate() { + if (date == null) + return null; + return date.getJavaCal(); + } + + public Object clone() { + SIPDateHeader retval = (SIPDateHeader) super.clone(); + if (this.date != null) + retval.date = (SIPDate) this.date.clone(); + return retval; + } +} +/* + * $Log: SIPDateHeader.java,v $ + * Revision 1.6 2009/07/17 18:57:37 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.5 2006/07/13 09:01:23 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:26 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.3 2005/04/16 20:38:50 dmuresan + * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/SIPETag.java b/java/gov/nist/javax/sip/header/SIPETag.java new file mode 100644 index 0000000..e629c1c --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPETag.java @@ -0,0 +1,101 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.text.ParseException; + +/** + * the SIP-ETag header. + * + * @author Jeroen van Bemmel<br/> + * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:57:37 $ + * @since 1.2 + */ +public class SIPETag extends SIPHeader implements SIPETagHeader , ExtensionHeader{ + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 3837543366074322107L; + + /** + * entity tag field + */ + protected String entityTag; + + /** Default constructor + */ + public SIPETag() { + super(NAME); + } + + public SIPETag( String tag ) throws ParseException { + this(); + this.setETag( tag ); + } + + + /** + * Encode into canonical form. + * @return String + */ + public String encodeBody() { + return entityTag; + } + + /** + * get the priority value. + * @return String + */ + public String getETag() { + return entityTag; + } + + /** + * Set the priority member + * @param etag String to set + */ + public void setETag(String etag) throws ParseException { + if (etag == null) + throw new NullPointerException( + "JAIN-SIP Exception," + + "SIP-ETag, setETag(), the etag parameter is null"); + this.entityTag = etag; + } + + /** + * This method needs to be added for backwards compatibility to + * avoid ClassCast exception on V1.1 applications + * + * @see javax.sip.header.ExtensionHeader#setValue(java.lang.String) + */ + public void setValue(String value) throws ParseException { + this.setETag(value); + + } +} diff --git a/java/gov/nist/javax/sip/header/SIPHeader.java b/java/gov/nist/javax/sip/header/SIPHeader.java new file mode 100644 index 0000000..f70ebf1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPHeader.java @@ -0,0 +1,157 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +/** + * Root class from which all SIPHeader objects are subclassed. + * + * @author M. Ranganathan <br/> + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:37 $ + * + * + */ +public abstract class SIPHeader + extends SIPObject + implements SIPHeaderNames, javax.sip.header.Header, HeaderExt { + + /** name of this header + */ + protected String headerName; + + /** Value of the header. + */ + + /** Constructor + * @param hname String to set + */ + protected SIPHeader(String hname) { + headerName = hname; + } + + /** Default constructor + */ + public SIPHeader() { + } + + /** + * Name of the SIPHeader + * @return String + */ + public String getHeaderName() { + return headerName; + } + + /** Alias for getHaderName above. + * + *@return String headerName + * + */ + public String getName() { + return this.headerName; + } + + /** + * Set the name of the header . + * @param hdrname String to set + */ + public void setHeaderName(String hdrname) { + headerName = hdrname; + } + + /** Get the header value (i.e. what follows the name:). + * This merely goes through and lops off the portion that follows + * the headerName: + */ + public String getHeaderValue() { + String encodedHdr = null; + try { + encodedHdr = this.encode(); + } catch (Exception ex) { + return null; + } + StringBuffer buffer = new StringBuffer(encodedHdr); + while (buffer.length() > 0 && buffer.charAt(0) != ':') { + buffer.deleteCharAt(0); + } + if (buffer.length() > 0) + buffer.deleteCharAt(0); + return buffer.toString().trim(); + } + + /** Return false if this is not a header list + * (SIPHeaderList overrrides this method). + *@return false + */ + public boolean isHeaderList() { + return false; + } + + /** Encode this header into canonical form. + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + buffer.append(this.headerName).append(COLON).append(SP); + this.encodeBody(buffer); + buffer.append(NEWLINE); + return buffer; + } + + /** Encode the body of this header (the stuff that follows headerName). + * A.K.A headerValue. + */ + protected abstract String encodeBody(); + + /** Encode the body of this header in the given buffer. + * Default implementation calls encodeBody(); + */ + protected StringBuffer encodeBody(StringBuffer buffer) { + return buffer.append(encodeBody()); + } + + /** Alias for getHeaderValue. + */ + public String getValue() { + return this.getHeaderValue(); + } + + /** + * This is a pretty simple hashCode but satisfies requirements. + * + */ + public int hashCode() { + return this.headerName.hashCode(); + } + + public final String toString() { + return this.encode(); + } +} diff --git a/java/gov/nist/javax/sip/header/SIPHeaderList.java b/java/gov/nist/javax/sip/header/SIPHeaderList.java new file mode 100644 index 0000000..d11506a --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPHeaderList.java @@ -0,0 +1,669 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.GenericObject; +import gov.nist.core.Separators; +import gov.nist.javax.sip.header.ims.PrivacyHeader; + +import javax.sip.header.Header; +import java.lang.reflect.Constructor; +import java.util.*; + +/** + * + * This is the root class for all lists of SIP headers. It imbeds a + * SIPObjectList object and extends SIPHeader Lists of ContactSIPObjects etc. + * derive from this class. This supports homogeneous lists (all elements in the + * list are of the same class). We use this for building type homogeneous lists + * of SIPObjects that appear in SIPHeaders + * + * @version 1.2 $Revision: 1.15 $ $Date: 2005/10/09 18:47:53 + */ +public abstract class SIPHeaderList<HDR extends SIPHeader> extends SIPHeader implements java.util.List<HDR>, Header { + + private static boolean prettyEncode = false; + /** + * hlist field. + */ + protected List<HDR> hlist; + + private Class<HDR> myClass; + + public String getName() { + return this.headerName; + } + + + private SIPHeaderList() { + hlist = new LinkedList<HDR>(); + } + + /** + * Constructor + * + * @param objclass + * Class to set + * @param hname + * String to set + */ + protected SIPHeaderList(Class<HDR> objclass, String hname) { + this(); + this.headerName = hname; + this.myClass = objclass; + } + + /** + * Concatenate the list of stuff that we are keeping around and also the + * text corresponding to these structures (that we parsed). + * + * @param objectToAdd + */ + public boolean add(HDR objectToAdd) { + hlist.add((HDR)objectToAdd); + return true; + } + + /** + * Concatenate the list of stuff that we are keeping around and also the + * text corresponding to these structures (that we parsed). + * + * @param obj + * Genericobject to set + */ + public void addFirst(HDR obj) { + hlist.add(0,(HDR) obj); + } + + /** + * Add to this list. + * + * @param sipheader + * SIPHeader to add. + * @param top + * is true if we want to add to the top of the list. + */ + public void add(HDR sipheader, boolean top) { + if (top) + this.addFirst(sipheader); + else + this.add(sipheader); + } + + /** + * Concatenate two compatible lists. This appends or prepends the new list + * to the end of this list. + * + * @param other + * SIPHeaderList to set + * @param topFlag + * flag which indicates which end to concatenate + * the lists. + * @throws IllegalArgumentException + * if the two lists are not compatible + */ + public void concatenate(SIPHeaderList<HDR> other, boolean topFlag) + throws IllegalArgumentException { + if (!topFlag) { + this.addAll(other); + } else { + // add given items to the top end of the list. + this.addAll(0, other); + } + + } + + + + /** + * Encode a list of sip headers. Headers are returned in cannonical form. + * + * @return String encoded string representation of this list of headers. + * (Contains string append of each encoded header). + */ + public String encode() { + return encode(new StringBuffer()).toString(); + } + + public StringBuffer encode(StringBuffer buffer) { + if (hlist.isEmpty()) { + buffer.append(headerName).append(':').append(Separators.NEWLINE); + } + else { + // The following headers do not have comma separated forms for + // multiple headers. Thus, they must be encoded separately. + if (this.headerName.equals(SIPHeaderNames.WWW_AUTHENTICATE) + || this.headerName.equals(SIPHeaderNames.PROXY_AUTHENTICATE) + || this.headerName.equals(SIPHeaderNames.AUTHORIZATION) + || this.headerName.equals(SIPHeaderNames.PROXY_AUTHORIZATION) + || (prettyEncode && + (this.headerName.equals(SIPHeaderNames.VIA) || this.headerName.equals(SIPHeaderNames.ROUTE) || this.headerName.equals(SIPHeaderNames.RECORD_ROUTE))) // Less confusing to read + || this.getClass().equals( ExtensionHeaderList.class) ) { + ListIterator<HDR> li = hlist.listIterator(); + while (li.hasNext()) { + HDR sipheader = (HDR) li.next(); + sipheader.encode(buffer); + } + } else { + // These can be concatenated together in an comma separated + // list. + buffer.append(headerName).append(Separators.COLON).append(Separators.SP); + this.encodeBody(buffer); + buffer.append(Separators.NEWLINE); + } + } + return buffer; + } + + /** + * Return a list of encoded strings (one for each sipheader). + * + * @return LinkedList containing encoded strings in this header list. an + * empty list is returned if this header list contains no sip + * headers. + */ + + public List<String> getHeadersAsEncodedStrings() { + List<String> retval = new LinkedList<String>(); + + ListIterator<HDR> li = hlist.listIterator(); + while (li.hasNext()) { + Header sipheader = li.next(); + retval.add(sipheader.toString()); + + } + + return retval; + + } + + /** + * Get the first element of this list. + * + * @return SIPHeader first element of the list. + */ + public Header getFirst() { + if (hlist == null || hlist.isEmpty()) + return null; + else + return hlist.get(0); + } + + /** + * Get the last element of this list. + * + * @return SIPHeader last element of the list. + */ + public Header getLast() { + if (hlist == null || hlist.isEmpty()) + return null; + return hlist.get(hlist.size() - 1); + } + + /** + * Get the class for the headers of this list. + * + * @return Class of header supported by this list. + */ + public Class<HDR> getMyClass() { + return this.myClass; + } + + /** + * Empty check + * + * @return boolean true if list is empty + */ + public boolean isEmpty() { + return hlist.isEmpty(); + } + + /** + * Get an initialized iterator for my imbedded list + * + * @return the generated ListIterator + */ + public ListIterator<HDR> listIterator() { + + return hlist.listIterator(0); + } + + /** + * Get the imbedded linked list. + * + * @return the imedded linked list of SIP headers. + */ + public List<HDR> getHeaderList() { + return this.hlist; + } + + /** + * Get the list iterator for a given position. + * + * @param position + * position for the list iterator to return + * @return the generated list iterator + */ + public ListIterator<HDR> listIterator(int position) { + return hlist.listIterator(position); + } + + /** + * Remove the first element of this list. + */ + public void removeFirst() { + if (hlist.size() != 0) + hlist.remove(0); + + } + + /** + * Remove the last element of this list. + */ + public void removeLast() { + if (hlist.size() != 0) + hlist.remove(hlist.size() - 1); + } + + /** + * Remove a sip header from this list of sip headers. + * + * @param obj + * SIPHeader to remove + * @return boolean + */ + public boolean remove(HDR obj) { + if (hlist.size() == 0) + return false; + else + return hlist.remove(obj); + } + + /** + * Set the root class for all objects inserted into my list (for assertion + * check) + * + * @param cl + * class to set + */ + protected void setMyClass(Class<HDR> cl) { + this.myClass = cl; + } + + /** + * convert to a string representation (for printing). + * + * @param indentation + * int to set + * @return String string representation of object (for printing). + */ + public String debugDump(int indentation) { + stringRepresentation = ""; + String indent = new Indentation(indentation).getIndentation(); + + String className = this.getClass().getName(); + sprint(indent + className); + sprint(indent + "{"); + + for (Iterator<HDR> it = hlist.iterator(); it.hasNext();) { + HDR sipHeader = (HDR) it.next(); + sprint(indent + sipHeader.debugDump()); + } + sprint(indent + "}"); + return stringRepresentation; + } + + /** + * convert to a string representation + * + * @return String + */ + public String debugDump() { + return debugDump(0); + } + + /** + * Array conversion. + * + * @return SIPHeader [] + */ + public Object[] toArray() { + return hlist.toArray(); + + } + + /** + * index of an element. + * + * @return index of the given element (-1) if element does not exist. + */ + public int indexOf(GenericObject gobj) { + return hlist.indexOf(gobj); + } + + /** + * insert at a location. + * + * @param index + * location where to add the sipHeader. + * @param sipHeader + * SIPHeader structure to add. + */ + + public void add(int index, HDR sipHeader) + throws IndexOutOfBoundsException { + hlist.add(index, sipHeader); + } + + /** + * Equality comparison operator. + * + * @param other + * the other object to compare with. true is returned iff the + * classes match and list of headers herein is equal to the list + * of headers in the target (order of the headers is not + * important). + */ + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + + if (other == this) + return true; + + if (other instanceof SIPHeaderList) { + SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) other; + if (this.hlist == that.hlist) + return true; + else if (this.hlist == null) + return that.hlist == null || that.hlist.size() == 0; + return this.hlist.equals(that.hlist); + } + return false; + } + + /** + * Template match against a template. null field in template indicates wild + * card match. + */ + public boolean match(SIPHeaderList<?> template) { + if (template == null) + return true; + if (!this.getClass().equals(template.getClass())) + return false; + SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) template; + if (this.hlist == that.hlist) + return true; + else if (this.hlist == null) + return false; + else { + + for (Iterator<SIPHeader> it = that.hlist.iterator(); it.hasNext();) { + SIPHeader sipHeader = (SIPHeader) it.next(); + + boolean found = false; + for (Iterator<HDR> it1 = this.hlist.iterator(); it1.hasNext() + && !found;) { + SIPHeader sipHeader1 = (SIPHeader) it1.next(); + found = sipHeader1.match(sipHeader); + } + if (!found) + return false; + } + return true; + } + } + + + /** + * make a clone of this header list. + * + * @return clone of this Header. + */ + public Object clone() { + try { + Class<?> clazz = this.getClass(); + + Constructor<?> cons = clazz.getConstructor((Class[])null); + SIPHeaderList<HDR> retval = (SIPHeaderList<HDR>) cons.newInstance((Object[])null); + retval.headerName = this.headerName; + retval.myClass = this.myClass; + return retval.clonehlist(this.hlist); + } catch (Exception ex) { + throw new RuntimeException("Could not clone!", ex); + } + } + + protected final SIPHeaderList<HDR> clonehlist(List<HDR> hlistToClone) { + if (hlistToClone != null) { + for (Iterator<HDR> it = (Iterator<HDR>) hlistToClone.iterator(); it.hasNext();) { + Header h = it.next(); + this.hlist.add((HDR)h.clone()); + } + } + return this; + } + + /** + * Get the number of headers in the list. + */ + public int size() { + return hlist.size(); + } + + /** + * Return true if this is a header list (overrides the base class method + * which returns false). + * + * @return true + */ + public boolean isHeaderList() { + return true; + } + + /** + * Encode the body of this header (the stuff that follows headerName). A.K.A + * headerValue. This will not give a reasonable result for WWW-Authenticate, + * Authorization, Proxy-Authenticate and Proxy-Authorization and hence this + * is protected. + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + ListIterator<HDR> iterator = this.listIterator(); + while (true) { + SIPHeader sipHeader = (SIPHeader) iterator.next(); + if ( sipHeader == this ) throw new RuntimeException ("Unexpected circularity in SipHeaderList"); + sipHeader.encodeBody(buffer); + // if (body.equals("")) System.out.println("BODY == "); + if (iterator.hasNext()) { + if (!this.headerName.equals(PrivacyHeader.NAME)) + buffer.append(Separators.COMMA); + else + buffer.append(Separators.SEMICOLON); + continue; + } else + break; + + } + return buffer; + } + + public boolean addAll(Collection<? extends HDR> collection) { + return this.hlist.addAll(collection); + } + + public boolean addAll(int index, Collection<? extends HDR> collection) { + return this.hlist.addAll(index, collection); + + } + + public boolean containsAll(Collection<?> collection) { + return this.hlist.containsAll(collection); + } + + + + + public void clear() { + this.hlist.clear(); + } + + public boolean contains(Object header) { + return this.hlist.contains(header); + } + + + /** + * Get the object at the specified location. + * + * @param index -- + * location from which to get the object. + * + */ + public HDR get(int index) { + return this.hlist.get(index); + } + + /** + * Return the index of a given object. + * + * @param obj -- + * object whose index to compute. + */ + public int indexOf(Object obj) { + return this.hlist.indexOf(obj); + } + + /** + * Return the iterator to the imbedded list. + * + * @return iterator to the imbedded list. + * + */ + + public java.util.Iterator<HDR> iterator() { + return this.hlist.listIterator(); + } + + /** + * Get the last index of the given object. + * + * @param obj -- + * object whose index to find. + */ + public int lastIndexOf(Object obj) { + + return this.hlist.lastIndexOf(obj); + } + + /** + * Remove the given object. + * + * @param obj -- + * object to remove. + * + */ + + public boolean remove(Object obj) { + + return this.hlist.remove(obj); + } + + /** + * Remove the object at a given index. + * + * @param index -- + * index at which to remove the object + */ + + public HDR remove(int index) { + return this.hlist.remove(index); + } + + /** + * Remove all the elements. + * @see List#removeAll(java.util.Collection) + */ + public boolean removeAll(java.util.Collection<?> collection) { + return this.hlist.removeAll(collection); + } + + + /** + * @see List#retainAll(java.util.Collection) + * @param collection + */ + public boolean retainAll(java.util.Collection<?> collection) { + return this.hlist.retainAll(collection); + } + + /** + * Get a sublist of the list. + * + * @see List#subList(int, int) + */ + public java.util.List<HDR> subList(int index1, int index2) { + return this.hlist.subList(index1, index2); + + } + + /** + * @see Object#hashCode() + * @return -- the computed hashcode. + */ + public int hashCode() { + + return this.headerName.hashCode(); + } + + /** + * Set a SIPHeader at a particular position in the list. + * + * @see List#set(int, java.lang.Object) + */ + public HDR set(int position, HDR sipHeader) { + + return hlist.set(position, sipHeader); + + } + + + public static void setPrettyEncode(boolean flag) { + prettyEncode = flag; + } + + + public <T> T[] toArray(T[] array) { + return this.hlist.toArray(array); + } + + +} diff --git a/java/gov/nist/javax/sip/header/SIPHeaderNames.java b/java/gov/nist/javax/sip/header/SIPHeaderNames.java new file mode 100644 index 0000000..1f82ff7 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPHeaderNames.java @@ -0,0 +1,121 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; + +/** + * SIPHeader names that are supported by this parser + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:37 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public interface SIPHeaderNames { + + public static final String MIN_EXPIRES = MinExpiresHeader.NAME; //1 + public static final String ERROR_INFO = ErrorInfoHeader.NAME; //2 + public static final String MIME_VERSION = MimeVersionHeader.NAME; //3 + public static final String IN_REPLY_TO = InReplyToHeader.NAME; //4 + public static final String ALLOW = AllowHeader.NAME; //5 + public static final String CONTENT_LANGUAGE = ContentLanguageHeader.NAME; + //6 + public static final String CALL_INFO = CallInfoHeader.NAME; //7 + public static final String CSEQ = CSeqHeader.NAME; //8 + public static final String ALERT_INFO = AlertInfoHeader.NAME; //9 + public static final String ACCEPT_ENCODING = AcceptEncodingHeader.NAME; + //10 + public static final String ACCEPT = AcceptHeader.NAME; //11 + public static final String ACCEPT_LANGUAGE = AcceptLanguageHeader.NAME; + //12 + public static final String RECORD_ROUTE = RecordRouteHeader.NAME; //13 + public static final String TIMESTAMP = TimeStampHeader.NAME; //14 + public static final String TO = ToHeader.NAME; //15 + public static final String VIA = ViaHeader.NAME; //16 + public static final String FROM = FromHeader.NAME; //17 + public static final String CALL_ID = CallIdHeader.NAME; //18 + public static final String AUTHORIZATION = AuthorizationHeader.NAME; //19 + public static final String PROXY_AUTHENTICATE = + ProxyAuthenticateHeader.NAME; + //20 + public static final String SERVER = ServerHeader.NAME; //21 + public static final String UNSUPPORTED = UnsupportedHeader.NAME; //22 + public static final String RETRY_AFTER = RetryAfterHeader.NAME; //23 + public static final String CONTENT_TYPE = ContentTypeHeader.NAME; //24 + public static final String CONTENT_ENCODING = ContentEncodingHeader.NAME; + //25 + public static final String CONTENT_LENGTH = ContentLengthHeader.NAME; //26 + public static final String ROUTE = RouteHeader.NAME; //27 + public static final String CONTACT = ContactHeader.NAME; //28 + public static final String WWW_AUTHENTICATE = WWWAuthenticateHeader.NAME; + //29 + public static final String MAX_FORWARDS = MaxForwardsHeader.NAME; //30 + public static final String ORGANIZATION = OrganizationHeader.NAME; //31 + public static final String PROXY_AUTHORIZATION = + ProxyAuthorizationHeader.NAME; + //32 + public static final String PROXY_REQUIRE = ProxyRequireHeader.NAME; //33 + public static final String REQUIRE = RequireHeader.NAME; //34 + public static final String CONTENT_DISPOSITION = + ContentDispositionHeader.NAME; + //35 + public static final String SUBJECT = SubjectHeader.NAME; //36 + public static final String USER_AGENT = UserAgentHeader.NAME; //37 + public static final String WARNING = WarningHeader.NAME; //38 + public static final String PRIORITY = PriorityHeader.NAME; //39 + public static final String DATE = DateHeader.NAME; //40 + public static final String EXPIRES = ExpiresHeader.NAME; //41 + public static final String SUPPORTED = SupportedHeader.NAME; //42 + public static final String AUTHENTICATION_INFO = + AuthenticationInfoHeader.NAME; + //43 + public static final String REPLY_TO = ReplyToHeader.NAME; //44 + public static final String RACK = RAckHeader.NAME; //45 + public static final String RSEQ = RSeqHeader.NAME; //46 + public static final String REASON = ReasonHeader.NAME; //47 + public static final String SUBSCRIPTION_STATE = + SubscriptionStateHeader.NAME; + //48 + public static final String EVENT = EventHeader.NAME; //44 + public static final String ALLOW_EVENTS = AllowEventsHeader.NAME; //45 + + public static final String SIP_ETAG = SIPETagHeader.NAME; //46 + public static final String SIP_IF_MATCH = SIPIfMatchHeader.NAME; //47 + + // NewHeights pmusgrave + public static final String REFERRED_BY = ReferredByHeader.NAME; //48 + public static final String SESSION_EXPIRES = SessionExpiresHeader.NAME; //49 + public static final String MIN_SE = MinSEHeader.NAME; //50 + public static final String REPLACES = ReplacesHeader.NAME; //51 + public static final String JOIN = JoinHeader.NAME; //52 + +} + diff --git a/java/gov/nist/javax/sip/header/SIPHeaderNamesCache.java b/java/gov/nist/javax/sip/header/SIPHeaderNamesCache.java new file mode 100644 index 0000000..19d33b3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPHeaderNamesCache.java @@ -0,0 +1,39 @@ +package gov.nist.javax.sip.header; + +import java.util.HashMap; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * @author yanick.belanger + */ +public abstract class SIPHeaderNamesCache +{ + private static final HashMap lowercaseMap = new HashMap(); + + static { + Field[] fields = SIPHeaderNames.class.getFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.getType().equals(String.class) && Modifier.isStatic(field.getModifiers())) { + try { + String value = (String) field.get(null); + String lowerCase = value.toLowerCase(); + lowercaseMap.put(value, lowerCase); + lowercaseMap.put(lowerCase, lowerCase); + } catch (IllegalAccessException e) { + } + } + } + } + + public static String toLowerCase(String headerName) { + String lowerCase = (String) lowercaseMap.get(headerName); + if (lowerCase == null) { + return headerName.toLowerCase(); + } + else { + return lowerCase; + } + } +} diff --git a/java/gov/nist/javax/sip/header/SIPIfMatch.java b/java/gov/nist/javax/sip/header/SIPIfMatch.java new file mode 100644 index 0000000..e812263 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPIfMatch.java @@ -0,0 +1,99 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; +import java.text.ParseException; + +/** + * the SIP-If-Match header. + * + * @author Jeroen van Bemmel<br/> + * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:57:38 $ + * @since 1.2 + */ +public class SIPIfMatch extends SIPHeader implements SIPIfMatchHeader,ExtensionHeader { + + /** + * unique serial id + */ + private static final long serialVersionUID = 3833745477828359730L; + + /** + * entity tag field + */ + protected String entityTag; + + /** Default constructor + */ + public SIPIfMatch() { + super(NAME); + } + + public SIPIfMatch(String etag) throws ParseException { + this(); + this.setETag( etag ); + } + + /** + * Encode into canonical form. + * @return String + */ + public String encodeBody() { + return entityTag; + } + + /** + * get the priority value. + * @return String + */ + public String getETag() { + return entityTag; + } + + /** + * Set the priority member + * @param etag -- the entity tag to set. + */ + public void setETag(String etag) throws ParseException { + if (etag == null) + throw new NullPointerException( + "JAIN-SIP Exception," + + "SIP-If-Match, setETag(), the etag parameter is null"); + this.entityTag = etag; + } + + /** + * For v 1.1 backwards compatibility. + * @see javax.sip.header.ExtensionHeader#setValue(java.lang.String) + */ + public void setValue(String value) throws ParseException { + this.setETag(value); + + + } +} diff --git a/java/gov/nist/javax/sip/header/SIPObject.java b/java/gov/nist/javax/sip/header/SIPObject.java new file mode 100644 index 0000000..98bc50a --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPObject.java @@ -0,0 +1,402 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *****************************************************************************/ +package gov.nist.javax.sip.header; +import gov.nist.core.GenericObject; +import gov.nist.core.GenericObjectList; +import gov.nist.core.InternalErrorHandler; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * Root class for all singleton objects in this package: + * specializes the gov.nist.sip.header.GenericObject class for SIPHeader + * related objects. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:38 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ + +public abstract class SIPObject extends GenericObject { + + /** default Constructor + */ + protected SIPObject() { + super(); + } + + + + /** Debug function + */ + public void dbgPrint() { + super.dbgPrint(); + } + + /** Encode the header into a String. + * @return String + */ + public abstract String encode(); + + /** Encode the header into the given StringBuffer. + * Default implemation calls encode(). + */ + public StringBuffer encode(StringBuffer buffer) { + return buffer.append(encode()); + } + + /** + * An introspection based equality predicate for SIPObjects. + *@param other the other object to test against. + */ + public boolean equals(Object other) { + if (!this.getClass().equals(other.getClass())) + return false; + SIPObject that = (SIPObject) other; + Class myclass = this.getClass(); + Class hisclass = other.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + if (!hisclass.equals(myclass)) + return false; + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } + } else if (g.get(that) == f.get(this)) + continue; + else if (f.get(this) == null && g.get(that) != null) + return false; + else if (g.get(that) == null && f.get(this) != null) + return false; + else if (!f.get(this).equals(g.get(that))) + return false; + } catch (IllegalAccessException ex1) { + System.out.println("accessed field " + fieldName); + System.out.println("modifier " + modifier); + System.out.println("modifier.private " + Modifier.PRIVATE); + InternalErrorHandler.handleException(ex1); + } + } + if (myclass.equals(SIPObject.class)) + break; + else { + myclass = myclass.getSuperclass(); + hisclass = hisclass.getSuperclass(); + } + } + return true; + } + + /** An introspection based predicate matching using a template + * object. Allows for partial match of two protocl Objects. + * You can set a generalized matcher (using regular expressions + * for example) by implementing the Match interface and registering + * it with the template. + *@param other the match pattern to test against. The match object + * has to be of the same type (class). Primitive types + * and non-sip fields that are non null are matched for equality. + * Null in any field matches anything. Some book-keeping fields + * are ignored when making the comparison. + * + */ + public boolean match(Object other) { + if (other == null) { + return true; + } + + if (!this.getClass().equals(other.getClass())) + return false; + GenericObject that = (GenericObject) other; + Class myclass = this.getClass(); + Class hisclass = other.getClass(); + while (true) { + Field[] fields = myclass.getDeclaredFields(); + Field[] hisfields = hisclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Field g = hisfields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + continue; + } + if (fieldName.compareTo("indentation") == 0) { + continue; + } + try { + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + if (fname.compareTo("int") == 0) { + if (f.getInt(this) != g.getInt(that)) + return false; + } else if (fname.compareTo("short") == 0) { + if (f.getShort(this) != g.getShort(that)) + return false; + } else if (fname.compareTo("char") == 0) { + if (f.getChar(this) != g.getChar(that)) + return false; + } else if (fname.compareTo("long") == 0) { + if (f.getLong(this) != g.getLong(that)) + return false; + } else if (fname.compareTo("boolean") == 0) { + if (f.getBoolean(this) != g.getBoolean(that)) + return false; + } else if (fname.compareTo("double") == 0) { + if (f.getDouble(this) != g.getDouble(that)) + return false; + } else if (fname.compareTo("float") == 0) { + if (f.getFloat(this) != g.getFloat(that)) + return false; + } else { + InternalErrorHandler.handleException( + "unknown type"); + } + } else { + Object myObj = f.get(this); + Object hisObj = g.get(that); + if (hisObj != null && myObj == null) + return false; + else if (hisObj == null && myObj != null) + continue; + else if (hisObj == null && myObj == null) + continue; + else if ( + hisObj instanceof java.lang.String + && myObj instanceof java.lang.String) { + if ((((String) hisObj).trim()).equals("")) + continue; + if (((String) myObj) + .compareToIgnoreCase((String) hisObj) + != 0) + return false; + } else if ( + hisObj != null + && GenericObject.isMySubclass(myObj.getClass()) + && GenericObject.isMySubclass(hisObj.getClass()) + && myObj.getClass().equals(hisObj.getClass()) + && ((GenericObject) hisObj).getMatcher() + != null) { + String myObjEncoded = + ((GenericObject) myObj).encode(); + boolean retval = + ((GenericObject) hisObj).getMatcher().match( + myObjEncoded); + if (!retval) + return false; + } else if ( + GenericObject.isMySubclass(myObj.getClass()) + && !((GenericObject) myObj).match(hisObj)) + return false; + else if ( + GenericObjectList.isMySubclass(myObj.getClass()) + && !((GenericObjectList) myObj).match(hisObj)) + return false; + + } + } catch (IllegalAccessException ex1) { + InternalErrorHandler.handleException(ex1); + } + } + if (myclass.equals(SIPObject.class)) + break; + else { + myclass = myclass.getSuperclass(); + hisclass = hisclass.getSuperclass(); + } + } + return true; + } + + /** + * An introspection based string formatting method. We need this because + * in this package (although it is an exact duplicate of the one in + * the superclass) because it needs to access the protected members + * of the other objects in this class. + * @return String + */ + public String debugDump() { + stringRepresentation = ""; + Class myclass = getClass(); + sprint(myclass.getName()); + sprint("{"); + Field[] fields = myclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) + continue; + Class fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + // avoid nasty recursions... + continue; + } + if (fieldName.compareTo("indentation") == 0) { + // formatting stuff - not relevant here. + continue; + } + sprint(fieldName + ":"); + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + sprint(fname + ":"); + if (fname.compareTo("int") == 0) { + int intfield = f.getInt(this); + sprint(intfield); + } else if (fname.compareTo("short") == 0) { + short shortField = f.getShort(this); + sprint(shortField); + } else if (fname.compareTo("char") == 0) { + char charField = f.getChar(this); + sprint(charField); + } else if (fname.compareTo("long") == 0) { + long longField = f.getLong(this); + sprint(longField); + } else if (fname.compareTo("boolean") == 0) { + boolean booleanField = f.getBoolean(this); + sprint(booleanField); + } else if (fname.compareTo("double") == 0) { + double doubleField = f.getDouble(this); + sprint(doubleField); + } else if (fname.compareTo("float") == 0) { + float floatField = f.getFloat(this); + sprint(floatField); + } + } else if (GenericObject.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObject) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else if ( + GenericObjectList.class.isAssignableFrom(fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObjectList) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else { + // Dont do recursion on things that are not + // of our header type... + if (f.get(this) != null) { + sprint(f.get(this).getClass().getName() + ":"); + } else { + sprint(fieldType.getName() + ":"); + } + + sprint("{"); + if (f.get(this) != null) { + sprint(f.get(this).toString()); + } else { + sprint("<null>"); + } + sprint("}"); + } + } catch (IllegalAccessException ex1) { + continue; // we are accessing a private field... + } + } + sprint("}"); + return stringRepresentation; + } + + /** + * Formatter with a given starting indentation (for nested structs). + * @param indent int to set + * @return String + */ + public String debugDump(int indent) { + int save = indentation; + indentation = indent; + String retval = this.debugDump(); + indentation = save; + return retval; + } + + + public String toString() { + return this.encode(); + } + +} diff --git a/java/gov/nist/javax/sip/header/SIPObjectList.java b/java/gov/nist/javax/sip/header/SIPObjectList.java new file mode 100644 index 0000000..c3205c3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SIPObjectList.java @@ -0,0 +1,152 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; +import java.util.ListIterator; +import java.util.LinkedList; +import java.util.Iterator; +import java.lang.reflect.*; +import gov.nist.core.*; + +/** + * Root class for all the collection objects in this list: + * a wrapper class on the GenericObjectList class for lists of objects + * that can appear in SIPObjects. + * IMPORTANT NOTE: SIPObjectList cannot derive from SIPObject. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:38 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class SIPObjectList extends GenericObjectList { + + + private static final long serialVersionUID = -3015154738977508905L; + + /** + * Construct a SIPObject List given a list name. + * @param lname String to set + */ + public SIPObjectList(String lname) { + super(lname); + } + + + + + /** + * Construct an empty SIPObjectList. + */ + public SIPObjectList() { + super(); + } + + + + + /** + * Do a merge of the GenericObjects contained in this list with the + * GenericObjects in the mergeList. Note that this does an inplace + * modification of the given list. This does an object by object + * merge of the given objects. + * + *@param mergeList is the list of Generic objects that we want to do + * an object by object merge with. Note that no new objects are + * added to this list. + * + */ + + public void mergeObjects(GenericObjectList mergeList) { + Iterator<GenericObject> it1 = this.listIterator(); + Iterator<GenericObject> it2 = mergeList.listIterator(); + while (it1.hasNext()) { + GenericObject outerObj = (GenericObject) it1.next(); + while (it2.hasNext()) { + Object innerObj = it2.next(); + outerObj.merge(innerObj); + } + } + } + + /** + * Append a given list to the end of this list. + * @param otherList SIPObjectList to set + */ + public void concatenate(SIPObjectList otherList) { + super.concatenate(otherList); + } + + /** + * Append or prepend a given list to this list. + * @param otherList SIPObjectList to set + * @param topFlag boolean to set + */ + public void concatenate(SIPObjectList otherList, boolean topFlag) { + super.concatenate(otherList, topFlag); + } + + /** + * Get the first object of this list. + * @return GenericObject + */ + public GenericObject first() { + return (SIPObject) super.first(); + } + + + /** + * Get the next object of this list (assumes that first() has been + * called prior to calling this method.) + * @return GenericObject + */ + public GenericObject next() { + return (SIPObject) super.next(); + } + + + + + + /** + * Convert to a string given an indentation(for pretty printing). + * This is useful for debugging the system in lieu of a debugger. + * + * @param indent int to set + * @return an indentation + */ + public String debugDump(int indent) { + return super.debugDump(indent); + } + + + + + +} diff --git a/java/gov/nist/javax/sip/header/Server.java b/java/gov/nist/javax/sip/header/Server.java new file mode 100644 index 0000000..e75d416 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Server.java @@ -0,0 +1,188 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ + +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; +import java.util.*; + +/** + * Supported SIP Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:38 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class Server extends SIPHeader implements ServerHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3587764149383342973L; + /** Product tokens. + */ + protected List productTokens; + + /** + * Return canonical form. + * @return String + */ + private String encodeProduct() { + StringBuffer tokens = new StringBuffer(); + ListIterator it = productTokens.listIterator(); + + while (it.hasNext()) { + tokens.append((String) it.next()); + if (it.hasNext()) + tokens.append('/'); + else + break; + } + return tokens.toString(); + } + + /** set the productToken field + * @param pt String to set + */ + public void addProductToken(String pt) { + productTokens.add(pt); + } + + /** + * Constructor. + */ + public Server() { + super(NAME); + productTokens = new LinkedList(); + } + + /** Encode only the body of this header. + *@return encoded value of the header. + */ + public String encodeBody() { + return encodeProduct(); + } + + /** + * Returns the list value of the product parameter. + * + * @return the software of this UserAgentHeader + */ + public ListIterator getProduct() { + if (productTokens == null || productTokens.isEmpty()) + return null; + else + return productTokens.listIterator(); + } + + /** + * Sets the product value of the UserAgentHeader. + * + * @param product - a List specifying the product value + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the product value. + */ + public void setProduct(List product) throws ParseException { + if (product == null) + throw new NullPointerException( + "JAIN-SIP Exception, UserAgent, " + + "setProduct(), the " + + " product parameter is null"); + productTokens = product; + } +} +/* + * $Log: Server.java,v $ + * Revision 1.5 2009/07/17 18:57:38 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:04 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/SipRequestLine.java b/java/gov/nist/javax/sip/header/SipRequestLine.java new file mode 100644 index 0000000..1763fe8 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SipRequestLine.java @@ -0,0 +1,69 @@ +package gov.nist.javax.sip.header; + +import javax.sip.address.URI; + + +/** + * The SIP Request Line. + * + * @since 2.0 + */ +public interface SipRequestLine { + + /** get the Request-URI. + * + * @return the request URI + */ + public abstract URI getUri(); + + /** + * Get the Method + * + * @return method string. + */ + public abstract String getMethod(); + + /** + * Get the SIP version. + * + * @return String + */ + public abstract String getSipVersion(); + + /** + * Set the URI. + * + * @param uri URI to set. + */ + public abstract void setUri(URI uri); + + /** + * Set the method member + * + * @param method String to set + */ + public abstract void setMethod(String method); + + /** + * Set the sipVersion member + * + * @param s String to set + */ + public abstract void setSipVersion(String version); + + /** + * Get the major verrsion number. + * + *@return String major version number + */ + public abstract String getVersionMajor(); + + /** + * Get the minor version number. + * + *@return String minor version number + * + */ + public abstract String getVersionMinor(); + +} diff --git a/java/gov/nist/javax/sip/header/SipStatusLine.java b/java/gov/nist/javax/sip/header/SipStatusLine.java new file mode 100644 index 0000000..eb4e3b5 --- /dev/null +++ b/java/gov/nist/javax/sip/header/SipStatusLine.java @@ -0,0 +1,55 @@ +package gov.nist.javax.sip.header; + +/** + * The SIP Status line. + * + * @since 2.0 + */ +public interface SipStatusLine { + + /** get the Sip Version + * @return SipVersion + */ + public abstract String getSipVersion(); + + /** get the Status Code + * @return StatusCode + */ + public abstract int getStatusCode(); + + /** get the ReasonPhrase field + * @return ReasonPhrase field + */ + public abstract String getReasonPhrase(); + + /** + * Set the sipVersion member + * @param sipVersion String to set + */ + public abstract void setSipVersion(String sipVersion); + + /** + * Set the statusCode member + * @param statusCode int to set + */ + public abstract void setStatusCode(int statusCode); + + /** + * Set the reasonPhrase member + * @param reasonPhrase String to set + */ + public abstract void setReasonPhrase(String reasonPhrase); + + /** + * Get the major version number. + *@return String major version number + */ + public abstract String getVersionMajor(); + + /** + * Get the minor version number. + *@return String minor version number + */ + public abstract String getVersionMinor(); + +} diff --git a/java/gov/nist/javax/sip/header/StatusLine.java b/java/gov/nist/javax/sip/header/StatusLine.java new file mode 100644 index 0000000..1cf4b16 --- /dev/null +++ b/java/gov/nist/javax/sip/header/StatusLine.java @@ -0,0 +1,286 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.SIPConstants; + +/** + * Status Line (for SIPReply) messages. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:34 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public final class StatusLine extends SIPObject implements SipStatusLine { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4738092215519950414L; + + protected boolean matchStatusClass; + + /** sipVersion field + */ + protected String sipVersion; + + /** status code field + */ + protected int statusCode; + + /** reasonPhrase field + */ + protected String reasonPhrase; + + /** Match with a template. + * Match only the response class if the last two digits of the + * match templates are 0's + */ + + public boolean match(Object matchObj) { + if (!(matchObj instanceof StatusLine)) + return false; + StatusLine sl = (StatusLine) matchObj; + // A pattern matcher has been registered. + if (sl.matchExpression != null) + return sl.matchExpression.match(this.encode()); + // no patter matcher has been registered.. + if (sl.sipVersion != null && !sl.sipVersion.equals(sipVersion)) + return false; + if (sl.statusCode != 0) { + if (matchStatusClass) { + int hiscode = sl.statusCode; + String codeString = Integer.toString(sl.statusCode); + String mycode = Integer.toString(statusCode); + if (codeString.charAt(0) != mycode.charAt(0)) + return false; + } else { + if (statusCode != sl.statusCode) + return false; + } + } + if (sl.reasonPhrase == null || reasonPhrase == sl.reasonPhrase) + return true; + return reasonPhrase.equals(sl.reasonPhrase); + + } + + /** set the flag on a match template. + *If this set to true, then the whole status code is matched (default + * behavior) else only the class of the response is matched. + */ + public void setMatchStatusClass(boolean flag) { + matchStatusClass = flag; + } + + /** Default Constructor + */ + public StatusLine() { + reasonPhrase = null; + sipVersion = SIPConstants.SIP_VERSION_STRING; + } + + /** + * Encode into a canonical form. + * @return String + */ + public String encode() { + String encoding = SIPConstants.SIP_VERSION_STRING + SP + statusCode; + if (reasonPhrase != null) + encoding += SP + reasonPhrase; + encoding += NEWLINE; + return encoding; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#getSipVersion() + */ + public String getSipVersion() { + return sipVersion; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#getStatusCode() + */ + public int getStatusCode() { + return statusCode; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#getReasonPhrase() + */ + public String getReasonPhrase() { + return reasonPhrase; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#setSipVersion(java.lang.String) + */ + public void setSipVersion(String s) { + sipVersion = s; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#setStatusCode(int) + */ + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#setReasonPhrase(java.lang.String) + */ + public void setReasonPhrase(String reasonPhrase) { + this.reasonPhrase = reasonPhrase; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#getVersionMajor() + */ + public String getVersionMajor() { + if (sipVersion == null) + return null; + String major = null; + boolean slash = false; + for (int i = 0; i < sipVersion.length(); i++) { + if (sipVersion.charAt(i) == '.') + slash = false; + if (slash) { + if (major == null) + major = "" + sipVersion.charAt(i); + else + major += sipVersion.charAt(i); + } + if (sipVersion.charAt(i) == '/') + slash = true; + } + return major; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.SipStatusLine#getVersionMinor() + */ + public String getVersionMinor() { + if (sipVersion == null) + return null; + String minor = null; + boolean dot = false; + for (int i = 0; i < sipVersion.length(); i++) { + if (dot) { + if (minor == null) + minor = "" + sipVersion.charAt(i); + else + minor += sipVersion.charAt(i); + } + if (sipVersion.charAt(i) == '.') + dot = true; + } + return minor; + } +} +/* + * $Log: StatusLine.java,v $ + * Revision 1.7 2009/10/18 13:46:34 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.6 2009/09/15 02:55:26 mranga + * Issue number: 222 + * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String) + * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies + * during call transfer). + * + * Revision 1.5 2009/07/17 18:57:38 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:48 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/Subject.java b/java/gov/nist/javax/sip/header/Subject.java new file mode 100644 index 0000000..51f9da1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Subject.java @@ -0,0 +1,165 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + +*******************************************************************************/ + +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; + +/** + * Supported SIP Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:39 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class Subject extends SIPHeader implements SubjectHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6479220126758862528L; + /** subject field + */ + protected String subject; + + /** Default Constructor. + */ + public Subject() { + super(SUBJECT); + } + + /** + * Generate the canonical form. + * @return String. + */ + public String encodeBody() { + if (subject != null) { + return subject; + } else { + return ""; + } + } + + /** + * Sets the subject value of the SubjectHeader to the supplied string + * subject value. + * + * @param subject - the new subject value of this header + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the subject value. + */ + public void setSubject(String subject) throws ParseException { + if (subject == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " Subject, setSubject(), the subject parameter is null"); + this.subject = subject; + } + + /** + * Gets the subject value of SubjectHeader + * + * @return subject of SubjectHeader + */ + public String getSubject() { + return subject; + } + +} +/* + * $Log: Subject.java,v $ + * Revision 1.5 2009/07/17 18:57:39 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:21 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/SubscriptionState.java b/java/gov/nist/javax/sip/header/SubscriptionState.java new file mode 100644 index 0000000..638156b --- /dev/null +++ b/java/gov/nist/javax/sip/header/SubscriptionState.java @@ -0,0 +1,187 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.SubscriptionStateHeader; +import java.text.ParseException; + +/** + *SubscriptionState header + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:39 $ + * + * @author Olivier Deruelle <br/> + * + * + */ +public class SubscriptionState + extends ParametersHeader + implements SubscriptionStateHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6673833053927258745L; + protected int expires; + protected int retryAfter; + protected String reasonCode; + protected String state; + + /** Creates a new instance of SubscriptionState */ + public SubscriptionState() { + super(SIPHeaderNames.SUBSCRIPTION_STATE); + expires = -1; + retryAfter = -1; + } + + /** + * Sets the relative expires value of the SubscriptionStateHeader. The + * expires value MUST be greater than zero and MUST be less than 2**31. + * + * @param expires - the new expires value of this SubscriptionStateHeader. + * @throws InvalidArgumentException if supplied value is less than zero. + */ + public void setExpires(int expires) throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SubscriptionState, setExpires(), the expires parameter is < 0"); + this.expires = expires; + } + + /** + * Gets the expires value of the SubscriptionStateHeader. This expires value is + * relative time. + * + * @return the expires value of the SubscriptionStateHeader. + */ + public int getExpires() { + return expires; + } + + /** + * Sets the retry after value of the SubscriptionStateHeader. The retry after value + * MUST be greater than zero and MUST be less than 2**31. + * + * @param retryAfter - the new retry after value of this SubscriptionStateHeader + * @throws InvalidArgumentException if supplied value is less than zero. + */ + public void setRetryAfter(int retryAfter) throws InvalidArgumentException { + if (retryAfter <= 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SubscriptionState, setRetryAfter(), the retryAfter parameter is <=0"); + this.retryAfter = retryAfter; + } + + /** + * Gets the retry after value of the SubscriptionStateHeader. This retry after + * value is relative time. + * + * @return the retry after value of the SubscriptionStateHeader. + */ + public int getRetryAfter() { + return retryAfter; + } + + /** + * Gets the reason code of SubscriptionStateHeader. + * + * @return the comment of this SubscriptionStateHeader, return null if no reason code + * is available. + */ + public String getReasonCode() { + return reasonCode; + } + + /** + * Sets the reason code value of the SubscriptionStateHeader. + * + * @param reasonCode - the new reason code string value of the SubscriptionStateHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the reason code. + */ + public void setReasonCode(String reasonCode) throws ParseException { + if (reasonCode == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SubscriptionState, setReasonCode(), the reasonCode parameter is null"); + this.reasonCode = reasonCode; + } + + /** + * Gets the state of SubscriptionStateHeader. + * + * @return the state of this SubscriptionStateHeader. + */ + public String getState() { + return state; + } + + /** + * Sets the state value of the SubscriptionStateHeader. + * + * @param state - the new state string value of the SubscriptionStateHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the state. + */ + public void setState(String state) throws ParseException { + if (state == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SubscriptionState, setState(), the state parameter is null"); + this.state = state; + } + + /** Just the encoded body of the header. + * @return the string encoded header body. + */ + public String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (state != null) + buffer.append(state); + if (reasonCode != null) + buffer.append(";reason=").append(reasonCode); + if (expires != -1) + buffer.append(";expires=").append(expires); + if (retryAfter != -1) + buffer.append(";retry-after=").append(retryAfter); + + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + return buffer; + } +} + diff --git a/java/gov/nist/javax/sip/header/Supported.java b/java/gov/nist/javax/sip/header/Supported.java new file mode 100644 index 0000000..5795931 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Supported.java @@ -0,0 +1,180 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; +import javax.sip.header.*; + +/** + * Supported SIP Header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:39 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class Supported extends SIPHeader implements SupportedHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -7679667592702854542L; + /* the Option field + */ + protected String optionTag; + + /** + * default constructor + */ + public Supported() { + super(SIPHeaderNames.SUPPORTED); + optionTag = null; + } + + /** + * Constructor + * @param option_tag String to set + */ + public Supported(String option_tag) { + super(SIPHeaderNames.SUPPORTED); + optionTag = option_tag; + } + + /** + * Return canonical form of the header. + * @return encoded header. + */ + public String encode() { + String retval = headerName + COLON; + if (optionTag != null) + retval += SP + optionTag; + retval += NEWLINE; + return retval; + } + + /** + * Just the encoded body of the header. + * @return the string encoded header body. + */ + public String encodeBody() { + return optionTag != null ? optionTag : ""; + } + + /** + * Sets the option tag value to the new supplied <var>optionTag</var> + * parameter. + * + * @param optionTag - the new string value of the option tag. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the optionTag value. + */ + public void setOptionTag(String optionTag) throws ParseException { + if (optionTag == null) + throw new NullPointerException( + "JAIN-SIP Exception, Supported, " + + "setOptionTag(), the optionTag parameter is null"); + this.optionTag = optionTag; + } + + /** + * Gets the option tag of this OptionTag class. + * + * @return the string that identifies the option tag value. + */ + public String getOptionTag() { + return optionTag; + } +} +/* + * $Log: Supported.java,v $ + * Revision 1.5 2009/07/17 18:57:39 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:27 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:30 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/SupportedList.java b/java/gov/nist/javax/sip/header/SupportedList.java new file mode 100644 index 0000000..29e7afd --- /dev/null +++ b/java/gov/nist/javax/sip/header/SupportedList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * A list of supported headers. + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:39 $ + * @see Supported + */ +public class SupportedList extends SIPHeaderList<Supported>{ + + /** + * + */ + private static final long serialVersionUID = -4539299544895602367L; + + public Object clone() { + SupportedList retval = new SupportedList(); + retval.clonehlist(this.hlist); + return retval; + } + + /** Default Constructor + */ + public SupportedList() { + super(Supported.class, SupportedHeader.NAME); + } +} + diff --git a/java/gov/nist/javax/sip/header/TimeStamp.java b/java/gov/nist/javax/sip/header/TimeStamp.java new file mode 100644 index 0000000..b4ead80 --- /dev/null +++ b/java/gov/nist/javax/sip/header/TimeStamp.java @@ -0,0 +1,196 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ + +package gov.nist.javax.sip.header; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.*; + +/** + * TimeStamp SIP Header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:31 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ +public class TimeStamp extends SIPHeader implements TimeStampHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3711322366481232720L; + + /** + * timeStamp field + */ + protected long timeStamp = -1; + + /** + * delay field + */ + protected int delay = -1; + + protected float delayFloat = -1; + + private float timeStampFloat = -1; + + /** + * Default Constructor + */ + public TimeStamp() { + super(TIMESTAMP); + delay = -1; + } + + private String getTimeStampAsString() { + if (timeStamp == -1 && timeStampFloat == -1) + return ""; + else if (timeStamp != -1) + return Long.toString(timeStamp); + else + return Float.toString(timeStampFloat); + } + + private String getDelayAsString() { + if (delay == -1 && delayFloat == -1) + return ""; + else if (delay != -1) + return Integer.toString(delay); + else + return Float.toString(delayFloat); + } + + /** + * Return canonical form of the header. + * + * @return String + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + String s1 = getTimeStampAsString(); + String s2 = getDelayAsString(); + if (s1.equals("") && s2.equals("")) + return ""; + if (!s1.equals("")) + retval.append(s1); + if (!s2.equals("")) + retval.append(" ").append(s2); + return retval.toString(); + + } + + /** + * return true if delay exists + * + * @return boolean + */ + public boolean hasDelay() { + return delay != -1; + } + + /* + * remove the Delay field + */ + public void removeDelay() { + delay = -1; + } + + + + public void setTimeStamp(float timeStamp) throws InvalidArgumentException { + if (timeStamp < 0) + throw new InvalidArgumentException( + "JAIN-SIP Exception, TimeStamp, " + + "setTimeStamp(), the timeStamp parameter is <0"); + this.timeStamp = -1; + this.timeStampFloat = timeStamp; + } + + + public float getTimeStamp() { + return this.timeStampFloat == -1 ? Float.valueOf(timeStamp).floatValue() + : this.timeStampFloat; + } + + + + public float getDelay() { + return delayFloat == -1 ? Float.valueOf(delay).floatValue() : delayFloat; + } + + /** + * Sets the new delay value of the TimestampHeader to the delay paramter + * passed to this method + * + * @param delay - + * the Float.valueOf delay value + * @throws InvalidArgumentException + * if the delay value argumenmt is a negative value other than + * <code>-1</code>. + */ + + public void setDelay(float delay) throws InvalidArgumentException { + if (delay < 0 && delay != -1) + throw new InvalidArgumentException( + "JAIN-SIP Exception, TimeStamp, " + + "setDelay(), the delay parameter is <0"); + this.delayFloat = delay; + this.delay = -1; + } + + public long getTime() { + return this.timeStamp == -1 ? (long) timeStampFloat : timeStamp; + } + + public int getTimeDelay() { + return this.delay == -1 ? (int) delayFloat : delay; + + } + + public void setTime(long timeStamp) throws InvalidArgumentException { + if (timeStamp < -1) + throw new InvalidArgumentException("Illegal timestamp"); + this.timeStamp = timeStamp; + this.timeStampFloat = -1; + + } + + public void setTimeDelay(int delay) throws InvalidArgumentException { + if (delay < -1) + throw new InvalidArgumentException("Value out of range " + delay); + this.delay = delay; + this.delayFloat = -1; + + } + +} diff --git a/java/gov/nist/javax/sip/header/To.java b/java/gov/nist/javax/sip/header/To.java new file mode 100644 index 0000000..fbdcda6 --- /dev/null +++ b/java/gov/nist/javax/sip/header/To.java @@ -0,0 +1,191 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.HostPort; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.parser.Parser; + +import javax.sip.header.ToHeader; +import java.text.ParseException; + +/** + * To SIP Header. + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:39 $ + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + * + * + */ + +public final class To extends AddressParametersHeader implements + javax.sip.header.ToHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -4057413800584586316L; + + /** + * default Constructor. + */ + public To() { + super(TO,true); + } + + /** + * Generate a TO header from a FROM header + */ + public To(From from) { + super(TO); + setAddress(from.address); + setParameters(from.parameters); + } + + /** + * Encode the header into a String. + * + * @since 1.0 + * @return String + */ + public String encode() { + return headerName + COLON + SP + encodeBody() + NEWLINE; + } + + /** + * Encode the header content into a String. + * + * @return String + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + if (address != null) { + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(LESS_THAN); + } + address.encode(buffer); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + buffer.append(GREATER_THAN); + } + + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + } + return buffer; + } + + /** + * Conveniance accessor function to get the hostPort field from the address. + * Warning -- this assumes that the embedded URI is a SipURL. + * + * @return hostport field + */ + public HostPort getHostPort() { + if (address == null) + return null; + return address.getHostPort(); + } + + /** + * Get the display name from the address. + * + * @return Display name + */ + public String getDisplayName() { + if (address == null) + return null; + return address.getDisplayName(); + } + + /** + * Get the tag parameter from the address parm list. + * + * @return tag field + */ + public String getTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.TAG); + + } + + /** + * Boolean function + * + * @return true if the Tag exist + */ + public boolean hasTag() { + if (parameters == null) + return false; + return hasParameter(ParameterNames.TAG); + + } + + /** + * remove Tag member + */ + public void removeTag() { + if (parameters != null) + parameters.delete(ParameterNames.TAG); + + } + + /** + * Set the tag member. This should remain empty for the initial request in + * a dialog. + * + * @param t - tag String to set. + */ + public void setTag(String t) throws ParseException { + // JvB: check that it is a valid token + Parser.checkToken(t); + this.setParameter(ParameterNames.TAG, t); + } + + /** + * Get the user@host port string. + */ + public String getUserAtHostPort() { + if (address == null) + return null; + return address.getUserAtHostPort(); + } + + public boolean equals(Object other) { + return (other instanceof ToHeader) && super.equals(other); + } +} diff --git a/java/gov/nist/javax/sip/header/Unsupported.java b/java/gov/nist/javax/sip/header/Unsupported.java new file mode 100644 index 0000000..774b4d4 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Unsupported.java @@ -0,0 +1,158 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.text.ParseException; + +/** + * the Unsupported header. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:40 $ + * @author Olivier Deruelle <br/> + * + * + * + */ +public class Unsupported + extends SIPHeader + implements javax.sip.header.UnsupportedHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -2479414149440236199L; + /** option-Tag field. + */ + protected String optionTag; + + /** Default Constructor. + */ + public Unsupported() { + super(NAME); + } + + /** Constructor + * @param ot String to set + */ + public Unsupported(String ot) { + super(NAME); + optionTag = ot; + } + + /** + * Return a canonical value. + * @return String. + */ + public String encodeBody() { + return optionTag; + } + + /** get the option tag field + * @return option Tag field + */ + public String getOptionTag() { + return optionTag; + } + + /** + * Set the option member + * @param o String to set + */ + public void setOptionTag(String o) throws ParseException { + if (o == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + " Unsupported, setOptionTag(), The option tag parameter is null"); + optionTag = o; + } +} +/* + * $Log: Unsupported.java,v $ + * Revision 1.5 2009/07/17 18:57:40 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.4 2006/07/13 09:01:34 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.2 2004/01/22 13:26:30 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/UnsupportedList.java b/java/gov/nist/javax/sip/header/UnsupportedList.java new file mode 100644 index 0000000..5f9bf25 --- /dev/null +++ b/java/gov/nist/javax/sip/header/UnsupportedList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import java.util.Iterator; + +import javax.sip.header.*; + +/** + * List of Unsupported headers. + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:40 $ + * @author M. Ranganathan + */ +public class UnsupportedList extends SIPHeaderList<Unsupported> { + + + private static final long serialVersionUID = -4052610269407058661L; + + + /** Default Constructor + */ + public UnsupportedList() { + super(Unsupported.class, UnsupportedHeader.NAME); + } + + + public Object clone() { + UnsupportedList retval = new UnsupportedList(); + return retval.clonehlist(this.hlist); + } +} diff --git a/java/gov/nist/javax/sip/header/UserAgent.java b/java/gov/nist/javax/sip/header/UserAgent.java new file mode 100644 index 0000000..a401b7e --- /dev/null +++ b/java/gov/nist/javax/sip/header/UserAgent.java @@ -0,0 +1,206 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import java.util.*; +import java.text.ParseException; +import javax.sip.header.*; + +/** + * the UserAgent SIPObject. + * + * @author Olivier Deruelle <br/> + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:40 $ + * + * + * + */ +public class UserAgent extends SIPHeader implements UserAgentHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 4561239179796364295L; + /** Product tokens. + */ + protected List productTokens; + + /** + * Return canonical form. + * pmusgrave - put a space between products (preserves format of header) + * @return String + */ + private String encodeProduct() { + StringBuffer tokens = new StringBuffer(); + ListIterator it = productTokens.listIterator(); + + while (it.hasNext()) { + tokens.append((String) it.next()); + + } + return tokens.toString(); + } + + /** set the productToken field + * @param pt String to set + */ + public void addProductToken(String pt) { + productTokens.add(pt); + } + + /** + * Constructor. + */ + public UserAgent() { + super(NAME); + productTokens = new LinkedList(); + } + + /** Encode only the body of this header. + *@return encoded value of the header. + */ + public String encodeBody() { + return encodeProduct(); + } + + /** + * Returns the list value of the product parameter. + * + * @return the software of this UserAgentHeader + */ + public ListIterator getProduct() { + if (productTokens == null || productTokens.isEmpty()) + return null; + else + return productTokens.listIterator(); + } + + /** + * Sets the product value of the UserAgentHeader. + * + * @param product - a List specifying the product value + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the product value. + */ + public void setProduct(List product) throws ParseException { + if (product == null) + throw new NullPointerException( + "JAIN-SIP Exception, UserAgent, " + + "setProduct(), the " + + " product parameter is null"); + productTokens = product; + } + + public Object clone() { + UserAgent retval = (UserAgent) super.clone(); + if (productTokens != null) + retval.productTokens = new LinkedList (productTokens); + return retval; + } + +} +/* + * $Log: UserAgent.java,v $ + * Revision 1.8 2009/07/17 18:57:40 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2008/07/30 14:36:06 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Fix minor issue in encoding of user-agent header. + * + * Revision 1.6 2006/10/12 11:57:55 pmusgrave + * Issue number: 79, 80 + * Submitted by: pmusgrave@newheights.com + * Reviewed by: mranga + * + * Revision 1.5 2006/07/13 09:01:48 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.3 2005/04/16 20:38:51 dmuresan + * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies + * + * Revision 1.2 2004/01/22 13:26:30 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/Via.java b/java/gov/nist/javax/sip/header/Via.java new file mode 100644 index 0000000..be40962 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Via.java @@ -0,0 +1,563 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.core.Host; +import gov.nist.core.HostPort; +import gov.nist.core.NameValue; +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.stack.HopImpl; + +import javax.sip.InvalidArgumentException; +import javax.sip.address.Hop; +import javax.sip.header.ViaHeader; +import java.text.ParseException; + +/** + * Via SIPHeader (these are strung together in a ViaList). + * + * @see ViaList + * + * @version 1.2 $Revision: 1.17 $ $Date: 2009/10/18 13:46:33 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class Via + extends ParametersHeader + implements javax.sip.header.ViaHeader, ViaHeaderExt { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 5281728373401351378L; + + /** The branch parameter is included by every forking proxy. + */ + public static final String BRANCH = ParameterNames.BRANCH; + + /** The "received" parameter is added only for receiver-added Via Fields. + */ + public static final String RECEIVED = ParameterNames.RECEIVED; + + /** The "maddr" paramter is designating the multicast address. + */ + public static final String MADDR = ParameterNames.MADDR; + + /** The "TTL" parameter is designating the time-to-live value. + */ + public static final String TTL = ParameterNames.TTL; + + /** The RPORT parameter. + */ + public static final String RPORT = ParameterNames.RPORT; + + /** sentProtocol field. + */ + protected Protocol sentProtocol; + + /** sentBy field. + */ + protected HostPort sentBy; + + /** + * comment field + * + * JvB note: RFC3261 does not allow a comment to appear in Via headers, and this + * is not accessible through the API. Suggest removal + */ + protected String comment; + + private boolean rPortFlag = false; + + /** Default constructor + */ + public Via() { + super(NAME); + sentProtocol = new Protocol(); + } + + public boolean equals(Object other) { + + if (other==this) return true; + + if (other instanceof ViaHeader) { + final ViaHeader o = (ViaHeader) other; + return getProtocol().equalsIgnoreCase( o.getProtocol() ) + && getTransport().equalsIgnoreCase( o.getTransport() ) + && getHost().equalsIgnoreCase( o.getHost() ) + && getPort() == o.getPort() + && equalParameters( o ); + } + return false; + } + + + /** get the Protocol Version + * @return String + */ + public String getProtocolVersion() { + if (sentProtocol == null) + return null; + else + return sentProtocol.getProtocolVersion(); + } + + /** + * Accessor for the sentProtocol field. + * @return Protocol field + */ + public Protocol getSentProtocol() { + + return sentProtocol; + } + + /** + * Accessor for the sentBy field + *@return SentBy field + */ + public HostPort getSentBy() { + return sentBy; + } + + /** + * Get the host, port and transport as a Hop. This is + * useful for the stack to avoid duplication of code. + * + */ + public Hop getHop() { + HopImpl hop = new HopImpl(sentBy.getHost().getHostname(), + sentBy.getPort(),sentProtocol.getTransport()); + return hop; + } + + /** + * Accessor for the parameters field + * @return parameters field + */ + public NameValueList getViaParms() { + return parameters; + } + + /** + * Accessor for the comment field. + * @return comment field. + * @deprecated RFC 2543 support feature. + */ + public String getComment() { + return comment; + } + + + + /** port of the Via Header. + * @return true if Port exists. + */ + public boolean hasPort() { + return (getSentBy()).hasPort(); + } + + /** comment of the Via Header. + * + * @return false if comment does not exist and true otherwise. + */ + public boolean hasComment() { + return comment != null; + } + + /** remove the port. + */ + public void removePort() { + sentBy.removePort(); + } + + /** remove the comment field. + */ + public void removeComment() { + comment = null; + } + + /** set the Protocol Version + * @param protocolVersion String to set + */ + public void setProtocolVersion(String protocolVersion) { + if (sentProtocol == null) + sentProtocol = new Protocol(); + sentProtocol.setProtocolVersion(protocolVersion); + } + + /** set the Host of the Via Header + * @param host String to set + */ + public void setHost(Host host) { + if (sentBy == null) { + sentBy = new HostPort(); + } + sentBy.setHost(host); + } + + /** + * Set the sentProtocol member + * @param s Protocol to set. + */ + public void setSentProtocol(Protocol s) { + sentProtocol = s; + } + + /** + * Set the sentBy member + * @param s HostPort to set. + */ + public void setSentBy(HostPort s) { + sentBy = s; + } + + /** + * Set the comment member + * @param c String to set. + * @deprecated This is an RFC 2543 feature. + */ + public void setComment(String c) { + comment = c; + } + + /** Encode the body of this header (the stuff that follows headerName). + * A.K.A headerValue. + */ + protected String encodeBody() { + return encodeBody(new StringBuffer()).toString(); + } + + protected StringBuffer encodeBody(StringBuffer buffer) { + sentProtocol.encode(buffer); + buffer.append(SP); + sentBy.encode(buffer); + if (!parameters.isEmpty()) { + buffer.append(SEMICOLON); + parameters.encode(buffer); + } + if (comment != null) { + buffer.append(SP).append(LPAREN).append(comment).append(RPAREN); + } + if (rPortFlag) buffer.append(";rport"); + return buffer; + } + + /** + * Set the host part of this ViaHeader to the newly supplied <code>host</code> + * parameter. + * + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the host value. + */ + public void setHost(String host) throws ParseException { + if (sentBy == null) + sentBy = new HostPort(); + try { + Host h = new Host(host); + sentBy.setHost(h); + } catch (Exception e) { + throw new NullPointerException(" host parameter is null"); + } + } + + /** + * Returns the host part of this ViaHeader. + * + * @return the string value of the host + */ + public String getHost() { + if (sentBy == null) + return null; + else { + Host host = sentBy.getHost(); + if (host == null) + return null; + else + return host.getHostname(); + } + } + + /** + * Set the port part of this ViaHeader to the newly supplied <code>port</code> + * parameter. + * + * @param port - the Integer.valueOf value of the port of this ViaHeader + */ + public void setPort(int port) throws InvalidArgumentException { + + if ( port!=-1 && (port<1 || port>65535)) { + throw new InvalidArgumentException( "Port value out of range -1, [1..65535]" ); + } + + if (sentBy == null) + sentBy = new HostPort(); + sentBy.setPort(port); + } + + /** + * Set the RPort flag parameter + */ + public void setRPort(){ + rPortFlag = true; + } + + /** + * Returns the port part of this ViaHeader. + * + * @return the integer value of the port + */ + public int getPort() { + if (sentBy == null) + return -1; + return sentBy.getPort(); + } + + + /** + * Return the rport parameter. + * + *@return the rport parameter or -1. + */ + public int getRPort() { + String strRport = getParameter(ParameterNames.RPORT); + if (strRport != null && ! strRport.equals("")) + return Integer.valueOf(strRport).intValue(); + else + return -1; + } + + + /** + * Returns the value of the transport parameter. + * + * @return the string value of the transport paramter of the ViaHeader + */ + public String getTransport() { + if (sentProtocol == null) + return null; + return sentProtocol.getTransport(); + } + + /** + * Sets the value of the transport. This parameter specifies + * which transport protocol to use for sending requests and responses to + * this entity. The following values are defined: "udp", "tcp", "sctp", + * "tls", but other values may be used also. + * + * @param transport - new value for the transport parameter + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the transport value. + */ + public void setTransport(String transport) throws ParseException { + if (transport == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "Via, setTransport(), the transport parameter is null."); + if (sentProtocol == null) + sentProtocol = new Protocol(); + sentProtocol.setTransport(transport); + } + + /** + * Returns the value of the protocol used. + * + * @return the string value of the protocol paramter of the ViaHeader + */ + public String getProtocol() { + if (sentProtocol == null) + return null; + return sentProtocol.getProtocol();// JvB: Return name ~and~ version + } + + /** + * Sets the value of the protocol parameter. This parameter specifies + * which protocol is used, for example "SIP/2.0". + * + * @param protocol - new value for the protocol parameter + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the protocol value. + */ + public void setProtocol(String protocol) throws ParseException { + if (protocol == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "Via, setProtocol(), the protocol parameter is null."); + + if (sentProtocol == null) + sentProtocol = new Protocol(); + + sentProtocol.setProtocol(protocol); + } + + /** + * Returns the value of the ttl parameter, or -1 if this is not set. + * + * @return the integer value of the <code>ttl</code> parameter + */ + public int getTTL() { + int ttl = getParameterAsInt(ParameterNames.TTL); + return ttl; + } + + /** + * Sets the value of the ttl parameter. The ttl parameter specifies the + * time-to-live value when packets are sent using UDP multicast. + * + * @param ttl - new value of the ttl parameter + * @throws InvalidArgumentException if supplied value is less than zero or + * greater than 255, excluding -1 the default not set value. + */ + public void setTTL(int ttl) throws InvalidArgumentException { + if (ttl < 0 && ttl != -1) + throw new InvalidArgumentException( + "JAIN-SIP Exception" + + ", Via, setTTL(), the ttl parameter is < 0"); + setParameter(new NameValue(ParameterNames.TTL, Integer.valueOf(ttl))); + } + + /** + * Returns the value of the <code>maddr</code> parameter, or null if this + * is not set. + * + * @return the string value of the maddr parameter + */ + public String getMAddr() { + return getParameter(ParameterNames.MADDR); + } + + /** + * Sets the value of the <code>maddr</code> parameter of this ViaHeader. The + * maddr parameter indicates the server address to be contacted for this + * user, overriding any address derived from the host field. + * + * @param mAddr new value of the <code>maddr</code> parameter + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the mAddr value. + */ + public void setMAddr(String mAddr) throws ParseException { + if (mAddr == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "Via, setMAddr(), the mAddr parameter is null."); + + Host host = new Host(); + host.setAddress(mAddr); + NameValue nameValue = new NameValue(ParameterNames.MADDR, host); + setParameter(nameValue); + + } + + /** + * Gets the received paramater of the ViaHeader. Returns null if received + * does not exist. + * + * @return the string received value of ViaHeader + */ + public String getReceived() { + return getParameter(ParameterNames.RECEIVED); + } + + /** + * Sets the received parameter of ViaHeader. + * + * @param received - the newly supplied received parameter. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the received value. + */ + public void setReceived(String received) throws ParseException { + if (received == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "Via, setReceived(), the received parameter is null."); + + setParameter(ParameterNames.RECEIVED, received); + + } + + /** + * Gets the branch paramater of the ViaHeader. Returns null if branch + * does not exist. + * + * @return the string branch value of ViaHeader + */ + public String getBranch() { + return getParameter(ParameterNames.BRANCH); + } + + /** + * Sets the branch parameter of the ViaHeader to the newly supplied + * branch value. + * + * @param branch - the new string branch parmameter of the ViaHeader. + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the branch value. + */ + public void setBranch(String branch) throws ParseException { + if (branch == null || branch.length()==0) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "Via, setBranch(), the branch parameter is null or length 0."); + + setParameter(ParameterNames.BRANCH, branch); + } + + public Object clone() { + Via retval = (Via) super.clone(); + if (this.sentProtocol != null) + retval.sentProtocol = (Protocol) this.sentProtocol.clone(); + if (this.sentBy != null) + retval.sentBy = (HostPort) this.sentBy.clone(); + if ( this.getRPort() != -1) + retval.setParameter(RPORT,this.getRPort()); + return retval; + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.header.ViaHeaderExt#getSentByField() + */ + public String getSentByField() { + if(sentBy != null) + return sentBy.encode(); + return null; + } + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.header.ViaHeaderExt#getSentProtocolField() + */ + public String getSentProtocolField() { + if(sentProtocol != null) + return sentProtocol.encode(); + return null; + } + +} diff --git a/java/gov/nist/javax/sip/header/ViaHeaderExt.java b/java/gov/nist/javax/sip/header/ViaHeaderExt.java new file mode 100644 index 0000000..7fc1ed1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ViaHeaderExt.java @@ -0,0 +1,26 @@ +/* + * This code has been contributed by the authors to the public domain. + */ +package gov.nist.javax.sip.header; + +import javax.sip.header.ViaHeader; + + +/** + * @author jean.deruelle@gmail.com + * + */ +public interface ViaHeaderExt extends ViaHeader { + /** + * Returns hostname:port as a string equivalent to the "sent-by" field + * @return "sent-by" field + * @since 2.0 + */ + public String getSentByField(); + /** + * Returns transport to the "sent-protocol" field + * @return "sent-protocol" field + * @since 2.0 + */ + public String getSentProtocolField(); +} diff --git a/java/gov/nist/javax/sip/header/ViaList.java b/java/gov/nist/javax/sip/header/ViaList.java new file mode 100644 index 0000000..8b39763 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ViaList.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +import java.util.Iterator; + +/** + * Keeps a list and a hashtable of via header functions. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:41 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public final class ViaList extends SIPHeaderList<Via> { + + private static final long serialVersionUID = 3899679374556152313L; + + public Object clone() { + ViaList retval = new ViaList(); + return retval.clonehlist(this.hlist); + } + /** + * Default Constructor. + */ + public ViaList() { + super(Via.class, ViaHeader.NAME); + } + + + +} diff --git a/java/gov/nist/javax/sip/header/WWWAuthenticate.java b/java/gov/nist/javax/sip/header/WWWAuthenticate.java new file mode 100644 index 0000000..92a5163 --- /dev/null +++ b/java/gov/nist/javax/sip/header/WWWAuthenticate.java @@ -0,0 +1,82 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import gov.nist.javax.sip.header.ims.WWWAuthenticateHeaderIms; + +import javax.sip.address.URI; +import javax.sip.header.*; + +/** + * The WWWAuthenticate SIP header. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:41 $ + * + * + * + * @see WWWAuthenticateList SIPHeader which strings these together. + */ + +public class WWWAuthenticate + extends AuthenticationHeader + implements WWWAuthenticateHeader, WWWAuthenticateHeaderIms { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 115378648697363486L; + + /** + * Default Constructor. + */ + public WWWAuthenticate() { + super(NAME); + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AuthenticationHeader#getURI() + * + * @since 1.2 this method is deprecated, uri is not a valid paramter for this header + * Fail silently for backwards compatibility + */ + public URI getURI() { + return null; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.AuthenticationHeader#setURI(javax.sip.address.URI) + * + * @since 1.2 this method is deprecated, uri is not a valid paramter for this header + * Fail silently for backwards compatibility + */ + public void setURI(URI uri) { + // empty, fail silently + } + +} diff --git a/java/gov/nist/javax/sip/header/WWWAuthenticateList.java b/java/gov/nist/javax/sip/header/WWWAuthenticateList.java new file mode 100644 index 0000000..7d0d23d --- /dev/null +++ b/java/gov/nist/javax/sip/header/WWWAuthenticateList.java @@ -0,0 +1,58 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; + +/** + * WWWAuthenticate SIPHeader (of which there can be several?) + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:41 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class WWWAuthenticateList extends SIPHeaderList<WWWAuthenticate> { + + + private static final long serialVersionUID = -6978902284285501346L; + + + public Object clone() { + WWWAuthenticateList retval = new WWWAuthenticateList(); + return retval.clonehlist(this.hlist); + } + /** + * constructor. + */ + public WWWAuthenticateList() { + super(WWWAuthenticate.class, WWWAuthenticateHeader.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/Warning.java b/java/gov/nist/javax/sip/header/Warning.java new file mode 100644 index 0000000..c12fd11 --- /dev/null +++ b/java/gov/nist/javax/sip/header/Warning.java @@ -0,0 +1,229 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; +import javax.sip.header.*; +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +/** + * the WarningValue SIPObject. + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:33 $ + * + * + * + * @see WarningList SIPHeader which strings these together. + */ +public class Warning extends SIPHeader implements WarningHeader { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -3433328864230783899L; + + /** warn code field, the warn code consists of three digits. + */ + protected int code; + + /** the name or pseudonym of the server adding + * the Warning header, for use in debugging + */ + protected String agent; + + /** warn-text field + */ + protected String text; + + /** + * constructor. + */ + public Warning() { + super(WARNING); + } + + /** Encode the body of the header (return the stuff following name:). + *@return the string encoding of the header value. + */ + public String encodeBody() { + return text != null + ? Integer.toString(code) + + SP + + agent + + SP + + DOUBLE_QUOTE + + text + + DOUBLE_QUOTE + : Integer.toString(code) + SP + agent; + } + + /** + * Gets code of WarningHeader + * @return code of WarningHeader + */ + public int getCode() { + return code; + } + + /** + * Gets agent host of WarningHeader + * @return agent host of WarningHeader + */ + public String getAgent() { + return agent; + } + + /** + * Gets text of WarningHeader + * @return text of WarningHeader + */ + public String getText() { + return text; + } + + /** + * Sets code of WarningHeader + * @param code int to set + * @throws SipParseException if code is not accepted by implementation + */ + public void setCode(int code) throws InvalidArgumentException { + if (code >99 && code < 1000) { // check this is a 3DIGIT code + this.code = code; + } else + throw new InvalidArgumentException( + "Code parameter in the Warning header is invalid: code=" + + code); + } + + /** + * Sets host of WarningHeader + * @param host String to set + * @throws ParseException if host is not accepted by implementation + */ + public void setAgent(String host) throws ParseException { + if (host == null) + throw new NullPointerException("the host parameter in the Warning header is null"); + else { + this.agent = host; + } + } + + /** + * Sets text of WarningHeader + * @param text String to set + * @throws ParseException if text is not accepted by implementation + */ + public void setText(String text) throws ParseException { + if (text == null) { + throw new ParseException( + "The text parameter in the Warning header is null", + 0); + } else + this.text = text; + } +} +/* + * $Log: Warning.java,v $ + * Revision 1.8 2009/10/18 13:46:33 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.7 2009/07/17 18:57:41 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:01:44 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/04/22 22:51:16 mranga + * Submitted by: Thomas Froment + * Reviewed by: mranga + * + * Fixed corner cases. + * + * Revision 1.2 2004/01/22 13:26:30 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/header/WarningList.java b/java/gov/nist/javax/sip/header/WarningList.java new file mode 100644 index 0000000..5094731 --- /dev/null +++ b/java/gov/nist/javax/sip/header/WarningList.java @@ -0,0 +1,60 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header; + +import javax.sip.header.*; + +/** + * A list of Warning headers. + * + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:41 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class WarningList extends SIPHeaderList<Warning> { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -1423278728898430175L; + + public Object clone() { + WarningList retval = new WarningList(); + return retval.clonehlist(this.hlist); + } + /** + * Constructor. + */ + public WarningList() { + super(Warning.class, Warning.NAME); + } +} diff --git a/java/gov/nist/javax/sip/header/extensions/Join.java b/java/gov/nist/javax/sip/header/extensions/Join.java new file mode 100644 index 0000000..73a8252 --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/Join.java @@ -0,0 +1,187 @@ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header.extensions; +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +import javax.sip.header.ExtensionHeader; +/* +* This code is in the public domain. +*/ + +/** + * Join SIPHeader. + * + * @author jean.deruelle@gmail.com <br/> + * + * @version JAIN-SIP-1.2 + * + * + */ + +public class Join + extends ParametersHeader implements ExtensionHeader, JoinHeader { + + /** + * + */ + private static final long serialVersionUID = -840116548918120056L; + + public static final String NAME = "Join"; + + /** + * callIdentifier field + */ + public CallIdentifier callIdentifier; + public String callId; + + /** + * Default constructor + */ + public Join() { + super(NAME); + } + + /** Constructor given the call Identifier. + *@param callId string call identifier (should be localid@host) + *@throws IllegalArgumentException if call identifier is bad. + */ + public Join(String callId) throws IllegalArgumentException { + super(NAME); + this.callIdentifier = new CallIdentifier(callId); + } + + /** + * Encode the body part of this header (i.e. leave out the hdrName). + * @return String encoded body part of the header. + */ + public String encodeBody() { + if (callId == null) + return null; + else { + String retVal = callId; + if (!parameters.isEmpty()) { + retVal += SEMICOLON + parameters.encode(); + } + return retVal; + } + } + + /** + * get the CallId field. This does the same thing as encodeBody + * + * @return String the encoded body part of the + */ + public String getCallId() { + return callId; + } + + /** + * get the call Identifer member. + * @return CallIdentifier + */ + public CallIdentifier getCallIdentifer() { + return callIdentifier; + } + + /** + * set the CallId field + * @param cid String to set. This is the body part of the Call-Id + * header. It must have the form localId@host or localId. + * @throws IllegalArgumentException if cid is null, not a token, or is + * not a token@token. + */ + public void setCallId(String cid) { + callId = cid; + } + + /** + * Set the callIdentifier member. + * @param cid CallIdentifier to set (localId@host). + */ + public void setCallIdentifier(CallIdentifier cid) { + callIdentifier = cid; + } + + /** + * Get the to-tag parameter from the address parm list. + * @return tag field + */ + public String getToTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.TO_TAG); + } + /** + * Set the to-tag member + * @param t tag to set. From tags are mandatory. + */ + public void setToTag(String t) throws ParseException { + if (t == null) + throw new NullPointerException("null tag "); + else if (t.trim().equals("")) + throw new ParseException("bad tag", 0); + this.setParameter(ParameterNames.TO_TAG, t); + } + /** Boolean function + * @return true if the Tag exist + */ + public boolean hasToTag() { + return hasParameter(ParameterNames.TO_TAG); + } + + /** remove Tag member + */ + public void removeToTag() { + parameters.delete(ParameterNames.TO_TAG); + } + /** + * Get the from-tag parameter from the address parm list. + * @return tag field + */ + public String getFromTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.FROM_TAG); + } + /** + * Set the to-tag member + * @param t tag to set. From tags are mandatory. + */ + public void setFromTag(String t) throws ParseException { + if (t == null) + throw new NullPointerException("null tag "); + else if (t.trim().equals("")) + throw new ParseException("bad tag", 0); + this.setParameter(ParameterNames.FROM_TAG, t); + } + /** Boolean function + * @return true if the Tag exist + */ + public boolean hasFromTag() { + return hasParameter(ParameterNames.FROM_TAG); + } + + /** remove Tag member + */ + public void removeFromTag() { + parameters.delete(ParameterNames.FROM_TAG); + } + + + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + +// public Object clone() { +// CallID retval = (CallID) super.clone(); +// if (this.callIdentifier != null) +// retval.setCallIdentifier( (CallIdentifier) this.callIdentifier.clone() ); +// return retval; +// } +} + diff --git a/java/gov/nist/javax/sip/header/extensions/JoinHeader.java b/java/gov/nist/javax/sip/header/extensions/JoinHeader.java new file mode 100644 index 0000000..105cf15 --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/JoinHeader.java @@ -0,0 +1,229 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.header.extensions; + + + +import java.text.ParseException; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + + +/** + * The From header field indicates the logical identity of the initiator + + * of the request, possibly the user's address-of-record. This may be different + + * from the initiator of the dialog. Requests sent by the callee to the caller + + * use the callee's address in the From header field. + + * <p> + + * Like the To header field, it contains a URI and optionally a display name, + + * encapsulated in a {@link javax.sip.address.Address}. It is used by SIP + + * elements to determine which processing rules to apply to a request (for + + * example, automatic call rejection). As such, it is very important that the + + * From URI not contain IP addresses or the FQDN of the host on which the UA is + + * running, since these are not logical names. + + * <p> + + * The From header field allows for a display name. A UAC SHOULD use + + * the display name "Anonymous", along with a syntactically correct, but + + * otherwise meaningless URI (like sip:thisis@anonymous.invalid), if the + + * identity of the client is to remain hidden. + + * <p> + + * Usually, the value that populates the From header field in requests + + * generated by a particular UA is pre-provisioned by the user or by the + + * administrators of the user's local domain. If a particular UA is used by + + * multiple users, it might have switchable profiles that include a URI + + * corresponding to the identity of the profiled user. Recipients of requests + + * can authenticate the originator of a request in order to ascertain that + + * they are who their From header field claims they are. + + * <p> + + * Two From header fields are equivalent if their URIs match, and their + + * parameters match. Extension parameters in one header field, not present in + + * the other are ignored for the purposes of comparison. This means that the + + * display name and presence or absence of angle brackets do not affect + + * matching. + + * <ul> + + * <li> The "Tag" parameter - is used in the To and From header fields of SIP + + * messages. It serves as a general mechanism to identify a dialog, which is + + * the combination of the Call-ID along with two tags, one from each + + * participant in the dialog. When a User Agent sends a request outside of a dialog, + + * it contains a From tag only, providing "half" of the dialog ID. The dialog + + * is completed from the response(s), each of which contributes the second half + + * in the To header field. When a tag is generated by a User Agent for insertion into + + * a request or response, it MUST be globally unique and cryptographically + + * random with at least 32 bits of randomness. Besides the requirement for + + * global uniqueness, the algorithm for generating a tag is implementation + + * specific. Tags are helpful in fault tolerant systems, where a dialog is to + + * be recovered on an alternate server after a failure. A UAS can select the + + * tag in such a way that a backup can recognize a request as part of a dialog + + * on the failed server, and therefore determine that it should attempt to + + * recover the dialog and any other state associated with it. + + * </ul> + * For Example:<br> + * <code>From: "Bob" sips:bob@biloxi.com ;tag=a48s<br> + * From: sip:+12125551212@phone2net.com;tag=887s<br> + * From: Anonymous sip:c8oqz84zk7z@privacy.org;tag=hyh8</code> + * + * @version 1.1 + * @author jean.deruelle@gmail.com + */ +public interface JoinHeader extends Parameters, Header { + + + + /** + + * Sets the tag parameter of the FromHeader. The tag in the From field of a + * request identifies the peer of the dialog. When a UA sends a request + * outside of a dialog, it contains a From tag only, providing "half" of + * the dialog Identifier. + * <p> + * The From Header MUST contain a new "tag" parameter, chosen by the UAC + * applicaton. Once the initial From "tag" is assigned it should not be + * manipulated by the application. That is on the client side for outbound + * requests the application is responsible for Tag assigmennment, after + * dialog establishment the stack will take care of Tag assignment. + * + * @param tag - the new tag of the FromHeader + * @throws ParseException which signals that an error has been reached + * unexpectedly while parsing the Tag value. + */ + public void setToTag(String tag) throws ParseException; + public void setFromTag(String tag) throws ParseException; + + + + + + /** + + * Gets the tag of FromHeader. The Tag parameter identified the Peer of the + + * dialogue and must always be present. + + * + + * @return the tag parameter of the FromHeader. + + */ + + public String getToTag(); + public String getFromTag(); + + + /** + + * Sets the Call-Id of the CallIdHeader. The CallId parameter uniquely + + * identifies a serious of messages within a dialogue. + + * + + * @param callId - the string value of the Call-Id of this CallIdHeader. + + * @throws ParseException which signals that an error has been reached + + * unexpectedly while parsing the callId value. + + */ + + public void setCallId(String callId) throws ParseException; + + + + /** + + * Returns the Call-Id of CallIdHeader. The CallId parameter uniquely + + * identifies a series of messages within a dialogue. + + * + + * @return the String value of the Call-Id of this CallIdHeader + + */ + + public String getCallId(); + + + + /** + + * Name of JoinHeader + + */ + + public final static String NAME = "Join"; + +} + + diff --git a/java/gov/nist/javax/sip/header/extensions/MinSE.java b/java/gov/nist/javax/sip/header/extensions/MinSE.java new file mode 100644 index 0000000..6e00c6f --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/MinSE.java @@ -0,0 +1,98 @@ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +/* +* This code has been contributed by the author to the public domain. +*/ +package gov.nist.javax.sip.header.extensions; + +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +import javax.sip.*; +import javax.sip.header.ExtensionHeader; + +/** + * MinSE SIP Header. + * + * (Created by modifying Expires.java) + * + * @version JAIN-SIP-1.1 $Revision: 1.4 $ $Date: 2009/10/18 13:46:36 $ + * + * @author P. Musgrave <pmusgrave@newheights.com> <br/> + * + */ +public class MinSE + extends ParametersHeader implements ExtensionHeader, MinSEHeader { + + // TODO: When the MinSEHeader is added to javax - move this there...pmusgrave + public static final String NAME = "Min-SE"; + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = 3134344915465784267L; + + /** expires field + */ + public int expires; + + /** default constructor + */ + public MinSE() { + super(NAME); + } + + /** + * Return canonical form. + * @return String + */ + public String encodeBody() { + String retval = Integer.toString(expires); // seems overkill - but Expires did this. + + if (!parameters.isEmpty()) { + retval += SEMICOLON + parameters.encode(); + } + return retval; + } + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + + /** + * Gets the expires value of the ExpiresHeader. This expires value is + * + * relative time. + * + * + * + * @return the expires value of the ExpiresHeader. + * + * @since JAIN SIP v1.1 + * + */ + public int getExpires() { + return expires; + } + + /** + * Sets the relative expires value of the ExpiresHeader. + * The expires value MUST be greater than zero and MUST be + * less than 2**31. + * + * @param expires - the new expires value of this ExpiresHeader + * + * @throws InvalidArgumentException if supplied value is less than zero. + * + * @since JAIN SIP v1.2 + * + */ + public void setExpires(int expires) throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad argument " + expires); + this.expires = expires; + } +} diff --git a/java/gov/nist/javax/sip/header/extensions/MinSEHeader.java b/java/gov/nist/javax/sip/header/extensions/MinSEHeader.java new file mode 100644 index 0000000..0a51175 --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/MinSEHeader.java @@ -0,0 +1,11 @@ +package gov.nist.javax.sip.header.extensions; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; + +public interface MinSEHeader extends Parameters, Header { + + public final static String NAME = "Min-SE"; + +} + diff --git a/java/gov/nist/javax/sip/header/extensions/References.java b/java/gov/nist/javax/sip/header/extensions/References.java new file mode 100644 index 0000000..43a72a8 --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/References.java @@ -0,0 +1,87 @@ +package gov.nist.javax.sip.header.extensions; + +import gov.nist.javax.sip.header.ParametersHeader; + +import java.text.ParseException; +import java.util.Iterator; + +import javax.sip.header.ExtensionHeader; + +public class References extends ParametersHeader implements ReferencesHeader,ExtensionHeader { + + private static final long serialVersionUID = 8536961681006637622L; + + + private String callId; + + public References() { + super(ReferencesHeader.NAME); + } + + + + + public String getCallId() { + return callId; + } + + + + public String getRel() { + return this.getParameter(REL); + } + + + + + public void setCallId(String callId) { + this.callId = callId; + } + + + public void setRel(String rel) throws ParseException{ + if ( rel != null ) { + this.setParameter(REL,rel); + } + } + + + public String getParameter(String name) { + return super.getParameter(name); + } + + + public Iterator getParameterNames() { + return super.getParameterNames(); + } + + + public void removeParameter(String name) { + super.removeParameter(name); + } + + + public void setParameter(String name, String value) throws ParseException { + super.setParameter(name,value); + } + + + public String getName() { + return ReferencesHeader.NAME; + } + + + protected String encodeBody() { + if ( super.parameters.isEmpty()) { + return callId ; + } else { + return callId + ";" + super.parameters.encode(); + } + } + + + public void setValue(String value) throws ParseException { + throw new UnsupportedOperationException("operation not supported"); + } + +} diff --git a/java/gov/nist/javax/sip/header/extensions/ReferencesHeader.java b/java/gov/nist/javax/sip/header/extensions/ReferencesHeader.java new file mode 100644 index 0000000..987e3b7 --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/ReferencesHeader.java @@ -0,0 +1,39 @@ +package gov.nist.javax.sip.header.extensions; + + +import java.text.ParseException; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; + +/** + * References header: See http://tools.ietf.org/html/draft-worley-references-05 + */ +public interface ReferencesHeader extends Parameters, Header { + + public static final String NAME = "References"; + + public static final String CHAIN = "chain"; + + public static final String INQUIRY = "inquiry"; + + public static final String REFER = "refer" ; + + public static final String SEQUEL = "sequel"; + + public static final String XFER = "xfer"; + + public static final String REL = "rel"; + + public static final String SERVICE = "service"; + + public void setCallId(String callId) throws ParseException; + + public String getCallId(); + + public void setRel (String rel) throws ParseException; + + public String getRel(); + + +} diff --git a/java/gov/nist/javax/sip/header/extensions/ReferredBy.java b/java/gov/nist/javax/sip/header/extensions/ReferredBy.java new file mode 100644 index 0000000..612e04c --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/ReferredBy.java @@ -0,0 +1,134 @@ + +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header.extensions; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; +import gov.nist.javax.sip.header.*; + +import gov.nist.javax.sip.address.*; +/* +* This code has been contributed by the author to the public domain. +*/ + +/** + * ReferredBy SIP Header. RFC 3892 + * + * @version JAIN-SIP-1.2 + * + * @author Peter Musgrave. + * + * + */ +public final class ReferredBy + extends AddressParametersHeader implements ExtensionHeader, ReferredByHeader { + + // TODO: Need a unique UID + private static final long serialVersionUID = 3134344915465784267L; + + // TODO: When the MinSEHeader is added to javax - move this there...pmusgrave + public static final String NAME = "Referred-By"; + + /** default Constructor. + */ + public ReferredBy() { + super(NAME); + } + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + + /** + * Encode the header content into a String. + * @return String + */ + protected String encodeBody() { + if (address == null) + return null; + String retval = ""; + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += LESS_THAN; + } + retval += address.encode(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval += GREATER_THAN; + } + + if (!parameters.isEmpty()) { + retval += SEMICOLON + parameters.encode(); + } + return retval; + } +} +/* + * $Log: ReferredBy.java,v $ + * Revision 1.3 2009/07/17 18:57:42 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.2 2006/10/27 20:58:31 mranga + * Issue number: + * Obtained from: + * Submitted by: + * Reviewed by: mranga + * doc fixups + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.1 2006/10/12 11:57:52 pmusgrave + * Issue number: 79, 80 + * Submitted by: pmusgrave@newheights.com + * Reviewed by: mranga + * + * Revision 1.2 2006/03/20 20:52:03 pmusgrave + * Add RefferedBy to header factory + * Correct implements statement in ReferredBy + * + * Revision 1.1.1.1 2006/03/15 16:00:07 pmusgrave + * Source with additions + * + * Revision 1.3 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ + diff --git a/java/gov/nist/javax/sip/header/extensions/ReferredByHeader.java b/java/gov/nist/javax/sip/header/extensions/ReferredByHeader.java new file mode 100644 index 0000000..ef7477f --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/ReferredByHeader.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed 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 gov.nist.javax.sip.header.extensions; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + +public interface ReferredByHeader extends Header, HeaderAddress, Parameters { + + String NAME = "Referred-By"; +} diff --git a/java/gov/nist/javax/sip/header/extensions/Replaces.java b/java/gov/nist/javax/sip/header/extensions/Replaces.java new file mode 100644 index 0000000..540f9ea --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/Replaces.java @@ -0,0 +1,256 @@ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.header.extensions; +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +import javax.sip.header.ExtensionHeader; +/* +* This code is in the public domain. +*/ + +/** + * Replaces SIPHeader. + * ToDo: add support for early-only flag. + * + * @author P, Musgrave <pmusgrave@mkcnetworks.com> <br/> + * + * @version JAIN-SIP-1.2 + * + * + */ + +public class Replaces + extends ParametersHeader implements ExtensionHeader, ReplacesHeader { + + // TODO: Need a unique UID + private static final long serialVersionUID = 8765762413224043300L; + + // TODO: When the MinSEHeader is added to javax - move this there...pmusgrave + public static final String NAME = "Replaces"; + + /** + * callIdentifier field + */ + public CallIdentifier callIdentifier; + public String callId; + + /** + * Default constructor + */ + public Replaces() { + super(NAME); + } + + /** Constructor given the call Identifier. + *@param callId string call identifier (should be localid@host) + *@throws IllegalArgumentException if call identifier is bad. + */ + public Replaces(String callId) throws IllegalArgumentException { + super(NAME); + this.callIdentifier = new CallIdentifier(callId); + } + + /** + * Encode the body part of this header (i.e. leave out the hdrName). + * @return String encoded body part of the header. + */ + public String encodeBody() { + if (callId == null) + return null; + else { + String retVal = callId; + if (!parameters.isEmpty()) { + retVal += SEMICOLON + parameters.encode(); + } + return retVal; + } + } + + /** + * get the CallId field. This does the same thing as encodeBody + * + * @return String the encoded body part of the + */ + public String getCallId() { + return callId; + } + + /** + * get the call Identifer member. + * @return CallIdentifier + */ + public CallIdentifier getCallIdentifer() { + return callIdentifier; + } + + /** + * set the CallId field + * @param cid String to set. This is the body part of the Call-Id + * header. It must have the form localId@host or localId. + * @throws IllegalArgumentException if cid is null, not a token, or is + * not a token@token. + */ + public void setCallId(String cid) { + callId = cid; + } + + /** + * Set the callIdentifier member. + * @param cid CallIdentifier to set (localId@host). + */ + public void setCallIdentifier(CallIdentifier cid) { + callIdentifier = cid; + } + + /** + * Get the to-tag parameter from the address parm list. + * @return tag field + */ + public String getToTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.TO_TAG); + } + /** + * Set the to-tag member + * @param t tag to set. From tags are mandatory. + */ + public void setToTag(String t) throws ParseException { + if (t == null) + throw new NullPointerException("null tag "); + else if (t.trim().equals("")) + throw new ParseException("bad tag", 0); + this.setParameter(ParameterNames.TO_TAG, t); + } + /** Boolean function + * @return true if the Tag exist + */ + public boolean hasToTag() { + return hasParameter(ParameterNames.TO_TAG); + } + + /** remove Tag member + */ + public void removeToTag() { + parameters.delete(ParameterNames.TO_TAG); + } + /** + * Get the from-tag parameter from the address parm list. + * @return tag field + */ + public String getFromTag() { + if (parameters == null) + return null; + return getParameter(ParameterNames.FROM_TAG); + } + /** + * Set the to-tag member + * @param t tag to set. From tags are mandatory. + */ + public void setFromTag(String t) throws ParseException { + if (t == null) + throw new NullPointerException("null tag "); + else if (t.trim().equals("")) + throw new ParseException("bad tag", 0); + this.setParameter(ParameterNames.FROM_TAG, t); + } + /** Boolean function + * @return true if the Tag exist + */ + public boolean hasFromTag() { + return hasParameter(ParameterNames.FROM_TAG); + } + + /** remove Tag member + */ + public void removeFromTag() { + parameters.delete(ParameterNames.FROM_TAG); + } + + + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + +// public Object clone() { +// CallID retval = (CallID) super.clone(); +// if (this.callIdentifier != null) +// retval.setCallIdentifier( (CallIdentifier) this.callIdentifier.clone() ); +// return retval; +// } +} +/* + * $Log: Replaces.java,v $ + * Revision 1.3 2009/07/17 18:57:42 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.2 2006/10/27 20:58:31 mranga + * Issue number: + * Obtained from: + * Submitted by: + * Reviewed by: mranga + * doc fixups + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.1 2006/10/12 11:57:51 pmusgrave + * Issue number: 79, 80 + * Submitted by: pmusgrave@newheights.com + * Reviewed by: mranga + * + * Revision 1.3 2006/07/19 15:05:20 pmusgrave + * Modify encodeBody so it uses callId and not CallIdentifier + * + * Revision 1.2 2006/04/17 23:41:31 pmusgrave + * Add Session Timer and Replaces headers + * + * Revision 1.1.1.1 2006/03/15 16:00:07 pmusgrave + * Source with additions + * + * Revision 1.3 2005/04/16 20:38:48 dmuresan + * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies + * + * Revision 1.2 2004/01/22 13:26:29 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ + diff --git a/java/gov/nist/javax/sip/header/extensions/ReplacesHeader.java b/java/gov/nist/javax/sip/header/extensions/ReplacesHeader.java new file mode 100644 index 0000000..305bc7a --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/ReplacesHeader.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed 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 gov.nist.javax.sip.header.extensions; + +import java.text.ParseException; +import javax.sip.header.Header; +import javax.sip.header.Parameters; + +public interface ReplacesHeader extends Header, Parameters { + + String NAME = "Replaces"; + String getToTag(); + void setToTag(String tag) throws ParseException; + String getFromTag(); + void setFromTag(String tag) throws ParseException; + String getCallId(); + void setCallId(String callId) throws ParseException; +}
\ No newline at end of file diff --git a/java/gov/nist/javax/sip/header/extensions/SessionExpires.java b/java/gov/nist/javax/sip/header/extensions/SessionExpires.java new file mode 100644 index 0000000..7854acf --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/SessionExpires.java @@ -0,0 +1,104 @@ + +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.header.extensions; + +import gov.nist.javax.sip.header.ParametersHeader; + +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.ExtensionHeader; + +/** + * ReferredBy SIP Header. + * + * @version JAIN-SIP-1.1 $Revision: 1.5 $ $Date: 2009/10/18 13:46:36 $ + * + * @author Peter Musgrave. + * + */ +public final class SessionExpires + extends ParametersHeader implements ExtensionHeader, SessionExpiresHeader { + + // TODO: Need a unique UID + private static final long serialVersionUID = 8765762413224043300L; + + // TODO: When the MinSEHeader is added to javax - move this there...pmusgrave + public static final String NAME = "Session-Expires"; + + public int expires; + + public static final String REFRESHER = "refresher"; + /** default Constructor. + */ + public SessionExpires() { + super(NAME); + } + + /** + * Gets the expires value of the SessionExpiresHeader. This expires value is + * relative time. + * + * + * + * @return the expires value of the ExpiresHeader. + * + * @since JAIN SIP v1.1 + * + */ + public int getExpires() { + return expires; + } + + /** + * Sets the relative expires value of the SessionExpiresHeader. + * The expires value MUST be greater than zero and MUST be + * less than 2**31. + * + * @param expires - the new expires value + * + * @throws InvalidArgumentException if supplied value is less than zero. + * + * @since JAIN SIP v1.1 + * + */ + public void setExpires(int expires) throws InvalidArgumentException { + if (expires < 0) + throw new InvalidArgumentException("bad argument " + expires); + this.expires = expires; + } + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + + /** + * Encode the header content into a String. + * @return String + */ + protected String encodeBody() { + + String retval = Integer.toString(expires); + + if (!parameters.isEmpty()) { + retval += SEMICOLON + parameters.encode(); + } + return retval; + } + + public String getRefresher() { + return parameters.getParameter(REFRESHER); + } + + public void setRefresher(String refresher) { + this.parameters.set(REFRESHER,refresher); + } +} + + + diff --git a/java/gov/nist/javax/sip/header/extensions/SessionExpiresHeader.java b/java/gov/nist/javax/sip/header/extensions/SessionExpiresHeader.java new file mode 100644 index 0000000..4d6445f --- /dev/null +++ b/java/gov/nist/javax/sip/header/extensions/SessionExpiresHeader.java @@ -0,0 +1,27 @@ +package gov.nist.javax.sip.header.extensions; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.*; + +/* + * Extension for SessionTimer RFC 4028 + * + * + */ + + +public interface SessionExpiresHeader extends Parameters, Header, ExtensionHeader{ + + public final static String NAME = "Session-Expires"; + + public int getExpires(); + + public void setExpires(int expires) throws InvalidArgumentException; + + public String getRefresher() ; + + public void setRefresher(String refresher); + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/AddressHeaderIms.java b/java/gov/nist/javax/sip/header/ims/AddressHeaderIms.java new file mode 100644 index 0000000..b785853 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/AddressHeaderIms.java @@ -0,0 +1,84 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.address.Address; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.SIPHeader; + +/** + * AddressHeader base class. + * @author ALEXANDRE MIGUEL SILVA SANTOS (PT Innovacau) + */ + +public abstract class AddressHeaderIms extends SIPHeader { + + protected AddressImpl address; + + /** + * get the Address field + * @return the imbedded Address + */ + public Address getAddress() { + return address; + } + + /** + * set the Address field + * @param address Address to set + */ + public void setAddress(Address address) { + this.address = (AddressImpl) address; + } + + public abstract String encodeBody(); + //protected abstract String encodeBody(); + + + /** + * Constructor given the name of the header. + */ + public AddressHeaderIms(String name) { + //protected AddressHeader(String name) { + super(name); + } + + public Object clone() { + AddressHeaderIms retval = (AddressHeaderIms) super.clone(); + if (this.address != null) + retval.address = (AddressImpl) this.address.clone(); + return retval; + } + + +} + diff --git a/java/gov/nist/javax/sip/header/ims/AuthorizationHeaderIms.java b/java/gov/nist/javax/sip/header/ims/AuthorizationHeaderIms.java new file mode 100644 index 0000000..d65b2d1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/AuthorizationHeaderIms.java @@ -0,0 +1,67 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import javax.sip.header.AuthorizationHeader; + + +/** + * + * Extension to Authorization header (3GPP TS 24299-5d0) + * + * This extension defines a new auth-param for the Authorization header used + * in REGISTER requests. + * For more information, see RFC 2617 [21] subclause 3.2.2. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public interface AuthorizationHeaderIms extends AuthorizationHeader +{ + + // issued by Miguel Freitas (IT) PT-Inovacao + public static final String YES = "yes"; + public static final String NO = "no"; + + + + /** + * @param integrityProtected + * @throws ParseException + */ + public void setIntegrityProtected(String integrityProtected) throws InvalidArgumentException, ParseException; + + + public String getIntegrityProtected(); + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfo.java b/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfo.java new file mode 100644 index 0000000..c220c78 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfo.java @@ -0,0 +1,288 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government, + * and others. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ContactHeader; +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.header.ParametersHeader; + +/** + * <p>P-Access-Network-Info SIP Private Header</p> + * + * @author Miguel Freitas (IT) PT-Inovacao + * + * @since 1.2 + */ + +public class PAccessNetworkInfo + extends ParametersHeader + implements PAccessNetworkInfoHeader, ExtensionHeader { + + // TODO: serialVersionUID + + private String accessType; + + private Object extendAccessInfo; + + /** + * Public constructor. + */ + public PAccessNetworkInfo() { + super(PAccessNetworkInfoHeader.NAME); + parameters.setSeparator(SEMICOLON); + } + + /** + * Constructor. + */ + public PAccessNetworkInfo(String accessTypeVal) { + this(); + setAccessType(accessTypeVal); + } + + /** + * Set the accessTpe + * + * @param accessTypeVal - access type + * @throws NullPointerException + */ + public void setAccessType(String accessTypeVal) { + if (accessTypeVal == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setAccessType(), the accessType parameter is null."); + + this.accessType = accessTypeVal; + } + + /** + * @return String access type + */ + public String getAccessType() { + return accessType; + } + + /** + * + * @param cgi -- String CGI value + * @throws NullPointerException -- if null argument passed in + * @throws ParseException -- if bad argument passed in. + */ + public void setCGI3GPP(String cgi) throws ParseException { + + if (cgi == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setCGI3GPP(), the cgi parameter is null."); + + setParameter(ParameterNamesIms.CGI_3GPP, cgi); + + } + + /** + * + * @return String CGI value + */ + public String getCGI3GPP() { + return getParameter(ParameterNamesIms.CGI_3GPP); + } + + /** + * Set the UtranCellID field. + * + * @param utranCellID -- String UTRAN Cell ID value + * @throws NullPointerException + * @throws ParseException + */ + public void setUtranCellID3GPP(String utranCellID) throws ParseException { + + if (utranCellID == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setUtranCellID3GPP(), the utranCellID parameter is null."); + + setParameter(ParameterNamesIms.UTRAN_CELL_ID_3GPP, utranCellID); + + } + + /** + * + * @return String UTRAN Cell ID value + */ + public String getUtranCellID3GPP() { + return getParameter(ParameterNamesIms.UTRAN_CELL_ID_3GPP); + } + + /** + * + * @param dslLocation - String with the DSL location value + * @throws NullPointerException + * @throws ParseException + */ + public void setDSLLocation(String dslLocation) throws ParseException { + + if (dslLocation == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setDSLLocation(), the dslLocation parameter is null."); + + setParameter(ParameterNamesIms.DSL_LOCATION, dslLocation); + + } + + /** + * + * @return String DSL location value + */ + public String getDSLLocation() { + return getParameter(ParameterNamesIms.DSL_LOCATION); + } + + /** + * + * @param ci3Gpp2 -- String CI 3GPP2 value + * @throws NullPointerException -- if arg is null + * @throws ParseException -- if arg is bad. + */ + public void setCI3GPP2(String ci3Gpp2) throws ParseException { + if (ci3Gpp2 == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setCI3GPP2(), the ci3Gpp2 parameter is null."); + + setParameter(ParameterNamesIms.CI_3GPP2, ci3Gpp2); + } + + /** + * + * @return String CI 3GPP2 value + */ + public String getCI3GPP2() { + return getParameter(ParameterNamesIms.CI_3GPP2); + } + + /** + * + * @param name -- + * parameter name + * @param value -- + * value of parameter + */ + public void setParameter(String name, Object value) { + /** + * @todo ParametersHeader needs to be fix!? missing "throws + * ParseException" in setParameter(String, Object) + */ + + if (name.equalsIgnoreCase(ParameterNamesIms.CGI_3GPP) + || name.equalsIgnoreCase(ParameterNamesIms.UTRAN_CELL_ID_3GPP) + || name.equalsIgnoreCase(ParameterNamesIms.DSL_LOCATION) + || name.equalsIgnoreCase(ParameterNamesIms.CI_3GPP2)) { + try { + super.setQuotedParameter(name, value.toString()); + } catch (ParseException e) { + + } + + } else { + // value can be token either than a quoted-string + super.setParameter(name, value); + + } + + } + + /** + * extension-access-info = gen-value gen-value = token / host / + * quoted-string + * + * @param extendAccessInfo - extended Access Information + */ + public void setExtensionAccessInfo(Object extendAccessInfo) + throws ParseException { + + if (extendAccessInfo == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Access-Network-Info, setExtendAccessInfo(), the extendAccessInfo parameter is null."); + + // or -> setParameter("", extendAccessInfo); + + this.extendAccessInfo = extendAccessInfo; + + } + + public Object getExtensionAccessInfo() { + return this.extendAccessInfo; + } + + protected String encodeBody() { + + StringBuffer encoding = new StringBuffer(); + + if (getAccessType() != null) + encoding.append(getAccessType()); + + if (!parameters.isEmpty()) { + encoding.append(SEMICOLON + SP + this.parameters.encode()); + } + // else if (getExtendAccessInfo() != null) // stack deve limitar, de + // acordo com a especificação ? + if (getExtensionAccessInfo() != null) { + encoding.append(SEMICOLON + SP + + getExtensionAccessInfo().toString()); + } + + return encoding.toString(); + + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value, 0); + + } + + + public boolean equals(Object other) { + return (other instanceof PAccessNetworkInfoHeader) && super.equals(other); + } + + /* + * Makes a deep clone. (ParametersHeader) + */ + public Object clone() { + PAccessNetworkInfo retval = (PAccessNetworkInfo) super.clone(); + return retval; + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfoHeader.java b/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfoHeader.java new file mode 100644 index 0000000..fca3fc3 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAccessNetworkInfoHeader.java @@ -0,0 +1,123 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ + +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + + +package gov.nist.javax.sip.header.ims; + + +import java.text.ParseException; +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + +/** + * <p>P-Access-Network-Info SIP P-Header </p> + * <p>This header carries information relating to the access network between + * the UAC and its serving proxy in the home network.</p> + * + * <p>IETF RFC3455 + 3GPP TS 24.229-720 (2005-12)</p> + * <p>Sintax: </p> + * <pre> + * P-Access-Network-Info = "P-Access-Network-Info": access-type *(; access-info) + * + * access-type = "IEEE-802.11a" / "IEEE-802.11b" / "3GPP-GERAN" / "3GPP-UTRAN-FDD" / + * "3GPP-UTRAN-TDD" / "ADSL" / "ADSL2" / "ADSL2+" / "RADSL" / "SDSL" / + * "HDSL" / "HDSL2" / "G.SHDSL" / "VDSL" / "IDSL" / "3GPP2-1X" / + * "3GPP2-1XHRPD" /token + * + * access-info = cgi-3gpp / utran-cell-id-3gpp / dsl-location / + * ci-3gpp2 / extension-access-info + * cgi-3gpp = "cgi-3gpp" EQUAL (token / quoted-string) + * utran-cell-id-3gpp = "utran-cell-id-3gpp" EQUAL (token / quoted-string) + * dsl-location = "dsl-location" EQUAL (token / quoted-string) + * ci-3gpp2 = "ci-3gpp2" EQUAL (token / quoted-string) + * extension-access-info = gen-value + * gen-value = token / host / quoted-string + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public interface PAccessNetworkInfoHeader extends Parameters, Header +{ + + public final static String NAME = "P-Access-Network-Info"; + + // access type + public static final String IEEE_802_11 = "IEEE-802.11"; + public static final String IEEE_802_11A = "IEEE-802.11a"; + public static final String IEEE_802_11B = "IEEE-802.11b"; + public static final String IEEE_802_11G = "IEEE-802.11g"; + public static final String GGGPP_GERAN = "3GPP-GERAN"; + public static final String GGGPP_UTRAN_FDD = "3GPP-UTRAN-FDD"; + public static final String GGGPP_UTRAN_TDD = "3GPP-UTRAN-TDD"; + public static final String GGGPP_CDMA2000 = "3GPP-CDMA2000"; + public static final String ADSL = "ADSL"; + public static final String ADSL2 = "ADSL2"; + public static final String ADSL2p = "ADSL2+"; + public static final String RADSL = "RADSL"; + public static final String SDSL = "SDSL"; + public static final String HDSL = "HDSL"; + public static final String HDSL2 = "HDSL2"; + public static final String GSHDSL = "G.SHDSL"; + public static final String VDSL = "VDSL"; + public static final String IDSL = "IDSL"; + public static final String GGGPP2_1X = "3GPP2-1X"; + public static final String GGGPP2_1XHRPD = "3GPP2-1XHRPD"; + + + + public void setAccessType(String accessTypeVal) throws ParseException; + public String getAccessType(); + + + public void setCGI3GPP(String cgi) throws ParseException; + public String getCGI3GPP(); + + + public void setUtranCellID3GPP(String utranCellID) throws ParseException; + public String getUtranCellID3GPP(); + + + public void setDSLLocation(String dslLocation) throws ParseException; + public String getDSLLocation(); + + + public void setCI3GPP2(String ci2Gpp2) throws ParseException; + public String getCI3GPP2(); + + + public void setExtensionAccessInfo(Object extendAccessInfo) throws ParseException; + public Object getExtensionAccessInfo(); + + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssertedIdentity.java b/java/gov/nist/javax/sip/header/ims/PAssertedIdentity.java new file mode 100644 index 0000000..6991247 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssertedIdentity.java @@ -0,0 +1,104 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.ims.PAssertedIdentityHeader; + +import gov.nist.javax.sip.header.AddressParametersHeader; + + +/** + * P-Asserted-Identity SIP Private Header. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class PAssertedIdentity + extends AddressParametersHeader + implements PAssertedIdentityHeader, SIPHeaderNamesIms, ExtensionHeader { + + + + /** + * constructor + * @param address address to set + */ + public PAssertedIdentity(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public PAssertedIdentity() + { + super(NAME); + } + + /** Encode into canonical form. + *@return String containing the canonicaly encoded header. + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + + if (!parameters.isEmpty()) + retval.append(COMMA + this.parameters.encode()); + return retval.toString(); + } + + + public Object clone() { + PAssertedIdentity retval = (PAssertedIdentity) super.clone(); + return retval; + } + + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssertedIdentityHeader.java b/java/gov/nist/javax/sip/header/ims/PAssertedIdentityHeader.java new file mode 100644 index 0000000..17e1042 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssertedIdentityHeader.java @@ -0,0 +1,64 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO- EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; + +/* + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +/** + * P-Asserted-Identity header + * Private Header: RFC 3455. + * Contains a URI (commonly a SIP URI) and an optional display-name + * enable a network of trusted SIP servers to assert + * the identity of authenticated users, and the application of existing + * privacy mechanisms to the identity problem. + * The use of this extension is only applicable inside an administrative + * domain with previously agreed-upon policies for generation, + * transport and usage of such information. + * + * + */ + + + +public interface PAssertedIdentityHeader extends HeaderAddress, Header { + + /** + * Name of AssertIdentityHeader + */ + public final static String NAME = "P-Asserted-Identity"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssertedIdentityList.java b/java/gov/nist/javax/sip/header/ims/PAssertedIdentityList.java new file mode 100644 index 0000000..a1a2221 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssertedIdentityList.java @@ -0,0 +1,66 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + + +import gov.nist.javax.sip.header.SIPHeaderList; + + +/** + * List of P-Asserted-Identity headers + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +/* + * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value + * *(COMMA PAssertedID-value) + * PAssertedID-value = name-addr / addr-spec + */ + + +public class PAssertedIdentityList extends SIPHeaderList<PAssertedIdentity> { + + private static final long serialVersionUID = -6465152445570308974L; + + + /** + * constructor. + */ + public PAssertedIdentityList() + { + super(PAssertedIdentity.class, PAssertedIdentityHeader.NAME); + } + + + public Object clone() { + PAssertedIdentityList retval = new PAssertedIdentityList(); + return retval.clonehlist(this.hlist); + } +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssertedService.java b/java/gov/nist/javax/sip/header/ims/PAssertedService.java new file mode 100644 index 0000000..2f8bea0 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssertedService.java @@ -0,0 +1,115 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import gov.nist.javax.sip.header.SIPHeader; +import javax.sip.header.ExtensionHeader; +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + */ +public class PAssertedService extends SIPHeader implements PAssertedServiceHeader, SIPHeaderNamesIms, ExtensionHeader{ + + private String subServiceIds; + private String subAppIds; + + protected PAssertedService(String name) { + super(NAME); + } + + public PAssertedService() + { + super(P_ASSERTED_SERVICE); + } + + @Override + protected String encodeBody() { + StringBuffer retval = new StringBuffer(); + + retval.append(ParameterNamesIms.SERVICE_ID); + + if(this.subServiceIds!=null) + { + retval.append(ParameterNamesIms.SERVICE_ID_LABEL).append("."); + + retval.append(this.getSubserviceIdentifiers()); + } + + else if(this.subAppIds!=null) + { + retval.append(ParameterNamesIms.APPLICATION_ID_LABEL).append("."); + retval.append(this.getApplicationIdentifiers()); + } + + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + public String getApplicationIdentifiers() { + if(this.subAppIds.charAt(0)=='.') + { + return this.subAppIds.substring(1); + } + return this.subAppIds; + } + + public String getSubserviceIdentifiers() { + if(this.subServiceIds.charAt(0)=='.') + { + return this.subServiceIds.substring(1); + } + return this.subServiceIds; + } + public void setApplicationIdentifiers(String appids) { + this.subAppIds = appids; + + } + + public void setSubserviceIdentifiers(String subservices) { + this.subServiceIds = subservices; + + } + + public boolean equals(Object other) + { + return (other instanceof PAssertedServiceHeader) && super.equals(other); + + } + + + public Object clone() { + PAssertedService retval = (PAssertedService) super.clone(); + return retval; + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssertedServiceHeader.java b/java/gov/nist/javax/sip/header/ims/PAssertedServiceHeader.java new file mode 100644 index 0000000..d99d2bf --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssertedServiceHeader.java @@ -0,0 +1,63 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import javax.sip.header.Header; +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * The ABNF for this header is all follows: + * + * PAssertedService = "P-Asserted-Service" + * HCOLON PAssertedService-value + * + * PAssertedService-value = Service-ID *(COMMA Service-ID) + * + * where, + * + * Service-ID = "urn:urn-7:" urn-service-id + * urn-service-id = top-level *("." sub-service-id) + * top-level = let-dig [ *26let-dig ] + * sub-service-id = let-dig [ *let-dig ] + * let-dig = ALPHA / DIGIT / "-" + * + * Egs: P-Asserted-Service: urn:urn-7:3gpp-service.exampletelephony.version1 + * P-Asserted-Service: urn:urn-7:3gpp-application.exampletelephony.version1 + * + */ +public interface PAssertedServiceHeader extends Header{ + + public static final String NAME = "P-Asserted-Service"; + + public void setSubserviceIdentifiers(String subservices); + + public String getSubserviceIdentifiers(); + + public void setApplicationIdentifiers(String appids); + + public String getApplicationIdentifiers(); +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssociatedURI.java b/java/gov/nist/javax/sip/header/ims/PAssociatedURI.java new file mode 100644 index 0000000..b621002 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssociatedURI.java @@ -0,0 +1,161 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/**************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) * + ****************************************************************************/ + +package gov.nist.javax.sip.header.ims; + + +import java.text.ParseException; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.GenericURI; +import javax.sip.address.URI; +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.header.ims.PAssociatedURIHeader; + + +/** + * <p>P-Associated-URI SIP Private Header. </p> + * <p>An associated URI is a URI that the service provider + * has allocated to a user for his own usage (address-of-record). </p> + * + * <p>sintax (RFC 3455): </p> + * <pre> + * P-Associated-URI = "P-Associated-URI" HCOLON + * (p-aso-uri-spec) *(COMMA p-aso-uri-spec) + * p-aso-uri-spec = name-addr *(SEMI ai-param) + * ai-param = generic-param + * name-addr = [display-name] angle-addr + * angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class PAssociatedURI + extends gov.nist.javax.sip.header.AddressParametersHeader + implements PAssociatedURIHeader, SIPHeaderNamesIms, ExtensionHeader +{ + // TODO: Need a unique UID + + + /** + * Default Constructor + */ + public PAssociatedURI() + { + super(PAssociatedURIHeader.NAME); + } + + /** + * Constructor + * @param address to be set in the header + */ + public PAssociatedURI(AddressImpl address) + { + super(PAssociatedURIHeader.NAME); + this.address = address; + } + + /** + * Constructor + * @param associatedURI - GenericURI to be set in the address of this header + */ + public PAssociatedURI(GenericURI associatedURI) + { + super(PAssociatedURIHeader.NAME); + this.address = new AddressImpl(); + this.address.setURI(associatedURI); + } + + + + + /** + * Encode into canonical form. + * @return String containing the canonicaly encoded header. + */ + public String encodeBody() + { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + return retval.toString(); + } + + + /** + * <p>Set the URI on this address</p> + * @param associatedURI - GenericURI to be set in the address of this header + * @throws NullPointerException when supplied URI is null + */ + public void setAssociatedURI(URI associatedURI) throws NullPointerException + { + if (associatedURI == null) + throw new NullPointerException("null URI"); + + this.address.setURI(associatedURI); + } + + /** + * <p>Get the address's URI</p> + * @return URI set in the address of this header + */ + public URI getAssociatedURI() { + return this.address.getURI(); + } + + + public Object clone() { + PAssociatedURI retval = (PAssociatedURI) super.clone(); + if (this.address != null) + retval.address = (AddressImpl) this.address.clone(); + return retval; + } + + + public void setValue(String value) throws ParseException{ + // not implemented + throw new ParseException(value,0); + + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssociatedURIHeader.java b/java/gov/nist/javax/sip/header/ims/PAssociatedURIHeader.java new file mode 100644 index 0000000..511d5ca --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssociatedURIHeader.java @@ -0,0 +1,90 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/**************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) * + ****************************************************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; +import javax.sip.address.URI; + + + +/** + * <p>P-Associated-URI SIP Private Header. </p> + * <p>An associated URI is a URI that the service provider + * has allocated to a user for his own usage (address-of-record). </p> + * + * <p>sintax (RFC 3455): </p> + * <pre> + * P-Associated-URI = "P-Associated-URI" HCOLON + * (p-aso-uri-spec) *(COMMA p-aso-uri-spec) + * p-aso-uri-spec = name-addr *(SEMI ai-param) + * ai-param = generic-param + * name-addr = [display-name] angle-addr + * angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +/* + + */ + + +public interface PAssociatedURIHeader + extends HeaderAddress, Parameters, Header +{ + + /** + * Name of PAssociatedURIHeader + */ + public final static String NAME = "P-Associated-URI"; + + + /** + * <p>Set the URI on this address</p> + * @param associatedURI - GenericURI to be set in the address of this header + * @throws NullPointerException when supplied URI is null + */ + public void setAssociatedURI(URI associatedURI) throws NullPointerException; + + /** + * <p>Get the address's URI</p> + * @return URI set in the address of this header + */ + public URI getAssociatedURI(); + + //public void setAssociatedURI(AddressImpl associatedURI); + //public AddressImpl getAssociatedURI(); + + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PAssociatedURIList.java b/java/gov/nist/javax/sip/header/ims/PAssociatedURIList.java new file mode 100644 index 0000000..4a2550e --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PAssociatedURIList.java @@ -0,0 +1,65 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + + +import gov.nist.javax.sip.header.SIPHeaderList; + + +/** + * List of P-Associated-URI headers + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +/* + * P-Associated-URI = "P-Associated-URI" ":" # ( "<" URI ">" *( ";" generic-param )) + */ + + +public class PAssociatedURIList extends SIPHeaderList<PAssociatedURI> { + + + private static final long serialVersionUID = 4454306052557362851L; + + + /** + * constructor. + */ + public PAssociatedURIList() + { + super(PAssociatedURI.class, PAssociatedURI.NAME); + } + + + public Object clone() { + PAssociatedURIList retval = new PAssociatedURIList(); + return retval.clonehlist(this.hlist); + } +} diff --git a/java/gov/nist/javax/sip/header/ims/PCalledPartyID.java b/java/gov/nist/javax/sip/header/ims/PCalledPartyID.java new file mode 100644 index 0000000..48ea4bb --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PCalledPartyID.java @@ -0,0 +1,91 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.ims.PCalledPartyIDHeader; + +/** + * P-Called-Party-ID SIP Private Header. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class PCalledPartyID + extends gov.nist.javax.sip.header.AddressParametersHeader + implements PCalledPartyIDHeader, SIPHeaderNamesIms , ExtensionHeader{ + + /** + * constructor + * @param address address to set + */ + public PCalledPartyID(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public PCalledPartyID() { + super(CALLED_PARTY_ID); + + } + + /** Encode into canonical form. + *@return String containing the canonicaly encoded header. + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + // not implemented. + throw new ParseException(value,0); + + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PCalledPartyIDHeader.java b/java/gov/nist/javax/sip/header/ims/PCalledPartyIDHeader.java new file mode 100644 index 0000000..9172d8b --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PCalledPartyIDHeader.java @@ -0,0 +1,67 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + + +/** + * P-Called-Party-ID header - Private Header: RFC 3455. + * <p>A proxy server inserts a P-Called-Party-ID header, typically in an INVITE request, + * en-route to its destination. The header is populated with the Request-URI received + * by the proxy in the request. </p> + * <p>Both the business SIP URI and the personal SIP URI are registered in the SIP registrar, + * so both URIs can receive invitations to new sessions. When the user receives an invitation + * to join a session, he/she should be aware of which of the several registered SIP URIs this + * session was sent to. </p> + * + * <pre> + * P-Called-Party-ID = "P-Called-Party-ID" HCOLON + * called-pty-id-spec + * called-pty-id-spec = name-addr *(SEMI cpid-param) + * cpid-param = generic-param + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + * + */ + + +public interface PCalledPartyIDHeader extends HeaderAddress, Parameters, Header { + + /** + * Name of CalledPartyIDHeader + */ + public final static String NAME = "P-Called-Party-ID"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddresses.java b/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddresses.java new file mode 100644 index 0000000..94570d4 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddresses.java @@ -0,0 +1,300 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import gov.nist.core.NameValue; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.header.ims.PChargingFunctionAddressesHeader; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; + + +/** + * <p>P-Charging-Function-Addresses SIP Private Header. </p> + * + * <p>Sintax (RFC 3455):</p> + * <pre> + * P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON + * charge-addr-params + * *(SEMI charge-addr-params) + * charge-addr-params = ccf / ecf / generic-param + * ccf = "ccf" EQUAL gen-value + * ecf = "ecf" EQUAL gen-value + * gen-value = token / host / quoted-string + * </pre> + * + * <p>example:</p> + * <p>P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2; + * ecf=192.1.1.3; ecf=192.1.1.4</p> + * + * <p>TODO: add PARSER support for IPv6 address. + * eg: P-Charging-Function-Addresses: ccf=[5555.b99.c88.d77.e66]; ecf=[5555.6aa.7bb.8cc.9dd] </p> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +public class PChargingFunctionAddresses + extends gov.nist.javax.sip.header.ParametersHeader + implements PChargingFunctionAddressesHeader, SIPHeaderNamesIms , ExtensionHeader{ + + + // TODO: serialVersionUID + + /** + * Defaul Constructor + */ + public PChargingFunctionAddresses() { + + super(P_CHARGING_FUNCTION_ADDRESSES); + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.header.ParametersHeader#encodeBody() + */ + protected String encodeBody() { + + StringBuffer encoding = new StringBuffer(); + + // issued by Miguel Freitas + if (!duplicates.isEmpty()) + { + encoding.append(duplicates.encode()); + } + + return encoding.toString(); + + } + + /** + * <p>Set the Charging Collection Function (CCF) Address</p> + * + * @param ccfAddress - the address to set in the CCF parameter + * @throws ParseException + */ + public void setChargingCollectionFunctionAddress(String ccfAddress) throws ParseException { + + if (ccfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null."); + + // setParameter(ParameterNamesIms.CCF, ccfAddress); + setMultiParameter(ParameterNamesIms.CCF, ccfAddress); + + } + + /** + * <p>Add another Charging Collection Function (CCF) Address to this header</p> + * + * @param ccfAddress - the address to set in the CCF parameter + * @throws ParseException + */ + public void addChargingCollectionFunctionAddress(String ccfAddress) throws ParseException { + + if (ccfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null."); + + this.parameters.set(ParameterNamesIms.CCF, ccfAddress); + + } + + /** + * <p>Remove a Charging Collection Function (CCF) Address set in this header</p> + * + * @param ccfAddress - the address in the CCF parameter to remove + * @throws ParseException if the address was not removed + */ + public void removeChargingCollectionFunctionAddress(String ccfAddress) throws ParseException { + + if (ccfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null."); + + if(!this.delete(ccfAddress, ParameterNamesIms.CCF)) { + + throw new ParseException("CCF Address Not Removed",0); + + } + + } + + /** + * <p>Get all the Charging Collection Function (CCF) Addresses set in this header</p> + * + * @return ListIterator that constains all CCF addresses of this header + */ + public ListIterator getChargingCollectionFunctionAddresses() { + + Iterator li = this.parameters.iterator(); + LinkedList ccfLIST = new LinkedList(); + NameValue nv; + while (li.hasNext()) { + nv = (NameValue) li.next(); + if (nv.getName().equalsIgnoreCase(ParameterNamesIms.CCF)) { + + NameValue ccfNV = new NameValue(); + + ccfNV.setName(nv.getName()); + ccfNV.setValueAsObject(nv.getValueAsObject()); + + ccfLIST.add(ccfNV); + + } + } + + return ccfLIST.listIterator(); + } + + /** + * <p>Set the Event Charging Function (ECF) Address</p> + * + * @param ecfAddress - the address to set in the ECF parameter + * @throws ParseException + */ + public void setEventChargingFunctionAddress(String ecfAddress) throws ParseException { + + if (ecfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null."); + + setMultiParameter(ParameterNamesIms.ECF, ecfAddress); + // setParameter(ParameterNamesIms.ECF, ecfAddress); + + } + + /** + * <p>Add another Event Charging Function (ECF) Address to this header</p> + * + * @param ecfAddress - the address to set in the ECF parameter + * @throws ParseException + */ + public void addEventChargingFunctionAddress(String ecfAddress) throws ParseException { + + if (ecfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null."); + + this.parameters.set(ParameterNamesIms.ECF, ecfAddress); + + } + + /** + * <p>Remove a Event Charging Function (ECF) Address set in this header</p> + * + * @param ecfAddress - the address in the ECF parameter to remove + * @throws ParseException if the address was not removed + */ + public void removeEventChargingFunctionAddress(String ecfAddress) throws ParseException { + + if (ecfAddress == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null."); + + if(!this.delete(ecfAddress, ParameterNamesIms.ECF)) { + + throw new java.text.ParseException("ECF Address Not Removed",0); + + } + + } + + /** + * <p>Get all the Event Charging Function (ECF) Addresses set in this header</p> + * + * @return ListIterator that constains all CCF addresses of this header + */ + public ListIterator<NameValue> getEventChargingFunctionAddresses() { + + LinkedList<NameValue> listw = new LinkedList<NameValue>(); + + Iterator li = this.parameters.iterator(); + ListIterator<NameValue> ecfLIST = listw.listIterator(); + NameValue nv; + boolean removed = false; + while (li.hasNext()) { + nv = (NameValue) li.next(); + if (nv.getName().equalsIgnoreCase(ParameterNamesIms.ECF)) { + + NameValue ecfNV = new NameValue(); + + ecfNV.setName(nv.getName()); + ecfNV.setValueAsObject(nv.getValueAsObject()); + + ecfLIST.add(ecfNV); + + } + } + + return ecfLIST; + } + + /** + * <p>Remove parameter </p> + * + * @param value - of the parameter + * @param name - of the parameter + * @return true if parameter was removed, and false if not + */ + public boolean delete(String value, String name) { + Iterator li = this.parameters.iterator(); + NameValue nv; + boolean removed = false; + while (li.hasNext()) { + nv = (NameValue) li.next(); + if (((String) nv.getValueAsObject()).equalsIgnoreCase(value) && nv.getName().equalsIgnoreCase(name)) { + li.remove(); + removed = true; + } + } + + return removed; + + } + + public void setValue(String value) throws ParseException { + throw new ParseException ( value,0); + + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddressesHeader.java b/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddressesHeader.java new file mode 100644 index 0000000..4924fca --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PChargingFunctionAddressesHeader.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import gov.nist.core.NameValue; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.ListIterator; + + +/** + * P-Charging-Function-Addresses header - + * Private Header: RFC 3455. + * + * There is a need to inform each SIP proxy involved in a transaction about the common + * charging functional entities to receive the generated charging records or charging events. + * <ul> + * <li> + * - CCF is used for off-line charging (e.g., for postpaid account charging). + * <li> + * - ECF is used for on-line charging (e.g., for pre-paid account charging). + * </ul> + * Only one instance of the header MUST be present in a particular request or response. + * + * <pre> + * P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON + * charge-addr-params + * *(SEMI charge-addr-params) + * charge-addr-params = ccf / ecf / generic-param + * ccf = "ccf" EQUAL gen-value + * ecf = "ecf" EQUAL gen-value + * + * gen-value = token / host / quoted-string + * + * host = hostname / IPv4address / IPv6reference + * hostname = *( domainlabel "." ) toplabel [ "." ] + * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum + * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum + * + * + * example: + * P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2; + * ecf=192.1.1.3; ecf=192.1.1.4 + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + + +public interface PChargingFunctionAddressesHeader extends Parameters, Header { + + /** + * Name of PChargingFunctionAddressesHeader + */ + public final static String NAME = "P-Charging-Function-Addresses"; + + + /** + * <p>Set the Charging Collection Function (CCF) Address</p> + * @param ccfAddress - the address to set in the CCF parameter + * @throws ParseException + */ + public void setChargingCollectionFunctionAddress(String ccfAddress) throws ParseException; + + /** + * <p>Add another Charging Collection Function (CCF) Address to this header</p> + * @param ccfAddress - the address to set in the CCF parameter + * @throws ParseException + */ + public void addChargingCollectionFunctionAddress(String ccfAddress) throws ParseException; + + /** + * <p>Remove a Charging Collection Function (CCF) Address set in this header</p> + * @param ccfAddress - the address in the CCF parameter to remove + * @throws ParseException if the address was not removed + */ + public void removeChargingCollectionFunctionAddress(String ccfAddress) throws ParseException; + + /** + * <p>Get all the Charging Collection Function (CCF) Addresses set in this header</p> + * @return ListIterator that constains all CCF addresses of this header + */ + public ListIterator getChargingCollectionFunctionAddresses(); + + /** + * <p>Set the Event Charging Function (ECF) Address</p> + * @param ecfAddress - the address to set in the ECF parameter + * @throws ParseException + */ + public void setEventChargingFunctionAddress(String ecfAddress)throws ParseException; + + /** + * <p>Add another Event Charging Function (ECF) Address to this header</p> + * @param ecfAddress - the address to set in the ECF parameter + * @throws ParseException + */ + public void addEventChargingFunctionAddress(String ecfAddress) throws ParseException; + + /** + * <p>Remove a Event Charging Function (ECF) Address set in this header</p> + * @param ecfAddress - the address in the ECF parameter to remove + * @throws ParseException if the address was not removed + */ + public void removeEventChargingFunctionAddress(String ecfAddress) throws ParseException; + + /** + * <p>Get all the Event Charging Function (ECF) Addresses set in this header</p> + * @return ListIterator that constains all CCF addresses of this header + */ + public ListIterator getEventChargingFunctionAddresses(); + +} diff --git a/java/gov/nist/javax/sip/header/ims/PChargingVector.java b/java/gov/nist/javax/sip/header/ims/PChargingVector.java new file mode 100644 index 0000000..069661e --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PChargingVector.java @@ -0,0 +1,226 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.header.ims.PChargingVectorHeader; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; + +/** + * P-Charging-Vector header SIP Private Header: RFC 3455. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public class PChargingVector extends gov.nist.javax.sip.header.ParametersHeader + implements PChargingVectorHeader, SIPHeaderNamesIms, ExtensionHeader { + + /** + * Default Constructor + */ + public PChargingVector() { + + super(P_CHARGING_VECTOR); + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.header.ParametersHeader#encodeBody() + */ + protected String encodeBody() { + + StringBuffer encoding = new StringBuffer(); + /* + * no need to check for the presence of icid-value. According to the + * spec above this is a mandatory field. if it does not exist, then we + * should throw an exception + * + * JvB 26/5: fix for issue #159, check for quotes around icid value + */ + gov.nist.core.NameValue nv = getNameValue( ParameterNamesIms.ICID_VALUE ); + nv.encode( encoding ); + + //the remaining parameters are optional. + // check for their presence, then add the parameter if it exists. + if (parameters.containsKey(ParameterNamesIms.ICID_GENERATED_AT)) + encoding.append(SEMICOLON).append( + ParameterNamesIms.ICID_GENERATED_AT).append(EQUALS).append( + getICIDGeneratedAt()); + + if (parameters.containsKey(ParameterNamesIms.TERM_IOI)) + + encoding.append(SEMICOLON).append(ParameterNamesIms.TERM_IOI) + .append(EQUALS).append(getTerminatingIOI()); + + if (parameters.containsKey(ParameterNamesIms.ORIG_IOI)) + + encoding.append(SEMICOLON).append(ParameterNamesIms.ORIG_IOI) + .append(EQUALS).append(getOriginatingIOI()); + + return encoding.toString(); + } + + /** + * <p> + * Get the icid-value parameter value + * </p> + * + * @return the value of the icid-value parameter + */ + public String getICID() { + + return getParameter(ParameterNamesIms.ICID_VALUE); + } + + /** + * <p> + * Set the icid-value parameter + * </p> + * + * @param icid - + * value to set in the icid-value parameter + * @throws ParseException + */ + public void setICID(String icid) throws ParseException { + + if (icid == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Vector, setICID(), the icid parameter is null."); + + setParameter(ParameterNamesIms.ICID_VALUE, icid); + + } + + /** + * <p> + * Get the icid-generated-at parameter value + * </p> + * + * @return the icid-generated-at parameter value + */ + public String getICIDGeneratedAt() { + + return getParameter(ParameterNamesIms.ICID_GENERATED_AT); + + } + + /** + * <p> + * Set the icid-generated-at parameter + * </p> + * + * @param host - + * value to set in the icid-generated-at parameter + * @throws ParseException + */ + public void setICIDGeneratedAt(String host) throws ParseException { + + if (host == null) + throw new NullPointerException( + "JAIN-SIP Exception, " + + "P-Charging-Vector, setICIDGeneratedAt(), the host parameter is null."); + + setParameter(ParameterNamesIms.ICID_GENERATED_AT, host); + + } + + /** + * <p> + * Get the orig-ioi parameter value + * </p> + * + * @return the orig-ioi parameter value + */ + public String getOriginatingIOI() { + + return getParameter(ParameterNamesIms.ORIG_IOI); + } + + /** + * <p> + * Set the orig-ioi parameter + * </p> + * + * @param origIOI - + * value to set in the orig-ioi parameter. If value is null or + * empty, the parameter is removed + * @throws ParseException + */ + public void setOriginatingIOI(String origIOI) throws ParseException { + + if (origIOI == null || origIOI.length() == 0) { + removeParameter(ParameterNamesIms.ORIG_IOI); + } else + setParameter(ParameterNamesIms.ORIG_IOI, origIOI); + + } + + /** + * <p> + * Get the term-ioi parameter value + * </p> + * + * @return the term-ioi parameter value + */ + public String getTerminatingIOI() { + + return getParameter(ParameterNamesIms.TERM_IOI); + } + + /** + * <p> + * Set the term-ioi parameter + * </p> + * + * @param termIOI - + * value to set in the term-ioi parameter. If value is null or + * empty, the parameter is removed + * @throws ParseException + */ + public void setTerminatingIOI(String termIOI) throws ParseException { + + if (termIOI == null || termIOI.length() == 0) { + removeParameter(ParameterNamesIms.TERM_IOI); + } else + setParameter(ParameterNamesIms.TERM_IOI, termIOI); + + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value, 0); + + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PChargingVectorHeader.java b/java/gov/nist/javax/sip/header/ims/PChargingVectorHeader.java new file mode 100644 index 0000000..446e7ee --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PChargingVectorHeader.java @@ -0,0 +1,167 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + + +import java.text.ParseException; +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + + + +/** + * <p>P-Charging-Vector header SIP Private Header. </p> + * + * <p> Sintax (RFC 3455): </p> + * <pre> + * P-Charging-Vector = "P-Charging-Vector" HCOLON icid-value (SEMI charge-params) + * charge-params = icid-gen-addr / orig-ioi / term-ioi / generic-param + * icid-value = "icid-value" EQUAL gen-value + * icid-gen-addr = "icid-generated-at" EQUAL host + * orig-ioi = "orig-ioi" EQUAL gen-value + * term-ioi = "term-ioi" EQUAL gen-value + * </pre> + * + * <p>Sintax from RFC3261: </p> + * <pre> + * generic-param = token [ EQUAL gen-value ] + * gen-value = token / host / quoted-string + * host = hostname / IPv4address / Ipv6reference + * </pre> + * + * + * <p> syntax as in 3GPP TS 24.229-720 (2005-12) : + * + * The access-network-charging-info parameter is an instance of generic-param + * from the current charge-params: </p> + * + * <pre> + * access-network-charging-info = (gprs-charging-info / i-wlan-charging-info / xdsl-charging-info / generic-param) + * gprs-charging-info = ggsn SEMI auth-token [SEMI pdp-info-hierarchy] *(SEMI extension-param) + * ggsn = "ggsn" EQUAL gen-value + * pdp-info-hierarchy = "pdp-info" EQUAL LDQUOT pdp-info *(COMMA pdp-info) RDQUOT + * pdp-info = pdp-item SEMI pdp-sig SEMI gcid [SEMI flow-id] + * pdp-item = "pdp-item" EQUAL DIGIT + * pdp-sig = "pdp-sig" EQUAL ("yes" / "no") + * gcid = "gcid" EQUAL 1*HEXDIG + * auth-token = "auth-token" EQUAL 1*HEXDIG + * flow-id = "flow-id" EQUAL "(" "{" 1*DIGIT COMMA 1*DIGIT "}" *(COMMA "{" 1*DIGIT COMMA 1*DIGIT"}")")" + * extension-param = token [EQUAL token] + * i-wlan-charging-info = "pdg" + * xdsl-charging-info = bras SEMI auth-token [SEMI xDSL-bearer-info] *(SEMI extension-param) + * bras = "bras" EQUAL gen-value + * xDSL-bearer-info = "dsl-bearer-info" EQUAL LDQUOT dsl-bearer-info *(COMMA dsl-bearer-info) RDQUOT + * dsl-bearer-info = dsl-bearer-item SEMI dsl-bearer-sig SEMI dslcid [SEMI flow-id] + * dsl-bearer-item = "dsl-bearer-item" EQUAL DIGIT + * dsl-bearer-sig = "dsl-bearer-sig" + * </pre> + * + * + * <p>example: + * P-Charging-Vector: icid-value=1234bc9876e; icid-generated-at=192.0.6.8; orig-ioi=home1.net </p> + * + * + * <p>TODO: gen-value can be token / host / quoted-string</p> + * <p>TODO: add suport for the new header extensions access-network-charging-info</p> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + + + +public interface PChargingVectorHeader extends Header, Parameters { + + /** + * Name of PChargingVectorHeader + */ + public final static String NAME = "P-Charging-Vector"; + + + /** + * @return -- icid value. + */ + public String getICID(); + + + /** + * @param icid + * @throws ParseException + */ + public void setICID(String icid) throws ParseException; + + /** + * @return -- the ICID generatedAt field. + */ + public String getICIDGeneratedAt(); + + + /** + * @param host -- set the icid host value. + * + * @throws ParseException -- if bad host value. + */ + public void setICIDGeneratedAt(String host) throws ParseException; + + + /** + * + * @return the originating IOI + */ + public String getOriginatingIOI(); + + + /** + * @param origIOI + * @throws ParseException + * + */ + public void setOriginatingIOI(String origIOI) throws ParseException; + + + /** + * @return -- the terminating IOI field + */ + public String getTerminatingIOI(); + + + /** + * @param termIOI -- the terminating IOI field to set. + * @throws ParseException + */ + public void setTerminatingIOI(String termIOI) throws ParseException; + + + + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PMediaAuthorization.java b/java/gov/nist/javax/sip/header/ims/PMediaAuthorization.java new file mode 100644 index 0000000..6ac82d1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PMediaAuthorization.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + +import java.text.ParseException; + +import gov.nist.javax.sip.header.SIPHeader; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.ExtensionHeader; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + + +/** + * P-Media-Authorization SIP Private Header - RFC 3313. + * + * <p>Sintax:</p> + * <pre> + * P-Media-Authorization = "P-Media-Authorization" HCOLON + * P-Media-Authorization-Token + * *(COMMA P-Media-Authorization-Token) + * P-Media-Authorization-Token = 1*HEXDIG + * </pre> + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public class PMediaAuthorization + extends SIPHeader + implements PMediaAuthorizationHeader, SIPHeaderNamesIms, ExtensionHeader +{ + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -6463630258703731133L; + + + /** + * P-Media-Authorization Token + */ + private String token; + + + /** + * Constructor + */ + public PMediaAuthorization() + { + super(P_MEDIA_AUTHORIZATION); + } + + + /** + * Get the media authorization token. + * + * @return token + */ + public String getToken() + { + return token; + } + + + /** + * Set the media authorization token. + * + * @param token - media authorization token to set + * @throws InvalidArgumentException - if token is null or empty + */ + public void setMediaAuthorizationToken(String token) throws InvalidArgumentException + { + if (token == null || token.length() == 0) + throw new InvalidArgumentException(" the Media-Authorization-Token parameter is null or empty"); + + this.token = token; + } + + /** + * Encode header + * @return the header content + */ + protected String encodeBody() + { + return token; + } + + + public void setValue(String value) throws ParseException { + throw new ParseException (value,0); + + } + + + public boolean equals(Object other) + { + if (other instanceof PMediaAuthorizationHeader) + { + final PMediaAuthorizationHeader o = (PMediaAuthorizationHeader) other; + return this.getToken().equals(o.getToken()); + } + return false; + + } + + + public Object clone() { + PMediaAuthorization retval = (PMediaAuthorization) super.clone(); + if (this.token != null) + retval.token = this.token; + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationHeader.java b/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationHeader.java new file mode 100644 index 0000000..7a4f763 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationHeader.java @@ -0,0 +1,73 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.Header; + + +/** + * The P-Media-Authorization SIP Private Header - RFC 3313. + * + * <p>Sintax:</p> + * <pre> + * P-Media-Authorization = "P-Media-Authorization" HCOLON + * P-Media-Authorization-Token + * *(COMMA P-Media-Authorization-Token) + * P-Media-Authorization-Token = 1*HEXDIG + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public interface PMediaAuthorizationHeader extends Header +{ + + /** + * Name of PMediaAuthorizationHeader + */ + public final static String NAME = "P-Media-Authorization"; + + /** + * Set the media authorization token. + * @param token - media authorization token to set + * @throws InvalidArgumentException - if token is null or empty + */ + public void setMediaAuthorizationToken(String token) throws InvalidArgumentException; + + /** + * Get the media authorization token. + * @return token + */ + public String getToken(); + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationList.java b/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationList.java new file mode 100644 index 0000000..13dc5cf --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PMediaAuthorizationList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + +import gov.nist.javax.sip.header.SIPHeaderList; + +/** + * List of P-Media-Authorization headers. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public class PMediaAuthorizationList extends SIPHeaderList<PMediaAuthorization> { + private static final long serialVersionUID = -8226328073989632317L; + + + public PMediaAuthorizationList() + { + super(PMediaAuthorization.class, PMediaAuthorizationHeader.NAME); + } + + + public Object clone() { + PMediaAuthorizationList retval = new PMediaAuthorizationList(); + return retval.clonehlist(this.hlist); + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PPreferredIdentity.java b/java/gov/nist/javax/sip/header/ims/PPreferredIdentity.java new file mode 100644 index 0000000..3b9ab13 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PPreferredIdentity.java @@ -0,0 +1,94 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.address.AddressImpl; + +import gov.nist.javax.sip.header.AddressParametersHeader; + + + + +/** + * P-Preferred-Identity SIP Private Header - RFC 3325. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + + +public class PPreferredIdentity + extends AddressParametersHeader + implements PPreferredIdentityHeader, SIPHeaderNamesIms , ExtensionHeader { + + /** + * constructor + * @param address address to set + */ + public PPreferredIdentity(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public PPreferredIdentity() { + super(P_PREFERRED_IDENTITY); + } + + /** Encode into canonical form. + * @return String containing the canonicaly encoded header. + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException (value,0); + + } + +} + diff --git a/java/gov/nist/javax/sip/header/ims/PPreferredIdentityHeader.java b/java/gov/nist/javax/sip/header/ims/PPreferredIdentityHeader.java new file mode 100644 index 0000000..17389ec --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PPreferredIdentityHeader.java @@ -0,0 +1,67 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; + +/** + * P-Preferred-Identity header - + * SIP Private Header: RFC 3325 + * + * <ul> + * <li> + * . is used from a user agent to a trusted proxy to carry the identity the + * user sending the SIP message wishes to be used for the P-Asserted-Header + * field value that the trusted element will insert. + * <li> + * . If there are two values, one value MUST be a sip or sips URI and the other + * MUST be a tel URI. + * </ul> + * + * <p>Sintax: </p> + * <pre> + * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value + * *(COMMA PPreferredID-value) + * PPreferredID-value = name-addr / addr-spec + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +public interface PPreferredIdentityHeader extends HeaderAddress, Header { + + /** + * Name of PreferredIdentityHeader + */ + public final static String NAME = "P-Preferred-Identity"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/PPreferredService.java b/java/gov/nist/javax/sip/header/ims/PPreferredService.java new file mode 100644 index 0000000..4a56407 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PPreferredService.java @@ -0,0 +1,115 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import javax.sip.header.ExtensionHeader; +import gov.nist.javax.sip.header.SIPHeader; +/** + * + * @author aayush.bhatnagar + * + */ +public class PPreferredService extends SIPHeader implements PPreferredServiceHeader, SIPHeaderNamesIms, ExtensionHeader{ + + private String subServiceIds; + private String subAppIds; + + protected PPreferredService(String name) { + super(NAME); + } + + public PPreferredService() + { + super(P_PREFERRED_SERVICE); + } + + @Override + protected String encodeBody() { + StringBuffer retval = new StringBuffer(); + + retval.append(ParameterNamesIms.SERVICE_ID); + + if(this.subServiceIds!=null) + { + retval.append(ParameterNamesIms.SERVICE_ID_LABEL).append("."); + + retval.append(this.getSubserviceIdentifiers()); + + } + + else if(this.subAppIds!=null) + { + retval.append(ParameterNamesIms.APPLICATION_ID_LABEL).append("."); + retval.append(this.getApplicationIdentifiers()); + } + + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + public String getApplicationIdentifiers() { + if(this.subAppIds.charAt(0)=='.') + { + return this.subAppIds.substring(1); + } + return this.subAppIds; + } + + public String getSubserviceIdentifiers() { + if(this.subServiceIds.charAt(0)=='.') + { + return this.subServiceIds.substring(1); + } + return this.subServiceIds; + } + + public void setApplicationIdentifiers(String appids) { + this.subAppIds = appids; + + } + + public void setSubserviceIdentifiers(String subservices) { + this.subServiceIds = ".".concat(subservices); + + } + + public boolean equals(Object other) + { + return (other instanceof PPreferredServiceHeader) && super.equals(other); + + } + + + public Object clone() { + PPreferredService retval = (PPreferredService) super.clone(); + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PPreferredServiceHeader.java b/java/gov/nist/javax/sip/header/ims/PPreferredServiceHeader.java new file mode 100644 index 0000000..75ff548 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PPreferredServiceHeader.java @@ -0,0 +1,65 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import javax.sip.header.Header; + +/** + * + * @author aayush.bhatnagar + * + * The ABNF for this header is all follows: + * + * PPreferredService = "P-Preferred-Service" + * HCOLON PPreferredService-value + * + * PPreferredService-value = Service-ID *(COMMA Service-ID) + * + * where, + * + * Service-ID = "urn:urn-7:" urn-service-id + * urn-service-id = top-level *("." sub-service-id) + * top-level = let-dig [ *26let-dig ] + * sub-service-id = let-dig [ *let-dig ] + * let-dig = ALPHA / DIGIT / "-" + * + * Egs: P-Preferred-Service: urn:urn-7:3gpp-service.exampletelephony.version1 + * P-Preferred-Service: urn:urn-7:3gpp-application.exampletelephony.version1 + * + */ +public interface PPreferredServiceHeader extends Header{ + + public static final String NAME = "P-Preferred-Service"; + + public void setSubserviceIdentifiers(String subservices); + + public String getSubserviceIdentifiers(); + + public void setApplicationIdentifiers(String appids); + + public String getApplicationIdentifiers(); + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PProfileKey.java b/java/gov/nist/javax/sip/header/ims/PProfileKey.java new file mode 100644 index 0000000..8c08060 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PProfileKey.java @@ -0,0 +1,87 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.AddressParametersHeader; +import javax.sip.header.ExtensionHeader; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + */ +public class PProfileKey extends AddressParametersHeader implements PProfileKeyHeader, SIPHeaderNamesIms , ExtensionHeader { + + public PProfileKey( ) { + super(P_PROFILE_KEY); + + } + + public PProfileKey(AddressImpl address) + { + super(NAME); + this.address = address; + } + + @Override + protected String encodeBody() { + + StringBuffer retval = new StringBuffer(); + + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + public boolean equals(Object other) + { + return (other instanceof PProfileKey) && super.equals(other); + + } + + + public Object clone() { + PProfileKey retval = (PProfileKey) super.clone(); + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PProfileKeyHeader.java b/java/gov/nist/javax/sip/header/ims/PProfileKeyHeader.java new file mode 100644 index 0000000..a5453fa --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PProfileKeyHeader.java @@ -0,0 +1,46 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * The ABNF syntax of this header is as follows: + * P-Profile-Key = "P-Profile-Key" HCOLON {name-addr / addr-spec} + * *{ SEMI generic-param } + * + * Eg: P-Profile-Key: <sip:chatroom-!.*!@example.com> + * + */ +public interface PProfileKeyHeader extends HeaderAddress, Header{ + + public final static String NAME = "P-Profile-Key"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/PServedUser.java b/java/gov/nist/javax/sip/header/ims/PServedUser.java new file mode 100644 index 0000000..e951bcf --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PServedUser.java @@ -0,0 +1,164 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import javax.sip.header.ExtensionHeader; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.AddressParametersHeader; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * This is the class used for encoding of the P-Served-User header + * + * + */ +public class PServedUser extends AddressParametersHeader implements PServedUserHeader, SIPHeaderNamesIms, ExtensionHeader{ + + + public PServedUser(AddressImpl address) + { + super(P_SERVED_USER); + this.address = address; + } + + public PServedUser() + { + super(NAME); + } + + public String getRegistrationState() { + + return getParameter(ParameterNamesIms.REGISTRATION_STATE); + } + + public String getSessionCase() { + + return getParameter(ParameterNamesIms.SESSION_CASE); + } + + public void setRegistrationState(String registrationState) { + + if((registrationState!=null)) + { + if(registrationState.equals("reg")||registrationState.equals("unreg")) + { + try { + setParameter(ParameterNamesIms.REGISTRATION_STATE, registrationState); + } catch (ParseException e) { + e.printStackTrace(); + } + + } + else + { + try { + throw new InvalidArgumentException("Value can be either reg or unreg"); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + } + + } + else + { + throw new NullPointerException("regstate Parameter value is null"); + } + + } + + public void setSessionCase(String sessionCase) { + + if((sessionCase!=null)) + { + if((sessionCase.equals("orig"))||(sessionCase.equals("term"))) + { + try { + setParameter(ParameterNamesIms.SESSION_CASE, sessionCase); + } catch (ParseException e) { + e.printStackTrace(); + } + } + else + { + try { + throw new InvalidArgumentException("Value can be either orig or term"); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + + } + } + else + { + throw new NullPointerException("sess-case Parameter value is null"); + } + + } + + @Override + protected String encodeBody() { + + StringBuffer retval = new StringBuffer(); + + retval.append(address.encode()); + + if(parameters.containsKey(ParameterNamesIms.REGISTRATION_STATE)) + retval.append(SEMICOLON).append(ParameterNamesIms.REGISTRATION_STATE).append(EQUALS) + .append(this.getRegistrationState()); + + if(parameters.containsKey(ParameterNamesIms.SESSION_CASE)) + retval.append(SEMICOLON).append(ParameterNamesIms.SESSION_CASE).append(EQUALS) + .append(this.getSessionCase()); + + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + public boolean equals(Object other) + { + if(other instanceof PServedUser) + { + final PServedUserHeader psu = (PServedUserHeader)other; + return this.getAddress().equals(((PServedUser) other).getAddress()); + } + return false; + } + + + public Object clone() { + PServedUser retval = (PServedUser) super.clone(); + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PServedUserHeader.java b/java/gov/nist/javax/sip/header/ims/PServedUserHeader.java new file mode 100644 index 0000000..0bd2505 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PServedUserHeader.java @@ -0,0 +1,61 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * The ABNF of the P-Served-User Header is as follows: + * + * P-Served-User = "P-Served-User" HCOLON PServedUser-value + * *(SEMI served-user-param) + * served-user-param = sessioncase-param + * / registration-state-param + * / generic-param + * PServedUser-value = name-addr / addr-spec + * sessioncase-param = "sescase" EQUAL "orig" / "term" + * registration-state-param = "regstate" EQUAL "unreg" / "reg" + * + * Eg: P-Served-User: <sip:aayush@rancore.com>; sescase=orig; regstate=reg + * + * + */ +public interface PServedUserHeader { + + public static final String NAME = "P-Served-User"; + + public void setSessionCase(String sessionCase); + + public String getSessionCase(); + + public void setRegistrationState(String registrationState); + + public String getRegistrationState(); + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PUserDatabase.java b/java/gov/nist/javax/sip/header/ims/PUserDatabase.java new file mode 100644 index 0000000..83d3b10 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PUserDatabase.java @@ -0,0 +1,107 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import javax.sip.header.ExtensionHeader; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + */ +public class PUserDatabase extends gov.nist.javax.sip.header.ParametersHeader implements PUserDatabaseHeader,SIPHeaderNamesIms, ExtensionHeader{ + + private String databaseName; + + /** + * + * @param databaseName + */ + public PUserDatabase(String databaseName) + { + super(NAME); + this.databaseName = databaseName; + } + + /** + * Default constructor. + */ + public PUserDatabase() { + super(P_USER_DATABASE); + } + + public String getDatabaseName() { + + return this.databaseName; + } + + + public void setDatabaseName(String databaseName) { + if((databaseName==null)||(databaseName.equals(" "))) + throw new NullPointerException("Database name is null"); + else + if(!databaseName.contains("aaa://")) + this.databaseName = new StringBuffer().append("aaa://").append(databaseName).toString(); + else + this.databaseName = databaseName; + + } + + protected String encodeBody() { + + StringBuffer retval = new StringBuffer(); + retval.append("<"); + if(getDatabaseName()!=null) + retval.append(getDatabaseName()); + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + retval.append(">"); + + return retval.toString(); + } + + public boolean equals(Object other) + { + return (other instanceof PUserDatabaseHeader) && super.equals(other); + + } + + + public Object clone() { + PUserDatabase retval = (PUserDatabase) super.clone(); + return retval; + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PUserDatabaseHeader.java b/java/gov/nist/javax/sip/header/ims/PUserDatabaseHeader.java new file mode 100644 index 0000000..0f7c887 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PUserDatabaseHeader.java @@ -0,0 +1,58 @@ +package gov.nist.javax.sip.header.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import javax.sip.header.Header; +import javax.sip.header.Parameters; +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * This is the interface that exposes the behavior + * of the P-User-Database header. We only have one + * major value for this header, as per RFC 4457. + * This value is the Database name. The DB here refers + * to the IMS HSS. The DB name is encoded as a URI, delimited + * by the < and > signs. There may be generic parameters for + * this header encoded as URI parameters. They also lie between + * the < and > delimiters. However, this URI is neither a SIP URI + * nor a TEL URI. It is a DIAMETER AAA URI.The value of this AAA URI + * is consumed by the S-CSCF. The S-CSCF can cache the value of the + * HSS received in this header,thus optimizing the IMS registration + * process. + * + */ +public interface PUserDatabaseHeader extends Parameters,Header +{ + public final static String NAME = "P-User-Database"; + + public String getDatabaseName(); + + public void setDatabaseName(String name); + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PVisitedNetworkID.java b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkID.java new file mode 100644 index 0000000..2f65db0 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkID.java @@ -0,0 +1,164 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; +import javax.sip.header.Parameters; + +import gov.nist.core.Token; + +/** + * P-Visited-Network-ID SIP Private Header: RFC 3455. + * + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + + +public class PVisitedNetworkID + extends gov.nist.javax.sip.header.ParametersHeader + implements PVisitedNetworkIDHeader, SIPHeaderNamesIms, ExtensionHeader { + + /** + * visited Network ID + */ + private String networkID; + + // issued by Miguel Freitas + private boolean isQuoted; + + + public PVisitedNetworkID() { + + super(P_VISITED_NETWORK_ID); + + } + + public PVisitedNetworkID(String networkID) { + + super(P_VISITED_NETWORK_ID); + setVisitedNetworkID(networkID); + + } + + public PVisitedNetworkID(Token tok) { + + super(P_VISITED_NETWORK_ID); + setVisitedNetworkID(tok.getTokenValue()); + + } + + protected String encodeBody() { + + StringBuffer retval = new StringBuffer(); + + if (getVisitedNetworkID() != null) + { + // issued by Miguel Freitas + if (isQuoted) + retval.append(DOUBLE_QUOTE + getVisitedNetworkID() + DOUBLE_QUOTE); + else + retval.append(getVisitedNetworkID()); + } + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + + return retval.toString(); + + } + + /** + * Set the visited network ID as a string. The value will be quoted in the header. + * @param networkID - string value + */ + public void setVisitedNetworkID(String networkID) { + if (networkID == null) + throw new NullPointerException(" the networkID parameter is null"); + + this.networkID = networkID; + + // issued by Miguel Freitas + this.isQuoted = true; + } + + /** + * Set the visited network ID as a token + * @param networkID - token value + */ + public void setVisitedNetworkID(Token networkID) { + if (networkID == null) + throw new NullPointerException(" the networkID parameter is null"); + + this.networkID = networkID.getTokenValue(); + + // issued by Miguel Freitas + this.isQuoted = false; + } + + /** + * Get the visited network ID value of this header + */ + public String getVisitedNetworkID() { + return networkID; + } + + + public void setValue(String value) throws ParseException { + throw new ParseException (value,0); + + } + + + public boolean equals(Object other) + { + if (other instanceof PVisitedNetworkIDHeader) + { + PVisitedNetworkIDHeader o = (PVisitedNetworkIDHeader) other; + return (this.getVisitedNetworkID().equals( o.getVisitedNetworkID() ) + && this.equalParameters( (Parameters) o )); + } + return false; + } + + + public Object clone() { + PVisitedNetworkID retval = (PVisitedNetworkID) super.clone(); + if (this.networkID != null) + retval.networkID = this.networkID; + retval.isQuoted = this.isQuoted; + return retval; + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDHeader.java b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDHeader.java new file mode 100644 index 0000000..2d3cf7f --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDHeader.java @@ -0,0 +1,107 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import gov.nist.core.Token; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + + +/** + * P-Visited-Network-ID SIP Private Header: RFC 3455. + * + * <ul> + * <li> + * . One of the conditions for a home network to accept the registration of a UA roaming to a + * particular visited network, is the existence of a roaming agreement between the home and + * the visited network. There is a need to indicate to the home network which one is the visited + * network that is providing services to the roaming UA. + * <li> + * . user agents always register to the home network. The REGISTER request is proxied by + * one or more proxies located in the visited network towards the home network + * <li> + * . the visited network includes an identification that is known at the home network + * <li> + * . This identification should be globally unique, and takes the form of a quoted text string or a token + * <li> + * . In case a REGISTER or other request is traversing different administrative domains + * (e.g., different visited networks), a SIP proxy MAY insert a NEW P-Visited-Network-ID header + * if the request does not contain a P-Visited-Network-ID header with the same network + * identifier as its own network identifier + * </ul> + * + * <p>Sintax: </p> + * + * <pre> + * P-Visited-Network-ID = "P-Visited-Network-ID" HCOLON + * vnetwork-spec + * *(COMMA vnetwork-spec) + * vnetwork-spec = (token / quoted-string) + * *(SEMI vnetwork-param) + * vnetwork-param = generic-param + * + * + * eg: P-Visited-Network-ID: other.net, "Visited network number 1" + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + + + +public interface PVisitedNetworkIDHeader extends Parameters, Header { + + /** + * Name of VisitedNetworkIDHeader + */ + public final static String NAME = "P-Visited-Network-ID"; + + + /** + * Set the visited network ID as a string. The value will be quoted in the header. + * @param networkID - string value + */ + public void setVisitedNetworkID(String networkID); + + /** + * Set the visited network ID as a token + * @param networkID - token value + */ + public void setVisitedNetworkID(Token networkID); + + /** + * Get the visited network ID value of this header + */ + public String getVisitedNetworkID(); + +} diff --git a/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDList.java b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDList.java new file mode 100644 index 0000000..2f58199 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDList.java @@ -0,0 +1,56 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.ims.PVisitedNetworkIDHeader; + +/** + * List of P-Visited-Network-ID headers. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class PVisitedNetworkIDList extends SIPHeaderList<PVisitedNetworkID> { + + private static final long serialVersionUID = -4346667490341752478L; + + /** Default constructor + */ + public PVisitedNetworkIDList() { + super(PVisitedNetworkID.class, PVisitedNetworkIDHeader.NAME); + } + + public Object clone() { + PVisitedNetworkIDList retval = new PVisitedNetworkIDList(); + return retval.clonehlist(this.hlist); + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/ParameterNamesIms.java b/java/gov/nist/javax/sip/header/ims/ParameterNamesIms.java new file mode 100644 index 0000000..1772471 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/ParameterNamesIms.java @@ -0,0 +1,91 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ +package gov.nist.javax.sip.header.ims; + +import gov.nist.javax.sip.address.ParameterNames; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ +public interface ParameterNamesIms extends ParameterNames { + + public static final String IK = "ik"; + public static final String CK = "ck"; + public static final String INTEGRITY_PROTECTED = "integrity-protected"; + public static final String CCF = "ccf"; + public static final String ECF = "ecf"; + public static final String ICID_VALUE = "icid-value"; + public static final String ICID_GENERATED_AT = "icid-generated-at"; + public static final String ORIG_IOI = "orig-ioi"; + public static final String TERM_IOI = "term-ioi"; + + // issued by Miguel Freitas // + // P-Access-Network-ID + public static final String CGI_3GPP = "cgi-3gpp"; + public static final String UTRAN_CELL_ID_3GPP = "utran-cell-id-3gpp"; + public static final String DSL_LOCATION = "dsl-location"; + public static final String CI_3GPP2 = "ci-3gpp2"; + // P-Charging-Vector + public static final String GGSN = "ggsn"; + public static final String PDP_INFO = "pdp-info"; + public static final String PDP_ITEM = "pdp-item"; + public static final String PDP_SIG = "pdp-sig"; + public static final String GCID = "gcid"; + public static final String AUTH_TOKEN = "auth-token"; + public static final String FLOW_ID = "flow-id"; + public static final String PDG = "pdg"; + public static final String BRAS = "bras"; + public static final String DSL_BEARER_INFO = "dsl-bearer-info"; + public static final String DSL_BEARER_ITEM = "dsl-bearer-item"; + public static final String DSL_BEARER_SIG = "dsl-bearer-sig"; + + // sec-agree (Security-Server, Security-Client, Security-Verify) + public static final String ALG = "alg"; + public static final String EALG = "ealg"; + public static final String Q = "q"; + public static final String PROT = "prot"; + public static final String MOD = "mod"; + public static final String SPI_C = "spi-c"; + public static final String SPI_S = "spi-s"; + public static final String PORT_C = "port-c"; + public static final String PORT_S = "port-s"; + public static final String D_VER = "d-ver"; + // end // + + //added by aayush.bhatnagar(Ref: RFC 5502) + public static final String SESSION_CASE = "sescase"; + public static final String REGISTRATION_STATE = "regstate"; + + //added by aayush.bhatnagar(Ref: draft-drage-sipping-service-identification-03) + public static final String SERVICE_ID = "urn:urn-7:"; + public static final String SERVICE_ID_LABEL = "3gpp-service"; + public static final String APPLICATION_ID_LABEL = "3gpp-application"; + + +} diff --git a/java/gov/nist/javax/sip/header/ims/Path.java b/java/gov/nist/javax/sip/header/ims/Path.java new file mode 100644 index 0000000..ce6ce1f --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/Path.java @@ -0,0 +1,89 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.ims.PathHeader; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class Path + extends gov.nist.javax.sip.header.AddressParametersHeader + implements PathHeader, SIPHeaderNamesIms , ExtensionHeader{ + + /** + * constructor + * @param address address to set + */ + public Path(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public Path() + { + // issued by Miguel Freitas + super(NAME); + + } + + /** Encode into canonical form. + *@return String containing the canonicaly encoded header. + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/PathHeader.java b/java/gov/nist/javax/sip/header/ims/PathHeader.java new file mode 100644 index 0000000..f643a0d --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PathHeader.java @@ -0,0 +1,57 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + +/* + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +/** + * PATH header SIP param: RFC 3327. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + * + */ + + + +public interface PathHeader extends HeaderAddress, Parameters, Header { + + /** + * Name of PathHeader + */ + public final static String NAME = "Path"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/PathList.java b/java/gov/nist/javax/sip/header/ims/PathList.java new file mode 100644 index 0000000..b39bb5f --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PathList.java @@ -0,0 +1,51 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ +package gov.nist.javax.sip.header.ims; + +import gov.nist.javax.sip.header.SIPHeaderList; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class PathList extends SIPHeaderList<Path> { + + /** Default constructor + */ + public PathList() { + super(Path.class, PathHeader.NAME); + } + + + public Object clone() { + PathList retval = new PathList(); + return retval.clonehlist(this.hlist); + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/Privacy.java b/java/gov/nist/javax/sip/header/ims/Privacy.java new file mode 100644 index 0000000..7b291fd --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/Privacy.java @@ -0,0 +1,149 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + + + + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; +import javax.sip.header.Parameters; + +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.header.SIPHeader; + +/** + * Privacy SIP header - RFC 3323. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class Privacy + extends SIPHeader + implements PrivacyHeader, SIPHeaderNamesIms, ExtensionHeader +{ + + /** + * Privacy type + */ + private String privacy; + + + /** + * Default constructor. + */ + public Privacy() { + super(PRIVACY); + } + + /** + * Constructor given a privacy type + *@param privacy + */ + public Privacy(String privacy) + { + this(); + this.privacy = privacy; + + } + + + /** + * Encode into a canonical string. + * @return String. + */ + public String encodeBody() + { + return this.privacy; + } + + + + /** + * Get privacy type + * @return privacy type + */ + public String getPrivacy() + { + return privacy; + } + + + + /** + * set the privacy type. + * @param privacy -- privacy type to set. + */ + + public void setPrivacy(String privacy) throws ParseException + { + + if (privacy == null || privacy == "") + throw new NullPointerException( + "JAIN-SIP Exception, " + + " Privacy, setPrivacy(), privacy value is null or empty"); + this.privacy = privacy; + + } + + /** + * Suppress direct setting of values. + * + */ + public void setValue(String value) throws ParseException { + throw new ParseException(value,0); + + } + + + public boolean equals(Object other) + { + if (other instanceof PrivacyHeader) + { + PrivacyHeader o = (PrivacyHeader) other; + return (this.getPrivacy().equals( o.getPrivacy() )); + } + return false; + + } + + + public Object clone() { + Privacy retval = (Privacy) super.clone(); + if (this.privacy != null) + retval.privacy = this.privacy; + return retval; + } + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/PrivacyHeader.java b/java/gov/nist/javax/sip/header/ims/PrivacyHeader.java new file mode 100644 index 0000000..6486cab --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PrivacyHeader.java @@ -0,0 +1,79 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +import java.text.ParseException; + +import javax.sip.header.Header; +import javax.sip.header.Parameters; + +/** + * Privacy Header RFC 3323. + * + * <p>Sintax: </p> + *<pre> + * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value) + * priv-value = "header" / "session" / "user" / + * "id" / "none" / "critical" / token + * example: + * Privacy: id + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public interface PrivacyHeader extends Header +{ + + /** + * Name of PrivacyHeader + */ + public final static String NAME = "Privacy"; + + + /** + * Set Privacy header value + * @param privacy -- privacy type to set. + */ + public void setPrivacy(String privacy) throws ParseException; + + /** + * Get Privacy header value + * @return privacy token name + */ + public String getPrivacy(); + + +} + diff --git a/java/gov/nist/javax/sip/header/ims/PrivacyList.java b/java/gov/nist/javax/sip/header/ims/PrivacyList.java new file mode 100644 index 0000000..bdb7414 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/PrivacyList.java @@ -0,0 +1,64 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/***************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) * + *****************************************************************************/ + +package gov.nist.javax.sip.header.ims; + + +import gov.nist.javax.sip.header.SIPHeaderList; + + +/** + * List of Privacy headers. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class PrivacyList extends SIPHeaderList<Privacy> { + + private static final long serialVersionUID = 1798720509806307461L; + + + /** + * Default constructor + */ + public PrivacyList() { + super(Privacy.class, PrivacyHeader.NAME); + } + + + public Object clone() { + PrivacyList retval = new PrivacyList(); + return retval.clonehlist(this.hlist); + } + + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/SIPHeaderNamesIms.java b/java/gov/nist/javax/sip/header/ims/SIPHeaderNamesIms.java new file mode 100644 index 0000000..0282395 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SIPHeaderNamesIms.java @@ -0,0 +1,72 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public interface SIPHeaderNamesIms + extends gov.nist.javax.sip.header.SIPHeaderNames { + + public static final String PATH = PathHeader.NAME; + public static final String SERVICE_ROUTE = ServiceRouteHeader.NAME; + public static final String P_ASSERTED_IDENTITY = PAssertedIdentityHeader.NAME; + public static final String P_PREFERRED_IDENTITY = PPreferredIdentityHeader.NAME; + public static final String CALLED_PARTY_ID = PCalledPartyIDHeader.NAME; + public static final String P_VISITED_NETWORK_ID = PVisitedNetworkIDHeader.NAME; + public static final String P_CHARGING_FUNCTION_ADDRESSES = PChargingFunctionAddressesHeader.NAME; + public static final String P_CHARGING_VECTOR = PChargingVectorHeader.NAME; + + + // issued by Miguel Freitas + public static final String PRIVACY = PrivacyHeader.NAME; + public static final String P_ASSOCIATED_URI = PAssociatedURIHeader.NAME; + public static final String P_MEDIA_AUTHORIZATION = PMediaAuthorizationHeader.NAME; + public static final String P_ACCESS_NETWORK_INFO = PAccessNetworkInfoHeader.NAME; + public static final String SECURITY_SERVER = SecurityServerHeader.NAME; + public static final String SECURITY_CLIENT = SecurityClientHeader.NAME; + public static final String SECURITY_VERIFY = SecurityVerifyHeader.NAME; + + //added by aayush + public static final String P_USER_DATABASE = PUserDatabaseHeader.NAME; + //added by aayush + public static final String P_PROFILE_KEY = PProfileKeyHeader.NAME; + //added by aayush + public static final String P_SERVED_USER = PServedUserHeader.NAME; + //added by aayush + public static final String P_PREFERRED_SERVICE = PPreferredServiceHeader.NAME; + //added by aayush + public static final String P_ASSERTED_SERVICE = PAssertedServiceHeader.NAME; + + +} + diff --git a/java/gov/nist/javax/sip/header/ims/SecurityAgree.java b/java/gov/nist/javax/sip/header/ims/SecurityAgree.java new file mode 100644 index 0000000..6c172c8 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityAgree.java @@ -0,0 +1,369 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + +package gov.nist.javax.sip.header.ims; + + + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import javax.sip.header.Parameters; + +import gov.nist.core.NameValue; +import gov.nist.core.Separators; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; +import gov.nist.javax.sip.header.ParametersHeader; + + +/** + * "Security Mechanism Agreemet for SIP Sessions" + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p>Headers: Security-Server + Security-Client + Security-Verify</p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public abstract class SecurityAgree + extends ParametersHeader +{ + //TODO serialVersionUID + //private static final long serialVersionUID = -6671234553927258745L; + + //public static final String EALG = ParameterNamesIms.EALG; + // ... + + /** + * Security Mechanism value + */ + private String secMechanism; + + + /** + * Constructor + * @param name - name of the Security Agree header to create + */ + public SecurityAgree(String name) + { + super(name); + parameters.setSeparator(Separators.SEMICOLON); + } + + /** + * Default constructor + */ + public SecurityAgree() + { + super(); + parameters.setSeparator(Separators.SEMICOLON); + } + + + public void setParameter(String name, String value) throws ParseException + { + if (value == null) + throw new NullPointerException("null value"); + + NameValue nv = super.parameters.getNameValue(name.toLowerCase()); + if (nv == null) + { + nv = new NameValue(name, value); + + // quoted values + if (name.equalsIgnoreCase(ParameterNamesIms.D_VER)) + { + nv.setQuotedValue(); + + if (value.startsWith(Separators.DOUBLE_QUOTE)) + throw new ParseException(value + + " : Unexpected DOUBLE_QUOTE", 0); + } + + super.setParameter(nv); + } + else + { + nv.setValueAsObject(value); + } + + } + + public String encodeBody() + { + return this.secMechanism + SEMICOLON + SP + parameters.encode(); + } + + + + /** + * Set security mechanism. + * <p>eg: Security-Client: ipsec-3gpp</p> + * @param secMech - security mechanism name + */ + public void setSecurityMechanism(String secMech) throws ParseException { + if (secMech == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SecurityAgree, setSecurityMechanism(), the sec-mechanism parameter is null"); + this.secMechanism = secMech; + } + + /** + * Set Encryption Algorithm (ealg parameter) + * @param ealg - encryption algorithm value + * @throws ParseException + */ + public void setEncryptionAlgorithm(String ealg) throws ParseException { + if (ealg == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SecurityClient, setEncryptionAlgorithm(), the encryption-algorithm parameter is null"); + + setParameter(ParameterNamesIms.EALG, ealg); + } + + /** + * Set Algorithm (alg parameter) + * @param alg - algorithm value + * @throws ParseException + */ + public void setAlgorithm(String alg) throws ParseException { + if (alg == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SecurityClient, setAlgorithm(), the algorithm parameter is null"); + setParameter(ParameterNamesIms.ALG, alg); + } + + /** + * Set Protocol (prot paramater) + * @param prot - protocol value + * @throws ParseException + */ + public void setProtocol(String prot) throws ParseException { + if (prot == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SecurityClient, setProtocol(), the protocol parameter is null"); + setParameter(ParameterNamesIms.PROT, prot); + } + + /** + * Set Mode (mod parameter) + * @param mod - mode value + * @throws ParseException + */ + public void setMode(String mod) throws ParseException { + if (mod == null) + throw new NullPointerException( + "JAIN-SIP " + + "Exception, SecurityClient, setMode(), the mode parameter is null"); + setParameter(ParameterNamesIms.MOD, mod); + } + + /** + * Set Client SPI (spi-c parameter) + * @param spic - spi-c value + * @throws InvalidArgumentException + */ + public void setSPIClient(int spic) throws InvalidArgumentException { + if (spic < 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SecurityClient, setSPIClient(), the spi-c parameter is <0"); + setParameter(ParameterNamesIms.SPI_C, spic); + } + + /** + * Set Server SPI (spi-s parameter) + * @param spis - spi-s value + * @throws InvalidArgumentException - when value is not valid + */ + public void setSPIServer(int spis) throws InvalidArgumentException { + if (spis < 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SecurityClient, setSPIServer(), the spi-s parameter is <0"); + setParameter(ParameterNamesIms.SPI_S, spis); + } + + /** + * Set Client Port (port-c parameter) + * @param portC - port-c value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPortClient(int portC) throws InvalidArgumentException { + if (portC < 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SecurityClient, setPortClient(), the port-c parameter is <0"); + setParameter(ParameterNamesIms.PORT_C, portC); + } + + /** + * Set Server Port (port-s parameter) + * @param portS - port-s value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPortServer(int portS) throws InvalidArgumentException { + if (portS < 0) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SecurityClient, setPortServer(), the port-s parameter is <0"); + setParameter(ParameterNamesIms.PORT_S, portS); + } + + /** + * <p>Set Preference. + * The "q" parameter indicates a relative preference for the particular mechanism. + * The higher the value the more preferred the mechanism is. + * Range from 0.001 to 0.999.</p> + * @param q - q parameter value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPreference(float q) throws InvalidArgumentException { + if (q < 0.0f) + throw new InvalidArgumentException( + "JAIN-SIP " + + "Exception, SecurityClient, setPreference(), the preference (q) parameter is <0"); + setParameter(ParameterNamesIms.Q, q); + } + + + + // get param + + /** + * Get Security Mechanism + * @return security mechanims value + */ + public String getSecurityMechanism() { + return this.secMechanism; + } + /** + * Get Encryption Algorithm + * @return ealg parameter value + */ + public String getEncryptionAlgorithm() { + return getParameter(ParameterNamesIms.EALG); + } + + /** + * Get Algorithm + * @return alg parameter value + */ + public String getAlgorithm() { + return getParameter(ParameterNamesIms.ALG); + } + + /** + * Get Protocol + * @return prot parameter value + */ + public String getProtocol() { + return getParameter(ParameterNamesIms.PROT); + } + + /** + * Get Mode + * @return mod parameter value + */ + public String getMode() { + return getParameter(ParameterNamesIms.MOD); + + } + /** + * Get Client SPI + * @return spi-c parameter value + */ + public int getSPIClient() { + return (Integer.parseInt(getParameter(ParameterNamesIms.SPI_C))); + } + + /** + * Get Server SPI + * @return spi-s parameter value + */ + public int getSPIServer() { + return (Integer.parseInt(getParameter(ParameterNamesIms.SPI_S))); + } + + /** + * Get Client Port + * @return port-c parameter value + */ + public int getPortClient() { + return (Integer.parseInt(getParameter(ParameterNamesIms.PORT_C))); + } + + /** + * Get Server Port + * @return port-s parameter value + */ + public int getPortServer() { + return (Integer.parseInt(getParameter(ParameterNamesIms.PORT_S))); + } + + /** + * Get Preference + * @return q parameter value + */ + public float getPreference() { + return (Float.parseFloat(getParameter(ParameterNamesIms.Q))); + } + + + public boolean equals(Object other) + { + + if(other instanceof SecurityAgreeHeader) + { + SecurityAgreeHeader o = (SecurityAgreeHeader) other; + return (this.getSecurityMechanism().equals( o.getSecurityMechanism() ) + && this.equalParameters( (Parameters) o )); + } + return false; + + } + + + public Object clone() { + SecurityAgree retval = (SecurityAgree) super.clone(); + if (this.secMechanism != null) + retval.secMechanism = this.secMechanism; + return retval; + } + + +} + + diff --git a/java/gov/nist/javax/sip/header/ims/SecurityAgreeHeader.java b/java/gov/nist/javax/sip/header/ims/SecurityAgreeHeader.java new file mode 100644 index 0000000..6876d95 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityAgreeHeader.java @@ -0,0 +1,185 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + +/** + * "Security Mechanism Agreemet for SIP Sessions" + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p>Headers: Security-Server + Security-Client + Security-Verify</p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public interface SecurityAgreeHeader extends Parameters, Header +{ + + /** + * Set security mechanism. + * <p>eg: Security-Client: ipsec-3gpp</p> + * @param secMech - security mechanism name + */ + public void setSecurityMechanism(String secMech) throws ParseException; + + /** + * Set Encryption Algorithm (ealg parameter) + * @param ealg - encryption algorithm value + * @throws ParseException + */ + public void setEncryptionAlgorithm(String ealg) throws ParseException; + + /** + * Set Algorithm (alg parameter) + * @param alg - algorithm value + * @throws ParseException + */ + public void setAlgorithm(String alg) throws ParseException; + + /** + * Set Protocol (prot paramater) + * @param prot - protocol value + * @throws ParseException + */ + public void setProtocol(String prot) throws ParseException; + + /** + * Set Mode (mod parameter) + * @param mod - mode value + * @throws ParseException + */ + public void setMode(String mod) throws ParseException; + + /** + * Set Client SPI (spi-c parameter) + * @param spic - spi-c value + * @throws InvalidArgumentException + */ + public void setSPIClient(int spic) throws InvalidArgumentException; + + /** + * Set Server SPI (spi-s parameter) + * @param spis - spi-s value + * @throws InvalidArgumentException - when value is not valid + */ + public void setSPIServer(int spis) throws InvalidArgumentException; + + /** + * Set Client Port (port-c parameter) + * @param portC - port-c value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPortClient(int portC) throws InvalidArgumentException; + + + /** + * Set Server Port (port-s parameter) + * @param portS - port-s value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPortServer(int portS) throws InvalidArgumentException; + + /** + * Set Preference + * @param q - q parameter value + * @throws InvalidArgumentException - when value is not valid + */ + public void setPreference(float q) throws InvalidArgumentException; + + + + /** + * Get Security Mechanism + * @return security mechanims value + */ + public String getSecurityMechanism(); + + /** + * Get Encryption Algorithm + * @return ealg parameter value + */ + public String getEncryptionAlgorithm(); + + /** + * Get Algorithm + * @return alg parameter value + */ + public String getAlgorithm(); + + /** + * Get Protocol + * @return prot parameter value + */ + public String getProtocol(); + + /** + * Get Mode + * @return mod parameter value + */ + public String getMode(); + + /** + * Get Client SPI + * @return spi-c parameter value + */ + public int getSPIClient(); + + /** + * Get Server SPI + * @return spi-s parameter value + */ + public int getSPIServer(); + + /** + * Get Client Port + * @return port-c parameter value + */ + public int getPortClient(); + + /** + * Get Server Port + * @return port-s parameter value + */ + public int getPortServer(); + + /** + * Get Preference + * @return q parameter value + */ + public float getPreference(); + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityClient.java b/java/gov/nist/javax/sip/header/ims/SecurityClient.java new file mode 100644 index 0000000..58880a9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityClient.java @@ -0,0 +1,74 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + +package gov.nist.javax.sip.header.ims; + + + +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.ExtensionHeader; + + +/** + * Security-Client header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class SecurityClient + extends SecurityAgree + implements SecurityClientHeader, ExtensionHeader +{ + + // TODO serialVersionUID + + public SecurityClient() + { + super(SecurityClientHeader.NAME); + + } + + + public void setValue(String value) throws ParseException + { + throw new ParseException(value,0); + } + +} + + + diff --git a/java/gov/nist/javax/sip/header/ims/SecurityClientHeader.java b/java/gov/nist/javax/sip/header/ims/SecurityClientHeader.java new file mode 100644 index 0000000..83d8cbb --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityClientHeader.java @@ -0,0 +1,50 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +/** + * Security-Client header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public interface SecurityClientHeader extends SecurityServerHeader +{ + /** + * Name of SecurityClientHeader + */ + public final static String NAME = "Security-Client"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityClientList.java b/java/gov/nist/javax/sip/header/ims/SecurityClientList.java new file mode 100644 index 0000000..40a745e --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityClientList.java @@ -0,0 +1,68 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.ims.SecurityClient; + + +/** + * List of Security-Client headers. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class SecurityClientList extends SIPHeaderList<SecurityClient> +{ + + + private static final long serialVersionUID = 3094231003329176217L; + + + public SecurityClientList() + { + super(SecurityClient.class, SecurityClientHeader.NAME); + } + + + public Object clone() { + SecurityClientList retval = new SecurityClientList(); + return retval.clonehlist(this.hlist); + } + +} + + diff --git a/java/gov/nist/javax/sip/header/ims/SecurityServer.java b/java/gov/nist/javax/sip/header/ims/SecurityServer.java new file mode 100644 index 0000000..ed73237 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityServer.java @@ -0,0 +1,72 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +import java.text.ParseException; +import javax.sip.header.ExtensionHeader; + + +/** + * Security-Server header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class SecurityServer + extends SecurityAgree + implements SecurityServerHeader, ExtensionHeader +{ + + // TODO serialVersionUID + + public SecurityServer() + { + super(SecurityServerHeader.NAME); + + } + + + public void setValue(String value) throws ParseException + { + throw new ParseException(value,0); + } + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityServerHeader.java b/java/gov/nist/javax/sip/header/ims/SecurityServerHeader.java new file mode 100644 index 0000000..93556ca --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityServerHeader.java @@ -0,0 +1,58 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; +import javax.sip.header.Header; +import javax.sip.header.Parameters; + + +/** + * Security-Server header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public interface SecurityServerHeader extends SecurityAgreeHeader +{ + /** + * Name of SecurityServerHeader + */ + public final static String NAME = "Security-Server"; + + + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityServerList.java b/java/gov/nist/javax/sip/header/ims/SecurityServerList.java new file mode 100644 index 0000000..1590c74 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityServerList.java @@ -0,0 +1,67 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + +package gov.nist.javax.sip.header.ims; + + + +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.ims.SecurityServer; + + +/** + * List of Security-Server headers. + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class SecurityServerList extends SIPHeaderList<SecurityServer> +{ + + + private static final long serialVersionUID = -1392066520803180238L; + + public SecurityServerList() + { + super(SecurityServer.class, SecurityServerHeader.NAME); + } + + public Object clone() { + SecurityServerList retval = new SecurityServerList(); + return retval.clonehlist(this.hlist); + } + +} + + diff --git a/java/gov/nist/javax/sip/header/ims/SecurityVerify.java b/java/gov/nist/javax/sip/header/ims/SecurityVerify.java new file mode 100644 index 0000000..51252c9 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityVerify.java @@ -0,0 +1,72 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + + +/** + * Security-Verify header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class SecurityVerify + extends SecurityAgree + implements SecurityVerifyHeader, ExtensionHeader +{ + + // TODO serialVersionUID + + public SecurityVerify() + { + super(SecurityVerifyHeader.NAME); + + } + + + public void setValue(String value) throws ParseException + { + throw new ParseException(value,0); + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityVerifyHeader.java b/java/gov/nist/javax/sip/header/ims/SecurityVerifyHeader.java new file mode 100644 index 0000000..33636e0 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityVerifyHeader.java @@ -0,0 +1,51 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement. +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + +/** + * Security-Verify header + * - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H). + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + + +public interface SecurityVerifyHeader extends SecurityAgreeHeader +{ + /** + * Name of SecurityVerifyHeader + */ + public final static String NAME = "Security-Verify"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/SecurityVerifyList.java b/java/gov/nist/javax/sip/header/ims/SecurityVerifyList.java new file mode 100644 index 0000000..2685749 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/SecurityVerifyList.java @@ -0,0 +1,70 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government, +* and others. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.header.ims; + + + +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.ims.SecurityVerify; + + +/** + * List of Security-Verify headers. + * + * <p></p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + + +public class SecurityVerifyList extends SIPHeaderList<SecurityVerify> +{ + + + private static final long serialVersionUID = 563201040577795125L; + + public SecurityVerifyList() + { + super(SecurityVerify.class, SecurityVerifyHeader.NAME); + } + + public Object clone() { + SecurityVerifyList retval = new SecurityVerifyList(); + return retval.clonehlist(this.hlist); + } + + +} + + diff --git a/java/gov/nist/javax/sip/header/ims/ServiceRoute.java b/java/gov/nist/javax/sip/header/ims/ServiceRoute.java new file mode 100644 index 0000000..bb77bfa --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/ServiceRoute.java @@ -0,0 +1,91 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; + +import javax.sip.header.ExtensionHeader; + +import gov.nist.javax.sip.address.AddressImpl; + + + +/** + * SERVICE-ROUTE header SIP param: RFC 3608. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + + +public class ServiceRoute + extends gov.nist.javax.sip.header.AddressParametersHeader + implements ServiceRouteHeader, SIPHeaderNamesIms, ExtensionHeader { + + /** + * constructor + * @param address address to set + */ + public ServiceRoute(AddressImpl address) { + super(NAME); + this.address = address; + } + + /** + * default constructor + */ + public ServiceRoute() { + super(SERVICE_ROUTE); + } + + /** Encode into canonical form. + *@return String containing the canonicaly encoded header. + */ + public String encodeBody() { + StringBuffer retval = new StringBuffer(); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(LESS_THAN); + } + retval.append(address.encode()); + if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) { + retval.append(GREATER_THAN); + } + + if (!parameters.isEmpty()) + retval.append(SEMICOLON + this.parameters.encode()); + return retval.toString(); + } + + public void setValue(String value) throws ParseException { + throw new ParseException (value,0); + + } + + +} diff --git a/java/gov/nist/javax/sip/header/ims/ServiceRouteHeader.java b/java/gov/nist/javax/sip/header/ims/ServiceRouteHeader.java new file mode 100644 index 0000000..5dfc1c1 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/ServiceRouteHeader.java @@ -0,0 +1,50 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ +package gov.nist.javax.sip.header.ims; + +import javax.sip.header.Header; +import javax.sip.header.HeaderAddress; +import javax.sip.header.Parameters; + + +/** + * SERVICE-ROUTE header SIP param: RFC 3608. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +public interface ServiceRouteHeader extends HeaderAddress, Parameters, Header { + + /** + * Name of ServiceRouteHeader + */ + public final static String NAME = "Service-Route"; + +} diff --git a/java/gov/nist/javax/sip/header/ims/ServiceRouteList.java b/java/gov/nist/javax/sip/header/ims/ServiceRouteList.java new file mode 100644 index 0000000..b224775 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/ServiceRouteList.java @@ -0,0 +1,53 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ +package gov.nist.javax.sip.header.ims; + +import gov.nist.javax.sip.header.SIPHeaderList; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + +public class ServiceRouteList extends SIPHeaderList<ServiceRoute> { + + + private static final long serialVersionUID = -4264811439080938519L; + + /** Default constructor + */ + public ServiceRouteList() { + super(ServiceRoute.class, ServiceRouteHeader.NAME); + } + + public Object clone() { + ServiceRouteList retval = new ServiceRouteList(); + return retval.clonehlist(this.hlist); + } + +} diff --git a/java/gov/nist/javax/sip/header/ims/WWWAuthenticateHeaderIms.java b/java/gov/nist/javax/sip/header/ims/WWWAuthenticateHeaderIms.java new file mode 100644 index 0000000..8a3ee36 --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/WWWAuthenticateHeaderIms.java @@ -0,0 +1,71 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.header.ims; + +import java.text.ParseException; +import javax.sip.header.WWWAuthenticateHeader; + + + +/** + * Extension to WWW-authenticate header (3GPP TS 24229-5d0). + * + * <p>Defines a new authentication parameter (auth-param) for the WWW-Authenticate header + * used in a 401 (Unauthorized) response to the REGISTER request. + * For more information, see RFC 2617 [21] subclause 3.2.1.</p> + * + * <pre> + * auth-param = 1#( integrity-key / cipher-key ) + * integrity-key = "ik" EQUAL ik-value + * cipher-key = "ck" EQUAL ck-value + * ik-value = LDQUOT *(HEXDIG) RDQUOT + * ck-value = LDQUOT *(HEXDIG) RDQUOT + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401 + */ + + +public interface WWWAuthenticateHeaderIms extends WWWAuthenticateHeader +{ + // issued by Miguel Freitas + public static final String IK = ParameterNamesIms.IK; + public static final String CK = ParameterNamesIms.CK; + + + public void setIK(String ik) throws ParseException; + + public String getIK(); + + public void setCK(String ck) throws ParseException; + + public String getCK(); + +} diff --git a/java/gov/nist/javax/sip/header/ims/package.html b/java/gov/nist/javax/sip/header/ims/package.html new file mode 100644 index 0000000..0bdb21d --- /dev/null +++ b/java/gov/nist/javax/sip/header/ims/package.html @@ -0,0 +1,10 @@ +<body> +NIST-SIP Specific support for IMS headers contributed by Jose Miguel +Freitas (Aveiro University, Portugal) and Alexandre Miguel Silva +Santos (PT Inovacau, Portugal). It is not part of the JAIN-SIP 1.2 +specification. Questions about the IMS Support in NIST-SIP 1.2 can be +directed to Miguel Feitas <a23875@gmail.com> or the NIST-SIP mailing +list. To acccess these headers you have to cast the HeaderFactory to +HeaderFactoryImpl. This package has been contributed to the public +domain. +</body> diff --git a/java/gov/nist/javax/sip/header/package.html b/java/gov/nist/javax/sip/header/package.html new file mode 100644 index 0000000..7595449 --- /dev/null +++ b/java/gov/nist/javax/sip/header/package.html @@ -0,0 +1,7 @@ + +<body> + +Contains implementations of the SIP headers as defined in JAIN-SIP 1.2 and +an implementation of the JAIN-SIP header factory. + +</body> diff --git a/java/gov/nist/javax/sip/message/Content.java b/java/gov/nist/javax/sip/message/Content.java new file mode 100644 index 0000000..e3cfc0c --- /dev/null +++ b/java/gov/nist/javax/sip/message/Content.java @@ -0,0 +1,24 @@ +package gov.nist.javax.sip.message; + +import javax.sip.header.ContentDispositionHeader; +import javax.sip.header.ContentTypeHeader; + +public interface Content { + + public abstract void setContent(Object content); + + public abstract Object getContent(); + + public abstract ContentTypeHeader getContentTypeHeader(); + + public abstract ContentDispositionHeader getContentDispositionHeader(); + + /** + * The default packing method. This packs the content to be appended to the + * sip message. + * + */ + public abstract String toString(); + + +} diff --git a/java/gov/nist/javax/sip/message/ContentImpl.java b/java/gov/nist/javax/sip/message/ContentImpl.java new file mode 100644 index 0000000..fb1224d --- /dev/null +++ b/java/gov/nist/javax/sip/message/ContentImpl.java @@ -0,0 +1,102 @@ +package gov.nist.javax.sip.message; + +import java.text.ParseException; + +import javax.sip.header.ContentDispositionHeader; +import javax.sip.header.ContentTypeHeader; + +public class ContentImpl implements Content { + + + /* + * The content type header for this chunk of content. + */ + + private Object content; + + private String boundary; + + private ContentTypeHeader contentTypeHeader; + + private ContentDispositionHeader contentDispositionHeader; + + + + public ContentImpl( String content, String boundary ) { + this.content = content; + + this.boundary = boundary; + } + + + + /* (non-Javadoc) + * @see gov.nist.javax.sip.message.ContentExt#setContent(java.lang.String) + */ + public void setContent(Object content) { + this.content = content; + } + + /* (non-Javadoc) + * @see gov.nist.javax.sip.message.ContentExt#getContentTypeHeader() + */ + public ContentTypeHeader getContentTypeHeader() { + return contentTypeHeader; + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.message.Content#getContent() + */ + public Object getContent() { + return this.content; + } + + + /* (non-Javadoc) + * @see gov.nist.javax.sip.message.ContentExt#toString() + */ + public String toString() { + // This is not part of a multipart message. + if (boundary == null) { + return content.toString(); + } else { + if ( this.contentDispositionHeader != null ) { + return "--" + boundary + "\r\n" + getContentTypeHeader() + + this.getContentDispositionHeader().toString() + "\r\n" + + content.toString(); + } else { + return "--" + boundary + "\r\n" + getContentTypeHeader() + "\r\n" + content.toString(); + } + } + } + + + + /** + * @param contentDispositionHeader the contentDispositionHeader to set + */ + public void setContentDispositionHeader(ContentDispositionHeader contentDispositionHeader) { + this.contentDispositionHeader = contentDispositionHeader; + } + + + + /** + * @return the contentDispositionHeader + */ + public ContentDispositionHeader getContentDispositionHeader() { + return contentDispositionHeader; + } + + + + /** + * @param contentTypeHeader the contentTypeHeader to set + */ + public void setContentTypeHeader(ContentTypeHeader contentTypeHeader) { + this.contentTypeHeader = contentTypeHeader; + } + + +} diff --git a/java/gov/nist/javax/sip/message/HeaderIterator.java b/java/gov/nist/javax/sip/message/HeaderIterator.java new file mode 100644 index 0000000..58db98c --- /dev/null +++ b/java/gov/nist/javax/sip/message/HeaderIterator.java @@ -0,0 +1,99 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.message; + +import gov.nist.javax.sip.header.*; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * Iterator over lists of headers. Allows for uniform removal handling for singleton headers. + * @author M. Ranganathan + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:53 $ + * @since 1.1 + */ +public class HeaderIterator implements ListIterator { + private boolean toRemove; + private int index; + private SIPMessage sipMessage; + private SIPHeader sipHeader; + + protected HeaderIterator(SIPMessage sipMessage, SIPHeader sipHeader) { + this.sipMessage = sipMessage; + this.sipHeader = sipHeader; + } + + public Object next() throws NoSuchElementException { + if (sipHeader == null || index == 1) + throw new NoSuchElementException(); + toRemove = true; + index = 1; + return (Object) sipHeader; + } + + public Object previous() throws NoSuchElementException { + if (sipHeader == null || index == 0) + throw new NoSuchElementException(); + toRemove = true; + index = 0; + return (Object) sipHeader; + } + + public int nextIndex() { + return 1; + } + + public int previousIndex() { + return index == 0 ? -1 : 0; + } + + public void set(Object header) { + throw new UnsupportedOperationException(); + } + + public void add(Object header) { + throw new UnsupportedOperationException(); + } + + public void remove() throws IllegalStateException { + if (this.sipHeader == null) + throw new IllegalStateException(); + if (toRemove) { + this.sipHeader = null; + this.sipMessage.removeHeader(sipHeader.getName()); + } else { + throw new IllegalStateException(); + } + } + + public boolean hasNext() { + return index == 0; + } + + public boolean hasPrevious() { + return index == 1; + } +} diff --git a/java/gov/nist/javax/sip/message/ListMap.java b/java/gov/nist/javax/sip/message/ListMap.java new file mode 100644 index 0000000..1e4bcce --- /dev/null +++ b/java/gov/nist/javax/sip/message/ListMap.java @@ -0,0 +1,187 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + *******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.ims.*; +import java.util.Hashtable; + +/** + * A map of which of the standard headers may appear as a list + * + * @version 1.2 $Revision: 1.14 $ $Date: 2009/07/17 18:57:53 $ + * @since 1.1 + */ +class ListMap { + // A table that indicates whether a header has a list representation or + // not (to catch adding of the non-list form when a list exists.) + // Entries in this table allow you to look up the list form of a header + // (provided it has a list form). Note that under JAVA-5 we have + // typed collections which would render such a list obsolete. However, + // we are not using java 5. + private static Hashtable<Class<?>,Class<?>> headerListTable; + + private static boolean initialized; + static { + initializeListMap(); + } + + static private void initializeListMap() { + /* + * Build a table mapping between objects that have a list form and the + * class of such objects. + */ + headerListTable = new Hashtable<Class<?>, Class<?>>(); + headerListTable.put(ExtensionHeaderImpl.class, ExtensionHeaderList.class); + + headerListTable.put(Contact.class, ContactList.class); + + headerListTable.put(ContentEncoding.class, ContentEncodingList.class); + + headerListTable.put(Via.class, ViaList.class); + + headerListTable.put(WWWAuthenticate.class, WWWAuthenticateList.class); + + headerListTable.put(Accept.class, AcceptList.class); + + headerListTable.put(AcceptEncoding.class, AcceptEncodingList.class); + + headerListTable.put(AcceptLanguage.class, AcceptLanguageList.class); + + headerListTable.put(ProxyRequire.class, ProxyRequireList.class); + + headerListTable.put(Route.class, RouteList.class); + + headerListTable.put(Require.class, RequireList.class); + + headerListTable.put(Warning.class, WarningList.class); + + headerListTable.put(Unsupported.class, UnsupportedList.class); + + headerListTable.put(AlertInfo.class, AlertInfoList.class); + + headerListTable.put(CallInfo.class, CallInfoList.class); + + headerListTable.put(ProxyAuthenticate.class,ProxyAuthenticateList.class); + + headerListTable.put(ProxyAuthorization.class, ProxyAuthorizationList.class); + + headerListTable.put(Authorization.class, AuthorizationList.class); + + headerListTable.put(Allow.class, AllowList.class); + + headerListTable.put(RecordRoute.class, RecordRouteList.class); + + headerListTable.put(ContentLanguage.class, ContentLanguageList.class); + + headerListTable.put(ErrorInfo.class, ErrorInfoList.class); + + headerListTable.put(Supported.class, SupportedList.class); + + headerListTable.put(InReplyTo.class,InReplyToList.class); + + // IMS headers. + + headerListTable.put(PAssociatedURI.class, PAssociatedURIList.class); + + headerListTable.put(PMediaAuthorization.class, PMediaAuthorizationList.class); + + headerListTable.put(Path.class, PathList.class); + + headerListTable.put(Privacy.class,PrivacyList.class); + + headerListTable.put(ServiceRoute.class, ServiceRouteList.class); + + headerListTable.put(PVisitedNetworkID.class, PVisitedNetworkIDList.class); + + headerListTable.put(SecurityClient.class, SecurityClientList.class); + + headerListTable.put(SecurityServer.class, SecurityServerList.class); + + headerListTable.put(SecurityVerify.class, SecurityVerifyList.class); + + headerListTable.put(PAssertedIdentity.class, PAssertedIdentityList.class); + + initialized = true; + + } + + /** + * return true if this has an associated list object. + */ + static protected boolean hasList(SIPHeader sipHeader) { + if (sipHeader instanceof SIPHeaderList) + return false; + else { + Class<?> headerClass = sipHeader.getClass(); + return headerListTable.get(headerClass) != null; + } + } + + /** + * Return true if this has an associated list object. + */ + static protected boolean hasList(Class<?> sipHdrClass) { + if (!initialized) + initializeListMap(); + return headerListTable.get(sipHdrClass) != null; + } + + /** + * Get the associated list class. + */ + static protected Class<?> getListClass(Class<?> sipHdrClass) { + if (!initialized) + initializeListMap(); + return (Class<?>) headerListTable.get(sipHdrClass); + } + + /** + * Return a list object for this header if it has an associated list object. + */ + @SuppressWarnings("unchecked") + static protected SIPHeaderList<SIPHeader> getList(SIPHeader sipHeader) { + if (!initialized) + initializeListMap(); + try { + Class<?> headerClass = sipHeader.getClass(); + Class<?> listClass = headerListTable.get(headerClass); + SIPHeaderList<SIPHeader> shl = (SIPHeaderList<SIPHeader>) listClass.newInstance(); + shl.setHeaderName(sipHeader.getName()); + return shl; + } catch (InstantiationException ex) { + ex.printStackTrace(); + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + } + return null; + } + +} + diff --git a/java/gov/nist/javax/sip/message/MessageExt.java b/java/gov/nist/javax/sip/message/MessageExt.java new file mode 100644 index 0000000..ed89fdf --- /dev/null +++ b/java/gov/nist/javax/sip/message/MessageExt.java @@ -0,0 +1,120 @@ +package gov.nist.javax.sip.message; + +import java.text.ParseException; + +import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContentLengthHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.FromHeader; +import javax.sip.header.ToHeader; +import javax.sip.header.ViaHeader; +import javax.sip.message.Message; + +/** + * + * @author jean.deruelle@gmail.com + * + */ +public interface MessageExt extends Message { + + /** + * This method allows applications to associate application context with + * the message. This specification does not define the format of this + * data, this the responsibility of the application and is dependent + * on the application. + * this application data is un-interpreted by the stack. + * Beware : when you clone a message, the deepcopy does not apply to the application data + * (instead, we would just make a copy of the pointer). + * + * @param applicationData - un-interpreted application data. + * @since v2.0 + * + */ + + public void setApplicationData (Object applicationData); + + + /** + * Returns the application data associated with the transaction.This + * specification does not define the format of this application specific + * data. This is the responsibility of the application. + * + * @return application data associated with the message by the application. + * @since v2.0 + * + */ + public Object getApplicationData(); + + /** + * Get the multipart mime content from a message. Builds a wrapper around the + * content and breaks it into multiple sections. Returns these sections as + * a multipart mime content list. If the content type is not multipart mime + * then the list will have a single element in it. + * + * @since v2.0 + * @param Message message + * @throws ParseException if the content type is multipart mime but the content + * is not properly encoded. + * + */ + public MultipartMimeContent getMultipartMimeContent() throws ParseException; + + /** + * Get the topmost Via header. + * + * @since v2.0 + */ + public ViaHeader getTopmostViaHeader(); + + /** + * Get the From header or null if none present. + * + * @since v2.0 + */ + public FromHeader getFromHeader(); + + /** + * Get the To header or null if none present. + * + * @since v2.0 + */ + public ToHeader getToHeader(); + + + /** + * Get the callId header or null if none present. + * + * @since v2.0 + */ + public CallIdHeader getCallIdHeader(); + + /** + * Get the CSeq header or null if none present. + * + * @since v2.0 + */ + public CSeqHeader getCSeqHeader(); + + /** + * Get the content type header or null if none present. + * + * @since v2.0 + */ + public ContentTypeHeader getContentTypeHeader(); + + /** + * Get the content length header or null if none present. + * + * @since v2.0 + */ + public ContentLengthHeader getContentLengthHeader(); + + /** + * Get the first line of the request or response. + * + * @since v2.0 + */ + public String getFirstLine(); + +} diff --git a/java/gov/nist/javax/sip/message/MessageFactoryExt.java b/java/gov/nist/javax/sip/message/MessageFactoryExt.java new file mode 100644 index 0000000..d2303bc --- /dev/null +++ b/java/gov/nist/javax/sip/message/MessageFactoryExt.java @@ -0,0 +1,70 @@ +package gov.nist.javax.sip.message; + +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.ServerHeader; +import javax.sip.header.UserAgentHeader; +import javax.sip.message.MessageFactory; + +/** + * Intefaces that will be supported by the next release of JAIN-SIP. + * + * @author mranga + * + */ +public interface MessageFactoryExt extends MessageFactory { + /** + * Set the common UserAgent header for all Requests created from this message factory. + * This header is applied to all Messages created from this Factory object except those + * that take String for an argument and create Message from the given String. + * + * @param userAgent -- the user agent header to set. + * + */ + + public void setDefaultUserAgentHeader(UserAgentHeader userAgent); + + + /** + * Set the common Server header for all Responses created from this message factory. + * This header is applied to all Messages created from this Factory object except those + * that take String for an argument and create Message from the given String. + * + * @param userAgent -- the user agent header to set. + * + * @since 2.0 + * + */ + + public void setDefaultServerHeader(ServerHeader userAgent); + + /** + * Set default charset used for encoding String content. Note that this + * will be applied to all content that is encoded. The default is UTF-8. + * + * @since 2.0 + * + * @param charset -- charset to set. + * @throws NullPointerException if null arg + * @throws IllegalArgumentException if Charset is not a known charset. + * + */ + public void setDefaultContentEncodingCharset(String charset) + throws NullPointerException,IllegalArgumentException ; + + /** + * Create a MultipartMime attachment from a list of content type, subtype and content. + * + * @since 2.0 + * + * @throws NullPointerException, IllegalArgumentException + */ + public MultipartMimeContent createMultipartMimeContent(ContentTypeHeader multipartMimeContentTypeHeader, + String[] contentType, + String[] contentSubtype, + String[] contentBody); + + + + + +} diff --git a/java/gov/nist/javax/sip/message/MessageFactoryImpl.java b/java/gov/nist/javax/sip/message/MessageFactoryImpl.java new file mode 100644 index 0000000..5045cf6 --- /dev/null +++ b/java/gov/nist/javax/sip/message/MessageFactoryImpl.java @@ -0,0 +1,849 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.message; + +import java.text.ParseException; +import javax.sip.header.*; + +import java.util.LinkedList; +import java.util.List; +import gov.nist.javax.sip.header.*; + +import javax.sip.message.*; +import javax.sip.address.*; +import gov.nist.javax.sip.parser.*; + +/** + * Message Factory implementation + * + * @version 1.2 $Revision: 1.23 $ $Date: 2009/09/08 01:58:40 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * @author Olivier Deruelle <br/> + * + */ +@SuppressWarnings("unchecked") +public class MessageFactoryImpl implements MessageFactory, MessageFactoryExt { + + private boolean testing = false; + + private boolean strict = true; + + private static String defaultContentEncodingCharset = "UTF-8"; + + + /* + * The UserAgent header to include for all requests created from this message factory. + */ + private static UserAgentHeader userAgent; + + /* + * The Server header to include + */ + private static ServerHeader server; + + + public void setStrict(boolean strict) { + this.strict = strict; + } + + + + /** + * This is for testing -- allows you to generate invalid requests + */ + public void setTest(boolean flag) { + this.testing = flag; + } + + /** + * Creates a new instance of MessageFactoryImpl + */ + public MessageFactoryImpl() { + } + + /** + * Creates a new Request message of type specified by the method paramater, + * containing the URI of the Request, the mandatory headers of the message + * with a body in the form of a Java object and the body content type. + * + * @param requestURI - + * the new URI object of the requestURI value of this Message. + * @param method - + * the new string of the method value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @param content - + * the new Object of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the method or the body. + */ + public Request createRequest(javax.sip.address.URI requestURI, + String method, CallIdHeader callId, CSeqHeader cSeq, + FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + Object content) throws ParseException { + if (requestURI == null || method == null || callId == null + || cSeq == null || from == null || to == null || via == null + || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException("Null parameters"); + + SIPRequest sipRequest = new SIPRequest(); + sipRequest.setRequestURI(requestURI); + sipRequest.setMethod(method); + sipRequest.setCallId(callId); + sipRequest.setCSeq(cSeq); + sipRequest.setFrom(from); + sipRequest.setTo(to); + sipRequest.setVia(via); + sipRequest.setMaxForwards(maxForwards); + sipRequest.setContent(content, contentType); + if ( userAgent != null ) { + sipRequest.setHeader(userAgent); + } + + return sipRequest; + } + + /** + * Creates a new Request message of type specified by the method paramater, + * containing the URI of the Request, the mandatory headers of the message + * with a body in the form of a byte array and body content type. + * + * @param requestURI - + * the new URI object of the requestURI value of this Message. + * @param method - + * the new string of the method value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @param content - + * the new byte array of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the method or the body. + */ + public Request createRequest(URI requestURI, String method, + CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, + List via, MaxForwardsHeader maxForwards, byte[] content, + ContentTypeHeader contentType) throws ParseException { + if (requestURI == null || method == null || callId == null + || cSeq == null || from == null || to == null || via == null + || maxForwards == null || content == null + || contentType == null) + throw new ParseException( + "JAIN-SIP Exception, some parameters are missing" + + ", unable to create the request", 0); + + SIPRequest sipRequest = new SIPRequest(); + sipRequest.setRequestURI(requestURI); + sipRequest.setMethod(method); + sipRequest.setCallId(callId); + sipRequest.setCSeq(cSeq); + sipRequest.setFrom(from); + sipRequest.setTo(to); + sipRequest.setVia(via); + sipRequest.setMaxForwards(maxForwards); + sipRequest.setHeader((ContentType) contentType); + sipRequest.setMessageContent(content); + if ( userAgent != null ) { + sipRequest.setHeader(userAgent); + } + return sipRequest; + } + + /** + * Creates a new Request message of type specified by the method paramater, + * containing the URI of the Request, the mandatory headers of the message. + * This new Request does not contain a body. + * + * @param requestURI - + * the new URI object of the requestURI value of this Message. + * @param method - + * the new string of the method value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the method. + */ + public Request createRequest(URI requestURI, String method, + CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to, + List via, MaxForwardsHeader maxForwards) throws ParseException { + if (requestURI == null || method == null || callId == null + || cSeq == null || from == null || to == null || via == null + || maxForwards == null) + throw new ParseException( + "JAIN-SIP Exception, some parameters are missing" + + ", unable to create the request", 0); + + SIPRequest sipRequest = new SIPRequest(); + sipRequest.setRequestURI(requestURI); + sipRequest.setMethod(method); + sipRequest.setCallId(callId); + sipRequest.setCSeq(cSeq); + sipRequest.setFrom(from); + sipRequest.setTo(to); + sipRequest.setVia(via); + sipRequest.setMaxForwards(maxForwards); + if (userAgent != null) { + sipRequest.setHeader(userAgent); + } + + return sipRequest; + } + + // Standard Response Creation methods + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, containing the mandatory headers of the message with a body in + * the form of a Java object and the body content type. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @param content - + * the new Object of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, Object content, + ContentTypeHeader contentType) throws ParseException { + if (callId == null || cSeq == null || from == null || to == null + || via == null || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException(" unable to create the response"); + + SIPResponse sipResponse = new SIPResponse(); + StatusLine statusLine = new StatusLine(); + statusLine.setStatusCode(statusCode); + String reasonPhrase = SIPResponse.getReasonPhrase(statusCode); + //if (reasonPhrase == null) + // throw new ParseException(statusCode + " Unkown ", 0); + statusLine.setReasonPhrase(reasonPhrase); + sipResponse.setStatusLine(statusLine); + sipResponse.setCallId(callId); + sipResponse.setCSeq(cSeq); + sipResponse.setFrom(from); + sipResponse.setTo(to); + sipResponse.setVia(via); + sipResponse.setMaxForwards(maxForwards); + sipResponse.setContent(content, contentType); + if (userAgent != null) { + sipResponse.setHeader(userAgent); + } + return sipResponse; + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, containing the mandatory headers of the message with a body in + * the form of a byte array and the body content type. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @param content - + * the new byte array of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, byte[] content, + ContentTypeHeader contentType) throws ParseException { + if (callId == null || cSeq == null || from == null || to == null + || via == null || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException("Null params "); + + SIPResponse sipResponse = new SIPResponse(); + sipResponse.setStatusCode(statusCode); + sipResponse.setCallId(callId); + sipResponse.setCSeq(cSeq); + sipResponse.setFrom(from); + sipResponse.setTo(to); + sipResponse.setVia(via); + sipResponse.setMaxForwards(maxForwards); + sipResponse.setHeader((ContentType) contentType); + sipResponse.setMessageContent(content); + if (userAgent != null) { + sipResponse.setHeader(userAgent); + } + return sipResponse; + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, containing the mandatory headers of the message. This new + * Response does not contain a body. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode. + */ + public Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards) throws ParseException { + if (callId == null || cSeq == null || from == null || to == null + || via == null || maxForwards == null) + throw new ParseException( + "JAIN-SIP Exception, some parameters are missing" + + ", unable to create the response", 0); + + SIPResponse sipResponse = new SIPResponse(); + sipResponse.setStatusCode(statusCode); + sipResponse.setCallId(callId); + sipResponse.setCSeq(cSeq); + sipResponse.setFrom(from); + sipResponse.setTo(to); + sipResponse.setVia(via); + sipResponse.setMaxForwards(maxForwards); + if (userAgent != null) { + sipResponse.setHeader(userAgent); + } + return sipResponse; + } + + // Response Creation methods based on a Request + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, based on a specific Request with a new body in the form of a + * Java object and the body content type. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param request - + * the received Reqest object upon which to base the Response. + * @param content - + * the new Object of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, Request request, + ContentTypeHeader contentType, Object content) + throws ParseException { + if (request == null || content == null || contentType == null) + throw new NullPointerException("null parameters"); + + SIPRequest sipRequest = (SIPRequest) request; + SIPResponse sipResponse = sipRequest.createResponse(statusCode); + sipResponse.setContent(content, contentType); + if (server != null) { + sipResponse.setHeader(server); + } + return sipResponse; + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, based on a specific Request with a new body in the form of a + * byte array and the body content type. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param request - + * the received Reqest object upon which to base the Response. + * @param content - + * the new byte array of the body content value of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, Request request, + ContentTypeHeader contentType, byte[] content) + throws ParseException { + if (request == null || content == null || contentType == null) + throw new NullPointerException("null Parameters"); + + SIPRequest sipRequest = (SIPRequest) request; + SIPResponse sipResponse = sipRequest.createResponse(statusCode); + sipResponse.setHeader((ContentType) contentType); + sipResponse.setMessageContent(content); + if (server != null) { + sipResponse.setHeader(server); + } + return sipResponse; + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, based on a specific Request message. This new Response does + * not contain a body. + * + * @param statusCode - + * the new integer of the statusCode value of this Message. + * @param request - + * the received Reqest object upon which to base the Response. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode. + */ + public Response createResponse(int statusCode, Request request) + throws ParseException { + if (request == null) + throw new NullPointerException("null parameters"); + + // if (LogWriter.needsLogging) + // LogWriter.logMessage("createResponse " + request); + + SIPRequest sipRequest = (SIPRequest) request; + SIPResponse sipResponse = sipRequest.createResponse(statusCode); + // Remove the content from the message (Bug report from + // Antonis Karydas. + sipResponse.removeContent(); + sipResponse.removeHeader(ContentTypeHeader.NAME); + if (server != null) { + sipResponse.setHeader(server); + } + return sipResponse; + } + + /** + * Creates a new Request message of type specified by the method paramater, + * containing the URI of the Request, the mandatory headers of the message + * with a body in the form of a byte array and body content type. + * + * @param requestURI - + * the new URI object of the requestURI value of this Message. + * @param method - + * the new string of the method value of this Message. + * @param callId - + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq - + * the new CSeqHeader object of the cSeq value of this Message. + * @param from - + * the new FromHeader object of the from value of this Message. + * @param to - + * the new ToHeader object of the to value of this Message. + * @param via - + * the new List object of the ViaHeaders of this Message. + * @param contentType - + * the new ContentTypeHeader object of the content type value of + * this Message. + * @param content - + * the new byte array of the body content value of this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the method or the body. + */ + public Request createRequest(javax.sip.address.URI requestURI, + String method, CallIdHeader callId, CSeqHeader cSeq, + FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + byte[] content) throws ParseException { + if (requestURI == null || method == null || callId == null + || cSeq == null || from == null || to == null || via == null + || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException("missing parameters"); + + SIPRequest sipRequest = new SIPRequest(); + sipRequest.setRequestURI(requestURI); + sipRequest.setMethod(method); + sipRequest.setCallId(callId); + sipRequest.setCSeq(cSeq); + sipRequest.setFrom(from); + sipRequest.setTo(to); + sipRequest.setVia(via); + sipRequest.setMaxForwards(maxForwards); + sipRequest.setContent(content, contentType); + if (userAgent != null) { + sipRequest.setHeader(userAgent); + } + return sipRequest; + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, containing the mandatory headers of the message with a body in + * the form of a Java object and the body content type. + * + * @param statusCode + * the new integer of the statusCode value of this Message. + * @param callId + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq + * the new CSeqHeader object of the cSeq value of this Message. + * @param from + * the new FromHeader object of the from value of this Message. + * @param to + * the new ToHeader object of the to value of this Message. + * @param via + * the new List object of the ViaHeaders of this Message. + * @param contentType + * the new ContentTypeHeader object of the content type value of + * this Message. + * @param content + * the new Object of the body content value of this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + Object content) throws ParseException { + if (callId == null || cSeq == null || from == null || to == null + || via == null || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException("missing parameters"); + SIPResponse sipResponse = new SIPResponse(); + StatusLine statusLine = new StatusLine(); + statusLine.setStatusCode(statusCode); + String reason = SIPResponse.getReasonPhrase(statusCode); + if (reason == null) + throw new ParseException(statusCode + " Unknown", 0); + statusLine.setReasonPhrase(reason); + sipResponse.setStatusLine(statusLine); + sipResponse.setCallId(callId); + sipResponse.setCSeq(cSeq); + sipResponse.setFrom(from); + sipResponse.setTo(to); + sipResponse.setVia(via); + sipResponse.setContent(content, contentType); + if ( userAgent != null) { + sipResponse.setHeader(userAgent); + } + return sipResponse; + + } + + /** + * Creates a new Response message of type specified by the statusCode + * paramater, containing the mandatory headers of the message with a body in + * the form of a byte array and the body content type. + * + * @param statusCode + * the new integer of the statusCode value of this Message. + * @param callId + * the new CallIdHeader object of the callId value of this + * Message. + * @param cSeq + * the new CSeqHeader object of the cSeq value of this Message. + * @param from + * the new FromHeader object of the from value of this Message. + * @param to + * the new ToHeader object of the to value of this Message. + * @param via + * the new List object of the ViaHeaders of this Message. + * @param contentType + * the new ContentTypeHeader object of the content type value of + * this Message. + * @param content + * the new byte array of the body content value of this Message. + * @throws ParseException + * which signals that an error has been reached unexpectedly + * while parsing the statusCode or the body. + */ + public Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + byte[] content) throws ParseException { + if (callId == null || cSeq == null || from == null || to == null + || via == null || maxForwards == null || content == null + || contentType == null) + throw new NullPointerException("missing parameters"); + SIPResponse sipResponse = new SIPResponse(); + StatusLine statusLine = new StatusLine(); + statusLine.setStatusCode(statusCode); + String reason = SIPResponse.getReasonPhrase(statusCode); + if (reason == null) + throw new ParseException(statusCode + " : Unknown", 0); + statusLine.setReasonPhrase(reason); + sipResponse.setStatusLine(statusLine); + sipResponse.setCallId(callId); + sipResponse.setCSeq(cSeq); + sipResponse.setFrom(from); + sipResponse.setTo(to); + sipResponse.setVia(via); + sipResponse.setContent(content, contentType); + if ( userAgent != null) { + sipResponse.setHeader(userAgent); + } + return sipResponse; + } + + /** + * Create a request from a string. Conveniance method for UACs that want to + * create an outgoing request from a string. Only the headers of the request + * should be included in the String that is supplied to this method. + * + * @param requestString -- + * string from which to create the message null string returns an + * empty message. + */ + public javax.sip.message.Request createRequest(String requestString) + throws java.text.ParseException { + if (requestString == null || requestString.equals("")) { + SIPRequest retval = new SIPRequest(); + retval.setNullRequest(); + return retval; + } + + StringMsgParser smp = new StringMsgParser(); + smp.setStrict(this.strict); + + /* + * This allows you to catch parse exceptions and create invalid messages + * if you want. + */ + ParseExceptionListener parseExceptionListener = new ParseExceptionListener() { + + public void handleException(ParseException ex, + SIPMessage sipMessage, Class headerClass, + String headerText, String messageText) + throws ParseException { + // Rethrow the error for the essential headers. Otherwise bad + // headers are simply + // recorded in the message. + if (testing) { + if (headerClass == From.class || headerClass == To.class + || headerClass == CallID.class + || headerClass == MaxForwards.class + || headerClass == Via.class + || headerClass == RequestLine.class + || headerClass == StatusLine.class + || headerClass == CSeq.class) + throw ex; + + sipMessage.addUnparsed(headerText); + } + + } + + }; + + if (this.testing) + smp.setParseExceptionListener(parseExceptionListener); + + SIPMessage sipMessage = smp.parseSIPMessage(requestString); + + if (!(sipMessage instanceof SIPRequest)) + throw new ParseException(requestString, 0); + + return (SIPRequest) sipMessage; + } + + /** + * Create a response from a string + * + * @param responseString -- + * string from which to create the message null string returns an + * empty message. + * + */ + public Response createResponse(String responseString) + throws java.text.ParseException { + if (responseString == null) + return new SIPResponse(); + + StringMsgParser smp = new StringMsgParser(); + + SIPMessage sipMessage = smp.parseSIPMessage(responseString); + + if (!(sipMessage instanceof SIPResponse)) + throw new ParseException(responseString, 0); + + return (SIPResponse) sipMessage; + } + + /** + * Set the common UserAgent header for all requests created from this message factory. + * This header is applied to all Messages created from this Factory object except those + * that take String for an argument and create Message from the given String. + * + * @param userAgent -- the user agent header to set. + * + * @since 2.0 + */ + + public void setDefaultUserAgentHeader(UserAgentHeader userAgent) { + MessageFactoryImpl.userAgent = userAgent; + } + + /** + * Set the common Server header for all responses created from this message factory. + * This header is applied to all Messages created from this Factory object except those + * that take String for an argument and create Message from the given String. + * + * @param userAgent -- the user agent header to set. + * + * @since 2.0 + */ + + public void setDefaultServerHeader(ServerHeader server) { + MessageFactoryImpl.server = server; + } + /** + * Get the default common UserAgentHeader. + * + * @return the user agent header. + * + * @since 2.0 + */ + public static UserAgentHeader getDefaultUserAgentHeader() { + return userAgent; + } + + + /** + * Get the default common server header. + * + * @return the server header. + */ + public static ServerHeader getDefaultServerHeader() { + return server; + } + + + /** + * Set default charset used for encoding String content. + * @param charset + */ + public void setDefaultContentEncodingCharset(String charset) throws NullPointerException, + IllegalArgumentException { + if (charset == null ) throw new NullPointerException ("Null argument!"); + MessageFactoryImpl.defaultContentEncodingCharset = charset; + + } + + public static String getDefaultContentEncodingCharset() { + return MessageFactoryImpl.defaultContentEncodingCharset; + } + + + public MultipartMimeContent createMultipartMimeContent(ContentTypeHeader multipartMimeCth, + String[] contentType, + String[] contentSubtype, + String[] contentBody) { + String boundary = multipartMimeCth.getParameter("boundary"); + MultipartMimeContentImpl retval = new MultipartMimeContentImpl(multipartMimeCth); + for (int i = 0 ; i < contentType.length; i++ ) { + ContentTypeHeader cth = new ContentType(contentType[i],contentSubtype[i]); + ContentImpl contentImpl = new ContentImpl(contentBody[i],boundary); + contentImpl.setContentTypeHeader(cth); + retval.add(contentImpl); + } + return retval; + } + + + + +} diff --git a/java/gov/nist/javax/sip/message/MessageObject.java b/java/gov/nist/javax/sip/message/MessageObject.java new file mode 100644 index 0000000..69e424d --- /dev/null +++ b/java/gov/nist/javax/sip/message/MessageObject.java @@ -0,0 +1,170 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + ******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.core.*; +import java.lang.reflect.*; + +/** + * This is the root object from which all other objects in this package + * are derived. This class is never directly instantiated (and hence it + * is abstract). + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:54 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public abstract class MessageObject extends GenericObject { + public abstract String encode(); + + public void dbgPrint() { + super.dbgPrint(); + } + + /** + * An introspection based string formatting method. We need this because + * in this package (although it is an exact duplicate of the one in + * the superclass) because it needs to access the protected members + * of the other objects in this class. + */ + public String debugDump() { + stringRepresentation = ""; + Class<?> myclass = getClass(); + sprint(myclass.getName()); + sprint("{"); + Field[] fields = myclass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + // Only print protected and public members. + int modifier = f.getModifiers(); + if (modifier == Modifier.PRIVATE) + continue; + Class<?> fieldType = f.getType(); + String fieldName = f.getName(); + if (fieldName.compareTo("stringRepresentation") == 0) { + // avoid nasty recursions... + continue; + } + if (fieldName.compareTo("indentation") == 0) { + // formatting stuff - not relevant here. + continue; + } + sprint(fieldName + ":"); + try { + // Primitive fields are printed with type: value + if (fieldType.isPrimitive()) { + String fname = fieldType.toString(); + sprint(fname + ":"); + if (fname.compareTo("int") == 0) { + int intfield = f.getInt(this); + sprint(intfield); + } else if (fname.compareTo("short") == 0) { + short shortField = f.getShort(this); + sprint(shortField); + } else if (fname.compareTo("char") == 0) { + char charField = f.getChar(this); + sprint(charField); + } else if (fname.compareTo("long") == 0) { + long longField = f.getLong(this); + sprint(longField); + } else if (fname.compareTo("boolean") == 0) { + boolean booleanField = f.getBoolean(this); + sprint(booleanField); + } else if (fname.compareTo("double") == 0) { + double doubleField = f.getDouble(this); + sprint(doubleField); + } else if (fname.compareTo("float") == 0) { + float floatField = f.getFloat(this); + sprint(floatField); + } + } else if ( + GenericObject.class.isAssignableFrom( + fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObject) f.get(this)).debugDump( + this.indentation + 1)); + } else { + sprint("<null>"); + } + + } else if (GenericObjectList.class.isAssignableFrom( + fieldType)) { + if (f.get(this) != null) { + sprint( + ((GenericObjectList) f.get(this)).debugDump( + indentation + 1)); + } else { + sprint("<null>"); + } + + } else { + // Dont do recursion on things that are not + // of our header type... + if (f.get(this) != null) { + sprint(f.get(this).getClass().getName() + ":"); + } else { + sprint(fieldType.getName() + ":"); + } + + sprint("{"); + if (f.get(this) != null) { + sprint(f.get(this).toString()); + } else { + sprint("<null>"); + } + sprint("}"); + } + } catch (IllegalAccessException ex1) { + continue; // we are accessing a private field... + } + } + sprint("}"); + return stringRepresentation; + } + + + protected MessageObject() { + super(); + } + + /** + * Formatter with a given starting indentation (for nested structs). + */ + public String dbgPrint(int indent) { + int save = indentation; + indentation = indent; + String retval = this.toString(); + indentation = save; + return retval; + } +} diff --git a/java/gov/nist/javax/sip/message/MultipartMimeContent.java b/java/gov/nist/javax/sip/message/MultipartMimeContent.java new file mode 100644 index 0000000..c5aa454 --- /dev/null +++ b/java/gov/nist/javax/sip/message/MultipartMimeContent.java @@ -0,0 +1,42 @@ +package gov.nist.javax.sip.message; + +import java.util.Iterator; +import java.util.List; + +import javax.sip.header.ContentTypeHeader; + +public interface MultipartMimeContent { + + public abstract boolean add(Content content); + + /** + * Return the Content type header to assign to the outgoing sip meassage. + * + * @return + */ + public abstract ContentTypeHeader getContentTypeHeader(); + + public abstract String toString(); + + /** + * Set the content by its type. + * + * @param content + */ + public abstract void addContent( Content content); + + /** + * Retrieve the list of Content that is part of this MultitypeMime content. + * + * @return - the content iterator. Returns an empty iterator if no content list present. + */ + public Iterator<Content> getContents(); + + /** + * Get the number of Content parts. + * + * @return - the content parts. + */ + public int getContentCount(); + +} diff --git a/java/gov/nist/javax/sip/message/MultipartMimeContentImpl.java b/java/gov/nist/javax/sip/message/MultipartMimeContentImpl.java new file mode 100644 index 0000000..6c89eb2 --- /dev/null +++ b/java/gov/nist/javax/sip/message/MultipartMimeContentImpl.java @@ -0,0 +1,190 @@ +package gov.nist.javax.sip.message; + +import gov.nist.javax.sip.header.HeaderFactoryExt; +import gov.nist.javax.sip.header.HeaderFactoryImpl; +import gov.nist.javax.sip.parser.StringMsgParser; + +import java.text.ParseException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.sip.header.ContentDispositionHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.Header; +import javax.sip.header.HeaderFactory; +import javax.sip.message.Message; + + + +/** + * Content list for multipart mime content type. + * + * @author M. Ranganathan + * + */ +public class MultipartMimeContentImpl implements MultipartMimeContent { + private List<Content> contentList = new LinkedList<Content>(); + + private ContentTypeHeader multipartMimeContentTypeHeader; + + private String boundary; + + public static String BOUNDARY = "boundary"; + + /** + * Creates a default content list. + */ + public MultipartMimeContentImpl(ContentTypeHeader contentTypeHeader) { + this.multipartMimeContentTypeHeader = contentTypeHeader; + this.boundary = contentTypeHeader.getParameter(BOUNDARY); + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.message.MultipartMimeContentExt#add(gov.nist.javax.sip.message.Content) + */ + public boolean add(Content content) { + return contentList.add((ContentImpl) content); + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentTypeHeader() + */ + public ContentTypeHeader getContentTypeHeader() { + return multipartMimeContentTypeHeader; + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.message.MultipartMimeContentExt#toString() + */ + @Override + public String toString() { + StringBuffer stringBuffer = new StringBuffer(); + + for (Content content : this.contentList) { + stringBuffer.append(content.toString()); + } + return stringBuffer.toString(); + + } + + /** + * unpack a multipart mime packet and return a list of content packets. + * + * @return -- an iterator of Content blocks. + * + */ + public void createContentList(String body) throws ParseException { + try { + HeaderFactoryExt headerFactory = new HeaderFactoryImpl(); + String delimiter = this.getContentTypeHeader().getParameter(BOUNDARY); + + if (delimiter == null) { + this.contentList = new LinkedList<Content>(); + ContentImpl content = new ContentImpl(body, delimiter); + content.setContentTypeHeader(this.getContentTypeHeader()); + this.contentList.add(content); + return; + } + + String[] fragments = body.split("--" + delimiter + "\r\n"); + + + for (String nextPart : fragments) { + // NOTE - we are not hanlding line folding for the sip header here. + + if (nextPart == null) { + return; + } + StringBuffer strbuf = new StringBuffer(nextPart); + while (strbuf.length() > 0 + && (strbuf.charAt(0) == '\r' || strbuf.charAt(0) == '\n')) + strbuf.deleteCharAt(0); + + if (strbuf.length() == 0) + continue; + nextPart = strbuf.toString(); + int position = nextPart.indexOf("\r\n\r\n"); + int off = 4; + if (position == -1) { + position = nextPart.indexOf("\n"); + off = 2; + } + if (position == -1) + throw new ParseException("no content type header found in " + nextPart, 0); + String rest = nextPart.substring(position + off); + + if (rest == null) + throw new ParseException("No content [" + nextPart + "]", 0); + // logger.debug("rest = [[" + rest + "]]"); + String headers = nextPart.substring(0, position); + ContentImpl content = new ContentImpl(rest, boundary); + + String[] headerArray = headers.split("\r\n"); + for (String hdr : headerArray) { + Header header = headerFactory.createHeader(hdr); + if (header instanceof ContentTypeHeader) { + content.setContentTypeHeader((ContentTypeHeader) header); + } else if (header instanceof ContentDispositionHeader) { + content.setContentDispositionHeader((ContentDispositionHeader) header); + } else { + throw new ParseException("Unexpected header type " + header.getName(), 0); + } + contentList.add(content); + } + + } + } catch (StringIndexOutOfBoundsException ex) { + throw new ParseException("Invalid Multipart mime format", 0); + } + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.message.MultipartMimeContentExt#getContentByType(java.lang.String, + * java.lang.String) + */ + public Content getContentByType(String contentType, String contentSubtype) { + Content retval = null; + if (contentList == null) + return null; + for (Content content : contentList) { + if (content.getContentTypeHeader().getContentType().equalsIgnoreCase(contentType) + && content.getContentTypeHeader().getContentSubType().equalsIgnoreCase( + contentSubtype)) { + retval = content; + break; + } + + } + return retval; + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.message.MultipartMimeContentExt#setContent(java.lang.String, + * java.lang.String, gov.nist.javax.sip.message.Content) + */ + public void addContent(Content content) { + this.add(content); + } + + public Iterator<Content> getContents() { + return this.contentList.iterator(); + } + + + public int getContentCount() { + return this.contentList.size(); + } + +} diff --git a/java/gov/nist/javax/sip/message/RequestExt.java b/java/gov/nist/javax/sip/message/RequestExt.java new file mode 100644 index 0000000..b8aaa22 --- /dev/null +++ b/java/gov/nist/javax/sip/message/RequestExt.java @@ -0,0 +1,10 @@ +package gov.nist.javax.sip.message; + +import javax.sip.message.Request; + +/** + * Extensions for the JAIN-SIP Request interface. + */ +public interface RequestExt extends Request, MessageExt { + +} diff --git a/java/gov/nist/javax/sip/message/ResponseExt.java b/java/gov/nist/javax/sip/message/ResponseExt.java new file mode 100644 index 0000000..7054f04 --- /dev/null +++ b/java/gov/nist/javax/sip/message/ResponseExt.java @@ -0,0 +1,11 @@ +package gov.nist.javax.sip.message; + +import javax.sip.message.Response; + +/** + *Extension for the jain-sip Response interface. This is a convenience + *interface (placeholder). + */ +public interface ResponseExt extends Response, MessageExt { + +} diff --git a/java/gov/nist/javax/sip/message/SIPDuplicateHeaderException.java b/java/gov/nist/javax/sip/message/SIPDuplicateHeaderException.java new file mode 100644 index 0000000..25232dc --- /dev/null +++ b/java/gov/nist/javax/sip/message/SIPDuplicateHeaderException.java @@ -0,0 +1,68 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Duplicate header exception: thrown when there is more + * than one header of a type where there should only be one. + * The exception handler may choose to : + * 1. discard the duplicate by returning null + * 2. keep the duplicate by just returning it. + * 3. Discard the entire message by throwing an exception. + * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:54 $ + * @since 1.1 + * @author M. Ranganathan + */ +public class SIPDuplicateHeaderException extends ParseException { + + private static final long serialVersionUID = 8241107266407879291L; + protected SIPHeader sipHeader; + protected SIPMessage sipMessage; + public SIPDuplicateHeaderException(String msg) { + super(msg, 0); + } + public SIPMessage getSIPMessage() { + return sipMessage; + } + + public SIPHeader getSIPHeader() { + return sipHeader; + } + + public void setSIPHeader(SIPHeader sipHeader) { + this.sipHeader = sipHeader; + } + + public void setSIPMessage(SIPMessage sipMessage) { + this.sipMessage = sipMessage; + } +} diff --git a/java/gov/nist/javax/sip/message/SIPMessage.java b/java/gov/nist/javax/sip/message/SIPMessage.java new file mode 100644 index 0000000..be27681 --- /dev/null +++ b/java/gov/nist/javax/sip/message/SIPMessage.java @@ -0,0 +1,1895 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + ******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.Utils; +import gov.nist.javax.sip.header.AlertInfo; +import gov.nist.javax.sip.header.Authorization; +import gov.nist.javax.sip.header.CSeq; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.ContactList; +import gov.nist.javax.sip.header.ContentLength; +import gov.nist.javax.sip.header.ContentType; +import gov.nist.javax.sip.header.ErrorInfo; +import gov.nist.javax.sip.header.ErrorInfoList; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.InReplyTo; +import gov.nist.javax.sip.header.MaxForwards; +import gov.nist.javax.sip.header.Priority; +import gov.nist.javax.sip.header.ProxyAuthenticate; +import gov.nist.javax.sip.header.ProxyAuthorization; +import gov.nist.javax.sip.header.ProxyRequire; +import gov.nist.javax.sip.header.ProxyRequireList; +import gov.nist.javax.sip.header.RSeq; +import gov.nist.javax.sip.header.RecordRouteList; +import gov.nist.javax.sip.header.RetryAfter; +import gov.nist.javax.sip.header.Route; +import gov.nist.javax.sip.header.RouteList; +import gov.nist.javax.sip.header.SIPETag; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.SIPHeaderNamesCache; +import gov.nist.javax.sip.header.SIPIfMatch; +import gov.nist.javax.sip.header.Server; +import gov.nist.javax.sip.header.Subject; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Unsupported; +import gov.nist.javax.sip.header.UserAgent; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.header.WWWAuthenticate; +import gov.nist.javax.sip.header.Warning; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.ParserFactory; +import gov.nist.javax.sip.parser.PipelinedMsgParser; +import gov.nist.javax.sip.parser.StringMsgParser; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.text.ParseException; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.ConcurrentLinkedQueue; + +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import javax.sip.header.AuthorizationHeader; +import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContactHeader; +import javax.sip.header.ContentDispositionHeader; +import javax.sip.header.ContentEncodingHeader; +import javax.sip.header.ContentLanguageHeader; +import javax.sip.header.ContentLengthHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.ExpiresHeader; +import javax.sip.header.FromHeader; +import javax.sip.header.Header; +import javax.sip.header.MaxForwardsHeader; +import javax.sip.header.RecordRouteHeader; +import javax.sip.header.RouteHeader; +import javax.sip.header.ToHeader; +import javax.sip.header.ViaHeader; +import javax.sip.message.Request; + +/* + * Acknowledgements: Yanick Belanger sent in a patch for the right content length when the content + * is a String. Bill Mccormick from Nortel Networks sent in a bug fix for setContent. + * + */ +/** + * This is the main SIP Message structure. + * + * @see StringMsgParser + * @see PipelinedMsgParser + * + * @version 1.2 $Revision: 1.53 $ $Date: 2009/12/16 14:58:40 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public abstract class SIPMessage extends MessageObject implements javax.sip.message.Message, + MessageExt { + + // JvB: use static here? + private String contentEncodingCharset = MessageFactoryImpl.getDefaultContentEncodingCharset(); + + /* + * True if this is a null request. + */ + protected boolean nullRequest; + + /** + * unparsed headers + */ + protected LinkedList<String> unrecognizedHeaders; + + /** + * List of parsed headers (in the order they were added) + */ + protected ConcurrentLinkedQueue<SIPHeader> headers; + + /** + * Direct accessors for frequently accessed headers + */ + protected From fromHeader; + + protected To toHeader; + + protected CSeq cSeqHeader; + + protected CallID callIdHeader; + + protected ContentLength contentLengthHeader; + + protected MaxForwards maxForwardsHeader; + + // Cumulative size of all the headers. + protected int size; + + // Payload + private String messageContent; + + private byte[] messageContentBytes; + + private Object messageContentObject; + + // Table of headers indexed by name. + private Hashtable<String, SIPHeader> nameTable; + + /** + * The application data pointer. This is un-interpreted by the stack. This is provided as a + * convenient way of keeping book-keeping data for applications. + */ + protected Object applicationData; + + /** + * Return true if the header belongs only in a Request. + * + * @param sipHeader is the header to test. + */ + public static boolean isRequestHeader(SIPHeader sipHeader) { + return sipHeader instanceof AlertInfo || sipHeader instanceof InReplyTo + || sipHeader instanceof Authorization || sipHeader instanceof MaxForwards + || sipHeader instanceof UserAgent || sipHeader instanceof Priority + || sipHeader instanceof ProxyAuthorization || sipHeader instanceof ProxyRequire + || sipHeader instanceof ProxyRequireList || sipHeader instanceof Route + || sipHeader instanceof RouteList || sipHeader instanceof Subject + || sipHeader instanceof SIPIfMatch; + } + + /** + * Return true if the header belongs only in a response. + * + * @param sipHeader is the header to test. + */ + public static boolean isResponseHeader(SIPHeader sipHeader) { + return sipHeader instanceof ErrorInfo || sipHeader instanceof ProxyAuthenticate + || sipHeader instanceof Server || sipHeader instanceof Unsupported + || sipHeader instanceof RetryAfter || sipHeader instanceof Warning + || sipHeader instanceof WWWAuthenticate || sipHeader instanceof SIPETag + || sipHeader instanceof RSeq; + + } + + /** + * Get the headers as a linked list of encoded Strings + * + * @return a linked list with each element of the list containing a string encoded header in + * canonical form. + */ + public LinkedList<String> getMessageAsEncodedStrings() { + LinkedList<String> retval = new LinkedList<String>(); + Iterator<SIPHeader> li = headers.iterator(); + while (li.hasNext()) { + SIPHeader sipHeader = (SIPHeader) li.next(); + if (sipHeader instanceof SIPHeaderList) { + SIPHeaderList< ? > shl = (SIPHeaderList< ? >) sipHeader; + retval.addAll(shl.getHeadersAsEncodedStrings()); + } else { + retval.add(sipHeader.encode()); + } + } + + return retval; + } + + /** + * Encode only the message and exclude the contents (for debugging); + * + * @return a string with all the headers encoded. + */ + protected String encodeSIPHeaders() { + StringBuffer encoding = new StringBuffer(); + Iterator<SIPHeader> it = this.headers.iterator(); + + while (it.hasNext()) { + SIPHeader siphdr = (SIPHeader) it.next(); + if (!(siphdr instanceof ContentLength)) + siphdr.encode(encoding); + } + + return contentLengthHeader.encode(encoding).append(NEWLINE).toString(); + } + + /** + * Encode all the headers except the contents. For debug logging. + */ + public abstract String encodeMessage(); + + /** + * Get A dialog identifier constructed from this messsage. This is an id that can be used to + * identify dialogs. + * + * @param isServerTransaction is a flag that indicates whether this is a server transaction. + */ + public abstract String getDialogId(boolean isServerTransaction); + + /** + * Template match for SIP messages. The matchObj is a SIPMessage template to match against. + * This method allows you to do pattern matching with incoming SIP messages. Null matches wild + * card. + * + * @param other is the match template to match against. + * @return true if a match occured and false otherwise. + */ + public boolean match(Object other) { + if (other == null) + return true; + if (!other.getClass().equals(this.getClass())) + return false; + SIPMessage matchObj = (SIPMessage) other; + Iterator<SIPHeader> li = matchObj.getHeaders(); + while (li.hasNext()) { + SIPHeader hisHeaders = (SIPHeader) li.next(); + List<SIPHeader> myHeaders = this.getHeaderList(hisHeaders.getHeaderName()); + + // Could not find a header to match his header. + if (myHeaders == null || myHeaders.size() == 0) + return false; + + if (hisHeaders instanceof SIPHeaderList) { + ListIterator< ? > outerIterator = ((SIPHeaderList< ? >) hisHeaders) + .listIterator(); + while (outerIterator.hasNext()) { + SIPHeader hisHeader = (SIPHeader) outerIterator.next(); + if (hisHeader instanceof ContentLength) + continue; + ListIterator< ? > innerIterator = myHeaders.listIterator(); + boolean found = false; + while (innerIterator.hasNext()) { + SIPHeader myHeader = (SIPHeader) innerIterator.next(); + if (myHeader.match(hisHeader)) { + found = true; + break; + } + } + if (!found) + return false; + } + } else { + SIPHeader hisHeader = hisHeaders; + ListIterator<SIPHeader> innerIterator = myHeaders.listIterator(); + boolean found = false; + while (innerIterator.hasNext()) { + SIPHeader myHeader = (SIPHeader) innerIterator.next(); + if (myHeader.match(hisHeader)) { + found = true; + break; + } + } + if (!found) + return false; + } + } + return true; + + } + + /** + * Merge a request with a template + * + * @param template -- template to merge with. + * + */ + public void merge(Object template) { + if (!template.getClass().equals(this.getClass())) + throw new IllegalArgumentException("Bad class " + template.getClass()); + SIPMessage templateMessage = (SIPMessage) template; + Object[] templateHeaders = templateMessage.headers.toArray(); + for (int i = 0; i < templateHeaders.length; i++) { + SIPHeader hdr = (SIPHeader) templateHeaders[i]; + String hdrName = hdr.getHeaderName(); + List<SIPHeader> myHdrs = this.getHeaderList(hdrName); + if (myHdrs == null) { + this.attachHeader(hdr); + } else { + ListIterator<SIPHeader> it = myHdrs.listIterator(); + while (it.hasNext()) { + SIPHeader sipHdr = (SIPHeader) it.next(); + sipHdr.merge(hdr); + } + } + } + + } + + /** + * Encode this message as a string. This is more efficient when the payload is a string + * (rather than a binary array of bytes). If the payload cannot be encoded as a UTF-8 string + * then it is simply ignored (will not appear in the encoded message). + * + * @return The Canonical String representation of the message (including the canonical string + * representation of the SDP payload if it exists). + */ + public String encode() { + StringBuffer encoding = new StringBuffer(); + Iterator<SIPHeader> it = this.headers.iterator(); + + while (it.hasNext()) { + SIPHeader siphdr = (SIPHeader) it.next(); + if (!(siphdr instanceof ContentLength)) + encoding.append(siphdr.encode()); + } + // Append the unrecognized headers. Headers that are not + // recognized are passed through unchanged. + for (String unrecognized : this.unrecognizedHeaders) { + encoding.append(unrecognized).append(NEWLINE); + } + + encoding.append(contentLengthHeader.encode()).append(NEWLINE); + + if (this.messageContentObject != null) { + String mbody = this.getContent().toString(); + + encoding.append(mbody); + } else if (this.messageContent != null || this.messageContentBytes != null) { + + String content = null; + try { + if (messageContent != null) + content = messageContent; + else { + // JvB: Check for 'charset' parameter which overrides the default UTF-8 + content = new String(messageContentBytes, getCharset() ); + } + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + + encoding.append(content); + } + return encoding.toString(); + } + + /** + * Encode the message as a byte array. Use this when the message payload is a binary byte + * array. + * + * @return The Canonical byte array representation of the message (including the canonical + * byte array representation of the SDP payload if it exists all in one contiguous + * byte array). + */ + public byte[] encodeAsBytes(String transport) { + if (this instanceof SIPRequest && ((SIPRequest) this).isNullRequest()) { + return "\r\n\r\n".getBytes(); + } + // JvB: added to fix case where application provides the wrong transport + // in the topmost Via header + ViaHeader topVia = (ViaHeader) this.getHeader(ViaHeader.NAME); + try { + topVia.setTransport(transport); + } catch (ParseException e) { + InternalErrorHandler.handleException(e); + } + + StringBuffer encoding = new StringBuffer(); + synchronized (this.headers) { + Iterator<SIPHeader> it = this.headers.iterator(); + + while (it.hasNext()) { + SIPHeader siphdr = (SIPHeader) it.next(); + if (!(siphdr instanceof ContentLength)) + siphdr.encode(encoding); + + } + } + contentLengthHeader.encode(encoding); + encoding.append(NEWLINE); + + byte[] retval = null; + byte[] content = this.getRawContent(); + if (content != null) { + // Append the content + + byte[] msgarray = null; + try { + msgarray = encoding.toString().getBytes( getCharset() ); + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + + retval = new byte[msgarray.length + content.length]; + System.arraycopy(msgarray, 0, retval, 0, msgarray.length); + System.arraycopy(content, 0, retval, msgarray.length, content.length); + } else { + // Message content does not exist. + + try { + retval = encoding.toString().getBytes( getCharset() ); + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + } + return retval; + } + + /** + * clone this message (create a new deep physical copy). All headers in the message are + * cloned. You can modify the cloned copy without affecting the original. The content is + * handled as follows: If the content is a String, or a byte array, a new copy of the content + * is allocated and copied over. If the content is an Object that supports the clone method, + * then the clone method is invoked and the cloned content is the new content. Otherwise, the + * content of the new message is set equal to the old one. + * + * @return A cloned copy of this object. + */ + public Object clone() { + SIPMessage retval = (SIPMessage) super.clone(); + retval.nameTable = new Hashtable<String, SIPHeader>(); + retval.fromHeader = null; + retval.toHeader = null; + retval.cSeqHeader = null; + retval.callIdHeader = null; + retval.contentLengthHeader = null; + retval.maxForwardsHeader = null; + if (this.headers != null) { + retval.headers = new ConcurrentLinkedQueue<SIPHeader>(); + for (Iterator<SIPHeader> iter = headers.iterator(); iter.hasNext();) { + SIPHeader hdr = (SIPHeader) iter.next(); + retval.attachHeader((SIPHeader) hdr.clone()); + } + + } + if (this.messageContentBytes != null) + retval.messageContentBytes = (byte[]) this.messageContentBytes.clone(); + if (this.messageContentObject != null) + retval.messageContentObject = makeClone(messageContentObject); + retval.unrecognizedHeaders = this.unrecognizedHeaders; + return retval; + } + + /** + * Get the string representation of this header (for pretty printing the generated structure). + * + * @return Formatted string representation of the object. Note that this is NOT the same as + * encode(). This is used mainly for debugging purposes. + */ + public String debugDump() { + stringRepresentation = ""; + sprint("SIPMessage:"); + sprint("{"); + try { + + Field[] fields = this.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field f = fields[i]; + Class< ? > fieldType = f.getType(); + String fieldName = f.getName(); + if (f.get(this) != null && SIPHeader.class.isAssignableFrom(fieldType) + && fieldName.compareTo("headers") != 0) { + sprint(fieldName + "="); + sprint(((SIPHeader) f.get(this)).debugDump()); + } + } + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + + sprint("List of headers : "); + sprint(headers.toString()); + sprint("messageContent = "); + sprint("{"); + sprint(messageContent); + sprint("}"); + if (this.getContent() != null) { + sprint(this.getContent().toString()); + } + sprint("}"); + return stringRepresentation; + } + + /** + * Constructor: Initializes lists and list headers. All the headers for which there can be + * multiple occurances in a message are derived from the SIPHeaderListClass. All singleton + * headers are derived from SIPHeader class. + */ + public SIPMessage() { + this.unrecognizedHeaders = new LinkedList<String>(); + this.headers = new ConcurrentLinkedQueue<SIPHeader>(); + nameTable = new Hashtable<String, SIPHeader>(); + try { + this.attachHeader(new ContentLength(0), false); + } catch (Exception ex) { + } + } + + /** + * Attach a header and die if you get a duplicate header exception. + * + * @param h SIPHeader to attach. + */ + private void attachHeader(SIPHeader h) { + if (h == null) + throw new IllegalArgumentException("null header!"); + try { + if (h instanceof SIPHeaderList) { + SIPHeaderList< ? > hl = (SIPHeaderList< ? >) h; + if (hl.isEmpty()) { + return; + } + } + attachHeader(h, false, false); + } catch (SIPDuplicateHeaderException ex) { + // InternalErrorHandler.handleException(ex); + } + } + + /** + * Attach a header (replacing the original header). + * + * @param sipHeader SIPHeader that replaces a header of the same type. + */ + public void setHeader(Header sipHeader) { + SIPHeader header = (SIPHeader) sipHeader; + if (header == null) + throw new IllegalArgumentException("null header!"); + try { + if (header instanceof SIPHeaderList) { + SIPHeaderList< ? > hl = (SIPHeaderList< ? >) header; + // Ignore empty lists. + if (hl.isEmpty()) + return; + } + this.removeHeader(header.getHeaderName()); + attachHeader(header, true, false); + } catch (SIPDuplicateHeaderException ex) { + InternalErrorHandler.handleException(ex); + } + } + + /** + * Set a header from a linked list of headers. + * + * @param headers -- a list of headers to set. + */ + public void setHeaders(java.util.List<SIPHeader> headers) { + ListIterator<SIPHeader> listIterator = headers.listIterator(); + while (listIterator.hasNext()) { + SIPHeader sipHeader = (SIPHeader) listIterator.next(); + try { + this.attachHeader(sipHeader, false); + } catch (SIPDuplicateHeaderException ex) { + } + } + } + + /** + * Attach a header to the end of the existing headers in this SIPMessage structure. This is + * equivalent to the attachHeader(SIPHeader,replaceflag,false); which is the normal way in + * which headers are attached. This was added in support of JAIN-SIP. + * + * @param h header to attach. + * @param replaceflag if true then replace a header if it exists. + * @throws SIPDuplicateHeaderException If replaceFlag is false and only a singleton header is + * allowed (fpr example CSeq). + */ + public void attachHeader(SIPHeader h, boolean replaceflag) throws SIPDuplicateHeaderException { + this.attachHeader(h, replaceflag, false); + } + + /** + * Attach the header to the SIP Message structure at a specified position in its list of + * headers. + * + * @param header Header to attach. + * @param replaceFlag If true then replace the existing header. + * @param top Location in the header list to insert the header. + * @exception SIPDuplicateHeaderException if the header is of a type that cannot tolerate + * duplicates and one of this type already exists (e.g. CSeq header). + * @throws IndexOutOfBoundsException If the index specified is greater than the number of + * headers that are in this message. + */ + + public void attachHeader(SIPHeader header, boolean replaceFlag, boolean top) + throws SIPDuplicateHeaderException { + if (header == null) { + throw new NullPointerException("null header"); + } + + SIPHeader h; + + if (ListMap.hasList(header) && !SIPHeaderList.class.isAssignableFrom(header.getClass())) { + SIPHeaderList<SIPHeader> hdrList = ListMap.getList(header); + hdrList.add(header); + h = hdrList; + } else { + h = header; + } + + String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(h.getName()); + if (replaceFlag) { + nameTable.remove(headerNameLowerCase); + } else if (nameTable.containsKey(headerNameLowerCase) && !(h instanceof SIPHeaderList)) { + if (h instanceof ContentLength) { + try { + ContentLength cl = (ContentLength) h; + contentLengthHeader.setContentLength(cl.getContentLength()); + } catch (InvalidArgumentException e) { + } + } + // Just ignore duplicate header. + return; + } + + SIPHeader originalHeader = (SIPHeader) getHeader(header.getName()); + + // Delete the original header from our list structure. + if (originalHeader != null) { + Iterator<SIPHeader> li = headers.iterator(); + while (li.hasNext()) { + SIPHeader next = (SIPHeader) li.next(); + if (next.equals(originalHeader)) { + li.remove(); + } + } + } + + if (!nameTable.containsKey(headerNameLowerCase)) { + nameTable.put(headerNameLowerCase, h); + headers.add(h); + } else { + if (h instanceof SIPHeaderList) { + SIPHeaderList< ? > hdrlist = (SIPHeaderList< ? >) nameTable + .get(headerNameLowerCase); + if (hdrlist != null) + hdrlist.concatenate((SIPHeaderList) h, top); + else + nameTable.put(headerNameLowerCase, h); + } else { + nameTable.put(headerNameLowerCase, h); + } + } + + // Direct accessor fields for frequently accessed headers. + if (h instanceof From) { + this.fromHeader = (From) h; + } else if (h instanceof ContentLength) { + this.contentLengthHeader = (ContentLength) h; + } else if (h instanceof To) { + this.toHeader = (To) h; + } else if (h instanceof CSeq) { + this.cSeqHeader = (CSeq) h; + } else if (h instanceof CallID) { + this.callIdHeader = (CallID) h; + } else if (h instanceof MaxForwards) { + this.maxForwardsHeader = (MaxForwards) h; + } + + } + + /** + * Remove a header given its name. If multiple headers of a given name are present then the + * top flag determines which end to remove headers from. + * + * @param headerName is the name of the header to remove. + * @param top -- flag that indicates which end of header list to process. + */ + public void removeHeader(String headerName, boolean top) { + + String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName); + SIPHeader toRemove = (SIPHeader) nameTable.get(headerNameLowerCase); + // nothing to do then we are done. + if (toRemove == null) + return; + if (toRemove instanceof SIPHeaderList) { + SIPHeaderList< ? > hdrList = (SIPHeaderList< ? >) toRemove; + if (top) + hdrList.removeFirst(); + else + hdrList.removeLast(); + // Clean up empty list + if (hdrList.isEmpty()) { + Iterator<SIPHeader> li = this.headers.iterator(); + while (li.hasNext()) { + SIPHeader sipHeader = (SIPHeader) li.next(); + if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase)) + li.remove(); + } + + // JvB: also remove it from the nameTable! Else NPE in + // DefaultRouter + nameTable.remove(headerNameLowerCase); + } + } else { + this.nameTable.remove(headerNameLowerCase); + if (toRemove instanceof From) { + this.fromHeader = null; + } else if (toRemove instanceof To) { + this.toHeader = null; + } else if (toRemove instanceof CSeq) { + this.cSeqHeader = null; + } else if (toRemove instanceof CallID) { + this.callIdHeader = null; + } else if (toRemove instanceof MaxForwards) { + this.maxForwardsHeader = null; + } else if (toRemove instanceof ContentLength) { + this.contentLengthHeader = null; + } + Iterator<SIPHeader> li = this.headers.iterator(); + while (li.hasNext()) { + SIPHeader sipHeader = (SIPHeader) li.next(); + if (sipHeader.getName().equalsIgnoreCase(headerName)) + li.remove(); + } + } + + } + + /** + * Remove all headers given its name. + * + * @param headerName is the name of the header to remove. + */ + public void removeHeader(String headerName) { + + if (headerName == null) + throw new NullPointerException("null arg"); + String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName); + SIPHeader removed = (SIPHeader) nameTable.remove(headerNameLowerCase); + // nothing to do then we are done. + if (removed == null) + return; + + // Remove the fast accessor fields. + if (removed instanceof From) { + this.fromHeader = null; + } else if (removed instanceof To) { + this.toHeader = null; + } else if (removed instanceof CSeq) { + this.cSeqHeader = null; + } else if (removed instanceof CallID) { + this.callIdHeader = null; + } else if (removed instanceof MaxForwards) { + this.maxForwardsHeader = null; + } else if (removed instanceof ContentLength) { + this.contentLengthHeader = null; + } + + Iterator<SIPHeader> li = this.headers.iterator(); + while (li.hasNext()) { + SIPHeader sipHeader = (SIPHeader) li.next(); + if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase)) + li.remove(); + + } + } + + /** + * Generate (compute) a transaction ID for this SIP message. + * + * @return A string containing the concatenation of various portions of the From,To,Via and + * RequestURI portions of this message as specified in RFC 2543: All responses to a + * request contain the same values in the Call-ID, CSeq, To, and From fields (with the + * possible addition of a tag in the To field (section 10.43)). This allows responses + * to be matched with requests. Incorporates a bug fix for a bug sent in by Gordon + * Ledgard of IPera for generating transactionIDs when no port is present in the via + * header. Incorporates a bug fix for a bug report sent in by Chris Mills of Nortel + * Networks (converts to lower case when returning the transaction identifier). + * + * @return a string that can be used as a transaction identifier for this message. This can be + * used for matching responses and requests (i.e. an outgoing request and its matching + * response have the same computed transaction identifier). + */ + public String getTransactionId() { + Via topVia = null; + if (!this.getViaHeaders().isEmpty()) { + topVia = (Via) this.getViaHeaders().getFirst(); + } + // Have specified a branch Identifier so we can use it to identify + // the transaction. BranchId is not case sensitive. + // Branch Id prefix is not case sensitive. + if (topVia != null + && topVia.getBranch() != null + && topVia.getBranch().toUpperCase().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE_UPPER_CASE)) { + // Bis 09 compatible branch assignment algorithm. + // implies that the branch id can be used as a transaction + // identifier. + if (this.getCSeq().getMethod().equals(Request.CANCEL)) + return (topVia.getBranch() + ":" + this.getCSeq().getMethod()).toLowerCase(); + else + return topVia.getBranch().toLowerCase(); + } else { + // Old style client so construct the transaction identifier + // from various fields of the request. + StringBuffer retval = new StringBuffer(); + From from = (From) this.getFrom(); + To to = (To) this.getTo(); + // String hpFrom = from.getUserAtHostPort(); + // retval.append(hpFrom).append(":"); + if (from.hasTag()) + retval.append(from.getTag()).append("-"); + // String hpTo = to.getUserAtHostPort(); + // retval.append(hpTo).append(":"); + String cid = this.callIdHeader.getCallId(); + retval.append(cid).append("-"); + retval.append(this.cSeqHeader.getSequenceNumber()).append("-").append( + this.cSeqHeader.getMethod()); + if (topVia != null) { + retval.append("-").append(topVia.getSentBy().encode()); + if (!topVia.getSentBy().hasPort()) { + retval.append("-").append(5060); + } + } + if (this.getCSeq().getMethod().equals(Request.CANCEL)) { + retval.append(Request.CANCEL); + } + return retval.toString().toLowerCase().replace(":", "-").replace("@", "-") + + Utils.getSignature(); + } + } + + /** + * Override the hashcode method ( see issue # 55 ) Note that if you try to use this method + * before you assemble a valid request, you will get a constant ( -1 ). Beware of placing any + * half formed requests in a table. + */ + public int hashCode() { + if (this.callIdHeader == null) + throw new RuntimeException( + "Invalid message! Cannot compute hashcode! call-id header is missing !"); + else + return this.callIdHeader.getCallId().hashCode(); + } + + /** + * Return true if this message has a body. + */ + public boolean hasContent() { + return messageContent != null || messageContentBytes != null; + } + + /** + * Return an iterator for the list of headers in this message. + * + * @return an Iterator for the headers of this message. + */ + public Iterator<SIPHeader> getHeaders() { + return headers.iterator(); + } + + /** + * Get the first header of the given name. + * + * @return header -- the first header of the given name. + */ + public Header getHeader(String headerName) { + return getHeaderLowerCase(SIPHeaderNamesCache.toLowerCase(headerName)); + } + + private Header getHeaderLowerCase(String lowerCaseHeaderName) { + if (lowerCaseHeaderName == null) + throw new NullPointerException("bad name"); + SIPHeader sipHeader = (SIPHeader) nameTable.get(lowerCaseHeaderName); + if (sipHeader instanceof SIPHeaderList) + return (Header) ((SIPHeaderList) sipHeader).getFirst(); + else + return (Header) sipHeader; + } + + /** + * Get the contentType header (null if one does not exist). + * + * @return contentType header + */ + + public ContentType getContentTypeHeader() { + return (ContentType) getHeaderLowerCase(CONTENT_TYPE_LOWERCASE); + } + + private static final String CONTENT_TYPE_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ContentTypeHeader.NAME); + + + /** + * Get the contentLength header. + */ + public ContentLengthHeader getContentLengthHeader() { + return this.getContentLength(); + } + + + /** + * Get the from header. + * + * @return -- the from header. + */ + public FromHeader getFrom() { + return (FromHeader) fromHeader; + } + + /** + * Get the ErrorInfo list of headers (null if one does not exist). + * + * @return List containing ErrorInfo headers. + */ + public ErrorInfoList getErrorInfoHeaders() { + return (ErrorInfoList) getSIPHeaderListLowerCase(ERROR_LOWERCASE); + } + + private static final String ERROR_LOWERCASE = SIPHeaderNamesCache.toLowerCase(ErrorInfo.NAME); + + /** + * Get the Contact list of headers (null if one does not exist). + * + * @return List containing Contact headers. + */ + public ContactList getContactHeaders() { + return (ContactList) this.getSIPHeaderListLowerCase(CONTACT_LOWERCASE); + } + + private static final String CONTACT_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ContactHeader.NAME); + + /** + * Get the contact header ( the first contact header) which is all we need for the most part. + * + */ + public Contact getContactHeader() { + ContactList clist = this.getContactHeaders(); + if (clist != null) { + return (Contact) clist.getFirst(); + + } else { + return null; + } + } + + /** + * Get the Via list of headers (null if one does not exist). + * + * @return List containing Via headers. + */ + public ViaList getViaHeaders() { + return (ViaList) getSIPHeaderListLowerCase(VIA_LOWERCASE); + } + + private static final String VIA_LOWERCASE = SIPHeaderNamesCache.toLowerCase(ViaHeader.NAME); + + /** + * Set A list of via headers. + * + * @param viaList a list of via headers to add. + */ + public void setVia(java.util.List viaList) { + ViaList vList = new ViaList(); + ListIterator it = viaList.listIterator(); + while (it.hasNext()) { + Via via = (Via) it.next(); + vList.add(via); + } + this.setHeader(vList); + } + + /** + * Set the header given a list of headers. + * + * @param sipHeaderList a headerList to set + */ + + public void setHeader(SIPHeaderList<Via> sipHeaderList) { + this.setHeader((Header) sipHeaderList); + } + + /** + * Get the topmost via header. + * + * @return the top most via header if one exists or null if none exists. + */ + public Via getTopmostVia() { + if (this.getViaHeaders() == null) + return null; + else + return (Via) (getViaHeaders().getFirst()); + } + + /** + * Get the CSeq list of header (null if one does not exist). + * + * @return CSeq header + */ + public CSeqHeader getCSeq() { + return (CSeqHeader) cSeqHeader; + } + + /** + * Get the Authorization header (null if one does not exist). + * + * @return Authorization header. + */ + public Authorization getAuthorization() { + return (Authorization) getHeaderLowerCase(AUTHORIZATION_LOWERCASE); + } + + private static final String AUTHORIZATION_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(AuthorizationHeader.NAME); + + /** + * Get the MaxForwards header (null if one does not exist). + * + * @return Max-Forwards header + */ + + public MaxForwardsHeader getMaxForwards() { + return maxForwardsHeader; + } + + /** + * Set the max forwards header. + * + * @param maxForwards is the MaxForwardsHeader to set. + */ + public void setMaxForwards(MaxForwardsHeader maxForwards) { + this.setHeader(maxForwards); + } + + /** + * Get the Route List of headers (null if one does not exist). + * + * @return List containing Route headers + */ + public RouteList getRouteHeaders() { + return (RouteList) getSIPHeaderListLowerCase(ROUTE_LOWERCASE); + } + + private static final String ROUTE_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(RouteHeader.NAME); + + /** + * Get the CallID header (null if one does not exist) + * + * @return Call-ID header . + */ + public CallIdHeader getCallId() { + return callIdHeader; + } + + /** + * Set the call id header. + * + * @param callId call idHeader (what else could it be?) + */ + public void setCallId(CallIdHeader callId) { + this.setHeader(callId); + } + + /** + * Get the CallID header (null if one does not exist) + * + * @param callId -- the call identifier to be assigned to the call id header + */ + public void setCallId(String callId) throws java.text.ParseException { + if (callIdHeader == null) { + this.setHeader(new CallID()); + } + callIdHeader.setCallId(callId); + } + + /** + * Get the RecordRoute header list (null if one does not exist). + * + * @return Record-Route header + */ + public RecordRouteList getRecordRouteHeaders() { + return (RecordRouteList) this.getSIPHeaderListLowerCase(RECORDROUTE_LOWERCASE); + } + + private static final String RECORDROUTE_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(RecordRouteHeader.NAME); + + /** + * Get the To header (null if one does not exist). + * + * @return To header + */ + public ToHeader getTo() { + return (ToHeader) toHeader; + } + + public void setTo(ToHeader to) { + this.setHeader(to); + } + + public void setFrom(FromHeader from) { + this.setHeader(from); + + } + + /** + * Get the ContentLength header (null if one does not exist). + * + * @return content-length header. + */ + public ContentLengthHeader getContentLength() { + return this.contentLengthHeader; + } + + /** + * Get the message body as a string. If the message contains a content type header with a + * specified charset, and if the payload has been read as a byte array, then it is returned + * encoded into this charset. + * + * @return Message body (as a string) + * @throws UnsupportedEncodingException if the platform does not support the charset specified + * in the content type header. + * + */ + public String getMessageContent() throws UnsupportedEncodingException { + if (this.messageContent == null && this.messageContentBytes == null) + return null; + else if (this.messageContent == null) { + this.messageContent = new String(messageContentBytes, getCharset() ); + } + return this.messageContent; + } + + /** + * Get the message content as an array of bytes. If the payload has been read as a String then + * it is decoded using the charset specified in the content type header if it exists. + * Otherwise, it is encoded using the default encoding which is UTF-8. + * + * @return an array of bytes that is the message payload. + */ + public byte[] getRawContent() { + try { + if ( this.messageContentBytes != null ) { + // return messageContentBytes; + } else if (this.messageContentObject != null) { + String messageContent = this.messageContentObject.toString(); + this.messageContentBytes = messageContent.getBytes( getCharset() ); + } else if (this.messageContent != null) { + this.messageContentBytes = messageContent.getBytes( getCharset() ); + } + return this.messageContentBytes; + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + return null; + } + } + + /** + * Set the message content given type and subtype. + * + * @param type is the message type (eg. application) + * @param subType is the message sybtype (eg. sdp) + * @param messageContent is the messge content as a string. + */ + public void setMessageContent(String type, String subType, String messageContent) { + if (messageContent == null) + throw new IllegalArgumentException("messgeContent is null"); + ContentType ct = new ContentType(type, subType); + this.setHeader(ct); + this.messageContent = messageContent; + this.messageContentBytes = null; + this.messageContentObject = null; + // Could be double byte so we need to compute length + // after converting to byte[] + computeContentLength(messageContent); + } + + /** + * Set the message content after converting the given object to a String. + * + * @param content -- content to set. + * @param contentTypeHeader -- content type header corresponding to content. + */ + public void setContent(Object content, ContentTypeHeader contentTypeHeader) + throws ParseException { + if (content == null) + throw new NullPointerException("null content"); + this.setHeader(contentTypeHeader); + + this.messageContent = null; + this.messageContentBytes = null; + this.messageContentObject = null; + + if (content instanceof String) { + this.messageContent = (String) content; + } else if (content instanceof byte[]) { + this.messageContentBytes = (byte[]) content; + } else + this.messageContentObject = content; + + computeContentLength(content); + } + + /** + * Get the content (body) of the message. + * + * @return the content of the sip message. + */ + public Object getContent() { + if (this.messageContentObject != null) + return messageContentObject; + else if (this.messageContent != null) + return this.messageContent; + else if (this.messageContentBytes != null) + return this.messageContentBytes; + else + return null; + } + + /** + * Set the message content for a given type and subtype. + * + * @param type is the messge type. + * @param subType is the message subType. + * @param messageContent is the message content as a byte array. + */ + public void setMessageContent(String type, String subType, byte[] messageContent) { + ContentType ct = new ContentType(type, subType); + this.setHeader(ct); + this.setMessageContent(messageContent); + + computeContentLength(messageContent); + } + + /** + * Set the message content for this message. + * + * @param content Message body as a string. + */ + public void setMessageContent(String content, boolean strict, boolean computeContentLength, int givenLength) + throws ParseException { + // Note that that this could be a double byte character + // set - bug report by Masafumi Watanabe + computeContentLength(content); + if ((!computeContentLength)) { + if ( (!strict && this.contentLengthHeader.getContentLength() != givenLength) + || this.contentLengthHeader.getContentLength() < givenLength) { + throw new ParseException("Invalid content length " + + this.contentLengthHeader.getContentLength() + " / " + givenLength, 0); + } + } + + messageContent = content; + messageContentBytes = null; + messageContentObject = null; + } + + /** + * Set the message content as an array of bytes. + * + * @param content is the content of the message as an array of bytes. + */ + public void setMessageContent(byte[] content) { + computeContentLength(content); + + messageContentBytes = content; + messageContent = null; + messageContentObject = null; + } + + /** + * Method to set the content - called by the parser + * + * @param content + * @throws ParseException + */ + public void setMessageContent(byte[] content, boolean computeContentLength, int givenLength) + throws ParseException { + computeContentLength(content); + if ((!computeContentLength) && this.contentLengthHeader.getContentLength() < givenLength) { + // System.out.println("!!!!!!!!!!! MISMATCH !!!!!!!!!!!"); + throw new ParseException("Invalid content length " + + this.contentLengthHeader.getContentLength() + " / " + givenLength, 0); + } + messageContentBytes = content; + messageContent = null; + messageContentObject = null; + } + + /** + * Compute and set the Content-length header based on the given content object. + * + * @param content is the content, as String, array of bytes, or other object. + */ + private void computeContentLength(Object content) { + int length = 0; + if (content != null) { + if (content instanceof String) { + try { + length = ((String) content).getBytes( getCharset() ).length; + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + } else if (content instanceof byte[]) { + length = ((byte[]) content).length; + } else { + length = content.toString().length(); + } + } + + try { + contentLengthHeader.setContentLength(length); + } catch (InvalidArgumentException e) { + // Cannot happen. + } + } + + /** + * Remove the message content if it exists. + */ + public void removeContent() { + messageContent = null; + messageContentBytes = null; + messageContentObject = null; + try { + this.contentLengthHeader.setContentLength(0); + } catch (InvalidArgumentException ex) { + } + } + + /** + * Get a SIP header or Header list given its name. + * + * @param headerName is the name of the header to get. + * @return a header or header list that contians the retrieved header. + */ + @SuppressWarnings("unchecked") + public ListIterator<SIPHeader> getHeaders(String headerName) { + if (headerName == null) + throw new NullPointerException("null headerName"); + SIPHeader sipHeader = (SIPHeader) nameTable.get(SIPHeaderNamesCache + .toLowerCase(headerName)); + // empty iterator + if (sipHeader == null) + return new LinkedList<SIPHeader>().listIterator(); + if (sipHeader instanceof SIPHeaderList) { + return ((SIPHeaderList<SIPHeader>) sipHeader).listIterator(); + } else { + return new HeaderIterator(this, sipHeader); + } + } + + /** + * Get a header of the given name as a string. This concatenates the headers of a given type + * as a comma separted list. This is useful for formatting and printing headers. + * + * @param name + * @return the header as a formatted string + */ + public String getHeaderAsFormattedString(String name) { + String lowerCaseName = name.toLowerCase(); + if (this.nameTable.containsKey(lowerCaseName)) { + return this.nameTable.get(lowerCaseName).toString(); + } else { + return this.getHeader(name).toString(); + } + } + + private SIPHeader getSIPHeaderListLowerCase(String lowerCaseHeaderName) { + return nameTable.get(lowerCaseHeaderName); + } + + /** + * Get a list of headers of the given name ( or null if no such header exists ). + * + * @param headerName -- a header name from which to retrieve the list. + * @return -- a list of headers with that name. + */ + @SuppressWarnings("unchecked") + private List<SIPHeader> getHeaderList(String headerName) { + SIPHeader sipHeader = (SIPHeader) nameTable.get(SIPHeaderNamesCache + .toLowerCase(headerName)); + if (sipHeader == null) + return null; + else if (sipHeader instanceof SIPHeaderList) + return (List<SIPHeader>) (((SIPHeaderList< ? >) sipHeader).getHeaderList()); + else { + LinkedList<SIPHeader> ll = new LinkedList<SIPHeader>(); + ll.add(sipHeader); + return ll; + } + } + + /** + * Return true if the SIPMessage has a header of the given name. + * + * @param headerName is the header name for which we are testing. + * @return true if the header is present in the message + */ + public boolean hasHeader(String headerName) { + return nameTable.containsKey(SIPHeaderNamesCache.toLowerCase(headerName)); + } + + /** + * Return true if the message has a From header tag. + * + * @return true if the message has a from header and that header has a tag. + */ + public boolean hasFromTag() { + return fromHeader != null && fromHeader.getTag() != null; + } + + /** + * Return true if the message has a To header tag. + * + * @return true if the message has a to header and that header has a tag. + */ + public boolean hasToTag() { + return toHeader != null && toHeader.getTag() != null; + } + + /** + * Return the from tag. + * + * @return the tag from the from header. + * + */ + public String getFromTag() { + return fromHeader == null ? null : fromHeader.getTag(); + } + + /** + * Set the From Tag. + * + * @param tag -- tag to set in the from header. + */ + public void setFromTag(String tag) { + try { + fromHeader.setTag(tag); + } catch (ParseException e) { + } + } + + /** + * Set the to tag. + * + * @param tag -- tag to set. + */ + public void setToTag(String tag) { + try { + toHeader.setTag(tag); + } catch (ParseException e) { + } + } + + /** + * Return the to tag. + */ + public String getToTag() { + return toHeader == null ? null : toHeader.getTag(); + } + + /** + * Return the encoded first line. + */ + public abstract String getFirstLine(); + + /** + * Add a SIP header. + * + * @param sipHeader -- sip header to add. + */ + public void addHeader(Header sipHeader) { + // Content length is never stored. Just computed. + SIPHeader sh = (SIPHeader) sipHeader; + try { + if ((sipHeader instanceof ViaHeader) || (sipHeader instanceof RecordRouteHeader)) { + attachHeader(sh, false, true); + } else { + attachHeader(sh, false, false); + } + } catch (SIPDuplicateHeaderException ex) { + try { + if (sipHeader instanceof ContentLength) { + ContentLength cl = (ContentLength) sipHeader; + contentLengthHeader.setContentLength(cl.getContentLength()); + } + } catch (InvalidArgumentException e) { + } + } + } + + /** + * Add a header to the unparsed list of headers. + * + * @param unparsed -- unparsed header to add to the list. + */ + public void addUnparsed(String unparsed) { + this.unrecognizedHeaders.add(unparsed); + } + + /** + * Add a SIP header. + * + * @param sipHeader -- string version of SIP header to add. + */ + + public void addHeader(String sipHeader) { + String hdrString = sipHeader.trim() + "\n"; + try { + HeaderParser parser = ParserFactory.createParser(sipHeader); + SIPHeader sh = parser.parse(); + this.attachHeader(sh, false); + } catch (ParseException ex) { + this.unrecognizedHeaders.add(hdrString); + } + } + + /** + * Get a list containing the unrecognized headers. + * + * @return a linked list containing unrecongnized headers. + */ + public ListIterator<String> getUnrecognizedHeaders() { + return this.unrecognizedHeaders.listIterator(); + } + + /** + * Get the header names. + * + * @return a list iterator to a list of header names. These are ordered in the same order as + * are present in the message. + */ + public ListIterator<String> getHeaderNames() { + Iterator<SIPHeader> li = this.headers.iterator(); + LinkedList<String> retval = new LinkedList<String>(); + while (li.hasNext()) { + SIPHeader sipHeader = (SIPHeader) li.next(); + String name = sipHeader.getName(); + retval.add(name); + } + return retval.listIterator(); + } + + /** + * Compare for equality. + * + * @param other -- the other object to compare with. + */ + public boolean equals(Object other) { + if (!other.getClass().equals(this.getClass())) { + return false; + } + SIPMessage otherMessage = (SIPMessage) other; + Collection<SIPHeader> values = this.nameTable.values(); + Iterator<SIPHeader> it = values.iterator(); + if (nameTable.size() != otherMessage.nameTable.size()) { + return false; + } + + while (it.hasNext()) { + SIPHeader mine = (SIPHeader) it.next(); + SIPHeader his = (SIPHeader) (otherMessage.nameTable.get(SIPHeaderNamesCache + .toLowerCase(mine.getName()))); + if (his == null) { + return false; + } else if (!his.equals(mine)) { + return false; + } + } + return true; + } + + /** + * get content disposition header or null if no such header exists. + * + * @return the contentDisposition header + */ + public javax.sip.header.ContentDispositionHeader getContentDisposition() { + return (ContentDispositionHeader) getHeaderLowerCase(CONTENT_DISPOSITION_LOWERCASE); + } + + private static final String CONTENT_DISPOSITION_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ContentDispositionHeader.NAME); + + /** + * get the content encoding header. + * + * @return the contentEncoding header. + */ + public javax.sip.header.ContentEncodingHeader getContentEncoding() { + return (ContentEncodingHeader) getHeaderLowerCase(CONTENT_ENCODING_LOWERCASE); + } + + private static final String CONTENT_ENCODING_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ContentEncodingHeader.NAME); + + /** + * Get the contentLanguage header. + * + * @return the content language header. + */ + public javax.sip.header.ContentLanguageHeader getContentLanguage() { + return (ContentLanguageHeader) getHeaderLowerCase(CONTENT_LANGUAGE_LOWERCASE); + } + + private static final String CONTENT_LANGUAGE_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ContentLanguageHeader.NAME); + + /** + * Get the exipres header. + * + * @return the expires header or null if one does not exist. + */ + public javax.sip.header.ExpiresHeader getExpires() { + return (ExpiresHeader) getHeaderLowerCase(EXPIRES_LOWERCASE); + } + + private static final String EXPIRES_LOWERCASE = SIPHeaderNamesCache + .toLowerCase(ExpiresHeader.NAME); + + /** + * Set the expiresHeader + * + * @param expiresHeader -- the expires header to set. + */ + + public void setExpires(ExpiresHeader expiresHeader) { + this.setHeader(expiresHeader); + } + + /** + * Set the content disposition header. + * + * @param contentDispositionHeader -- content disposition header. + */ + + public void setContentDisposition(ContentDispositionHeader contentDispositionHeader) { + this.setHeader(contentDispositionHeader); + + } + + public void setContentEncoding(ContentEncodingHeader contentEncodingHeader) { + this.setHeader(contentEncodingHeader); + + } + + public void setContentLanguage(ContentLanguageHeader contentLanguageHeader) { + this.setHeader(contentLanguageHeader); + } + + /** + * Set the content length header. + * + * @param contentLength -- content length header. + */ + public void setContentLength(ContentLengthHeader contentLength) { + try { + this.contentLengthHeader.setContentLength(contentLength.getContentLength()); + } catch (InvalidArgumentException ex) { + } + + } + + /** + * Set the size of all the headers. This is for book keeping. Called by the parser. + * + * @param size -- size of the headers. + */ + public void setSize(int size) { + this.size = size; + } + + public int getSize() { + return this.size; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.message.Message#addLast(javax.sip.header.Header) + */ + public void addLast(Header header) throws SipException, NullPointerException { + if (header == null) + throw new NullPointerException("null arg!"); + + try { + this.attachHeader((SIPHeader) header, false, false); + } catch (SIPDuplicateHeaderException ex) { + throw new SipException("Cannot add header - header already exists"); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.message.Message#addFirst(javax.sip.header.Header) + */ + public void addFirst(Header header) throws SipException, NullPointerException { + + if (header == null) + throw new NullPointerException("null arg!"); + + try { + this.attachHeader((SIPHeader) header, false, true); + } catch (SIPDuplicateHeaderException ex) { + throw new SipException("Cannot add header - header already exists"); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.message.Message#removeFirst(java.lang.String) + */ + public void removeFirst(String headerName) throws NullPointerException { + if (headerName == null) + throw new NullPointerException("Null argument Provided!"); + this.removeHeader(headerName, true); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.message.Message#removeLast(java.lang.String) + */ + public void removeLast(String headerName) { + if (headerName == null) + throw new NullPointerException("Null argument Provided!"); + this.removeHeader(headerName, false); + + } + + /** + * Set the CSeq header. + * + * @param cseqHeader -- CSeq Header. + */ + + public void setCSeq(CSeqHeader cseqHeader) { + this.setHeader(cseqHeader); + } + + /** + * Set the application data pointer. This method is not used the stack. It is provided as a + * convenient way of storing book-keeping data for applications. Note that null clears the + * application data pointer (releases it). + * + * @param applicationData -- application data pointer to set. null clears the application data + * pointer. + */ + public void setApplicationData(Object applicationData) { + this.applicationData = applicationData; + } + + /** + * Get the application data associated with this message. + * + * @return stored application data. + */ + public Object getApplicationData() { + return this.applicationData; + } + + /** + * Get the multipart MIME content + * + */ + public MultipartMimeContent getMultipartMimeContent() throws ParseException { + if (this.contentLengthHeader.getContentLength() == 0) { + return null; + } + MultipartMimeContentImpl retval = new MultipartMimeContentImpl(this + .getContentTypeHeader()); + byte[] rawContent = getRawContent(); + try { + String body = new String( rawContent, getCharset() ); + retval.createContentList(body); + return retval; + } catch (UnsupportedEncodingException e) { + InternalErrorHandler.handleException(e); + return null; + } + } + + public CallIdHeader getCallIdHeader() { + return this.callIdHeader; + } + + + public FromHeader getFromHeader() { + return this.fromHeader; + } + + + public ToHeader getToHeader() { + return this.toHeader; + } + + + public ViaHeader getTopmostViaHeader() { + return this.getTopmostVia(); + } + + public CSeqHeader getCSeqHeader() { + return this.cSeqHeader; + } + + /** + * Returns the charset to use for encoding/decoding the body of this message + */ + protected final String getCharset() { + ContentType ct = getContentTypeHeader(); + if (ct!=null) { + String c = ct.getCharset(); + return c!=null ? c : contentEncodingCharset; + } else return contentEncodingCharset; + } + + /** + * Return true if this is a null request (i.e. does not have a request line ). + * + * @return true if null request. + */ + public boolean isNullRequest() { + return this.nullRequest; + } + + /** + * Set a flag to indiate this is a special message ( encoded with CRLFCRLF ). + * + */ + public void setNullRequest() { + this.nullRequest = true; + } + + + public abstract void setSIPVersion(String sipVersion) throws ParseException; + + public abstract String getSIPVersion(); + + public abstract String toString(); + +} diff --git a/java/gov/nist/javax/sip/message/SIPRequest.java b/java/gov/nist/javax/sip/message/SIPRequest.java new file mode 100644 index 0000000..3136383 --- /dev/null +++ b/java/gov/nist/javax/sip/message/SIPRequest.java @@ -0,0 +1,1207 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + *******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.javax.sip.address.*; +import gov.nist.core.*; + +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.Set; +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import javax.sip.address.URI; +import javax.sip.message.*; + +import java.text.ParseException; +import javax.sip.*; +import javax.sip.header.*; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.stack.SIPTransactionStack; + +/* + * Acknowledgements: Mark Bednarek made a few fixes to this code. Jeff Keyser added two methods + * that create responses and generate cancel requests from incoming orignial requests without the + * additional overhead of encoding and decoding messages. Bruno Konik noticed an extraneous + * newline added to the end of the buffer when encoding it. Incorporates a bug report from Andreas + * Bystrom. Szabo Barna noticed a contact in a cancel request - this is a pointless header for + * cancel. Antonis Kyardis contributed bug fixes. Jeroen van Bemmel noted that method names are + * case sensitive, should use equals() in getting CannonicalName + * + */ + +/** + * The SIP Request structure. + * + * @version 1.2 $Revision: 1.52 $ $Date: 2009/12/16 14:58:40 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + * + */ + +public final class SIPRequest extends SIPMessage implements javax.sip.message.Request, RequestExt { + + private static final long serialVersionUID = 3360720013577322927L; + + private static final String DEFAULT_USER = "ip"; + + private static final String DEFAULT_TRANSPORT = "udp"; + + private transient Object transactionPointer; + + private RequestLine requestLine; + + private transient Object messageChannel; + + + + private transient Object inviteTransaction; // The original invite request for a + // given cancel request + + /** + * Set of target refresh methods, currently: INVITE, UPDATE, SUBSCRIBE, NOTIFY, REFER + * + * A target refresh request and its response MUST have a Contact + */ + private static final Set<String> targetRefreshMethods = new HashSet<String>(); + + /* + * A table that maps a name string to its cannonical constant. This is used to speed up + * parsing of messages .equals reduces to == if we use the constant value. + */ + private static final Hashtable<String, String> nameTable = new Hashtable<String, String>(); + + private static void putName(String name) { + nameTable.put(name, name); + } + + static { + targetRefreshMethods.add(Request.INVITE); + targetRefreshMethods.add(Request.UPDATE); + targetRefreshMethods.add(Request.SUBSCRIBE); + targetRefreshMethods.add(Request.NOTIFY); + targetRefreshMethods.add(Request.REFER); + + putName(Request.INVITE); + putName(Request.BYE); + putName(Request.CANCEL); + putName(Request.ACK); + putName(Request.PRACK); + putName(Request.INFO); + putName(Request.MESSAGE); + putName(Request.NOTIFY); + putName(Request.OPTIONS); + putName(Request.PRACK); + putName(Request.PUBLISH); + putName(Request.REFER); + putName(Request.REGISTER); + putName(Request.SUBSCRIBE); + putName(Request.UPDATE); + + } + + /** + * @return true iff the method is a target refresh + */ + public static boolean isTargetRefresh(String ucaseMethod) { + return targetRefreshMethods.contains(ucaseMethod); + } + + /** + * @return true iff the method is a dialog creating method + */ + public static boolean isDialogCreating(String ucaseMethod) { + return SIPTransactionStack.isDialogCreated(ucaseMethod); + } + + /** + * Set to standard constants to speed up processing. this makes equals comparisons run much + * faster in the stack because then it is just identity comparision. Character by char + * comparison is not required. The method returns the String CONSTANT corresponding to the + * String name. + * + */ + public static String getCannonicalName(String method) { + + if (nameTable.containsKey(method)) + return (String) nameTable.get(method); + else + return method; + } + + /** + * Get the Request Line of the SIPRequest. + * + * @return the request line of the SIP Request. + */ + + public RequestLine getRequestLine() { + return requestLine; + } + + /** + * Set the request line of the SIP Request. + * + * @param requestLine is the request line to set in the SIP Request. + */ + + public void setRequestLine(RequestLine requestLine) { + this.requestLine = requestLine; + } + + /** + * Constructor. + */ + public SIPRequest() { + super(); + } + + /** + * Convert to a formatted string for pretty printing. Note that the encode method converts + * this into a sip message that is suitable for transmission. Note hack here if you want to + * convert the nice curly brackets into some grotesque XML tag. + * + * @return a string which can be used to examine the message contents. + * + */ + public String debugDump() { + String superstring = super.debugDump(); + stringRepresentation = ""; + sprint(SIPRequest.class.getName()); + sprint("{"); + if (requestLine != null) + sprint(requestLine.debugDump()); + sprint(superstring); + sprint("}"); + return stringRepresentation; + } + + /** + * Check header for constraints. (1) Invite options and bye requests can only have SIP URIs in + * the contact headers. (2) Request must have cseq, to and from and via headers. (3) Method in + * request URI must match that in CSEQ. + */ + public void checkHeaders() throws ParseException { + String prefix = "Missing a required header : "; + + /* Check for required headers */ + + if (getCSeq() == null) { + throw new ParseException(prefix + CSeqHeader.NAME, 0); + } + if (getTo() == null) { + throw new ParseException(prefix + ToHeader.NAME, 0); + } + + if (this.callIdHeader == null || this.callIdHeader.getCallId() == null + || callIdHeader.getCallId().equals("")) { + throw new ParseException(prefix + CallIdHeader.NAME, 0); + } + if (getFrom() == null) { + throw new ParseException(prefix + FromHeader.NAME, 0); + } + if (getViaHeaders() == null) { + throw new ParseException(prefix + ViaHeader.NAME, 0); + } + if (getMaxForwards() == null) { + throw new ParseException(prefix + MaxForwardsHeader.NAME, 0); + } + + if (getTopmostVia() == null) + throw new ParseException("No via header in request! ", 0); + + if (getMethod().equals(Request.NOTIFY)) { + if (getHeader(SubscriptionStateHeader.NAME) == null) + throw new ParseException(prefix + SubscriptionStateHeader.NAME, 0); + + if (getHeader(EventHeader.NAME) == null) + throw new ParseException(prefix + EventHeader.NAME, 0); + + } else if (getMethod().equals(Request.PUBLISH)) { + /* + * For determining the type of the published event state, the EPA MUST include a + * single Event header field in PUBLISH requests. The value of this header field + * indicates the event package for which this request is publishing event state. + */ + if (getHeader(EventHeader.NAME) == null) + throw new ParseException(prefix + EventHeader.NAME, 0); + } + + /* + * RFC 3261 8.1.1.8 The Contact header field MUST be present and contain exactly one SIP + * or SIPS URI in any request that can result in the establishment of a dialog. For the + * methods defined in this specification, that includes only the INVITE request. For these + * requests, the scope of the Contact is global. That is, the Contact header field value + * contains the URI at which the UA would like to receive requests, and this URI MUST be + * valid even if used in subsequent requests outside of any dialogs. + * + * If the Request-URI or top Route header field value contains a SIPS URI, the Contact + * header field MUST contain a SIPS URI as well. + */ + if (requestLine.getMethod().equals(Request.INVITE) + || requestLine.getMethod().equals(Request.SUBSCRIBE) + || requestLine.getMethod().equals(Request.REFER)) { + if (this.getContactHeader() == null) { + // Make sure this is not a target refresh. If this is a target + // refresh its ok not to have a contact header. Otherwise + // contact header is mandatory. + if (this.getToTag() == null) + throw new ParseException(prefix + ContactHeader.NAME, 0); + } + + if (requestLine.getUri() instanceof SipUri) { + String scheme = ((SipUri) requestLine.getUri()).getScheme(); + if ("sips".equalsIgnoreCase(scheme)) { + SipUri sipUri = (SipUri) this.getContactHeader().getAddress().getURI(); + if (!sipUri.getScheme().equals("sips")) { + throw new ParseException("Scheme for contact should be sips:" + sipUri, 0); + } + } + } + } + + /* + * Contact header is mandatory for a SIP INVITE request. + */ + if (this.getContactHeader() == null + && (this.getMethod().equals(Request.INVITE) + || this.getMethod().equals(Request.REFER) || this.getMethod().equals( + Request.SUBSCRIBE))) { + throw new ParseException("Contact Header is Mandatory for a SIP INVITE", 0); + } + + if (requestLine != null && requestLine.getMethod() != null + && getCSeq().getMethod() != null + && requestLine.getMethod().compareTo(getCSeq().getMethod()) != 0) { + throw new ParseException("CSEQ method mismatch with Request-Line ", 0); + + } + + } + + /** + * Set the default values in the request URI if necessary. + */ + protected void setDefaults() { + // The request line may be unparseable (set to null by the + // exception handler. + if (requestLine == null) + return; + String method = requestLine.getMethod(); + // The requestLine may be malformed! + if (method == null) + return; + GenericURI u = requestLine.getUri(); + if (u == null) + return; + if (method.compareTo(Request.REGISTER) == 0 || method.compareTo(Request.INVITE) == 0) { + if (u instanceof SipUri) { + SipUri sipUri = (SipUri) u; + sipUri.setUserParam(DEFAULT_USER); + try { + sipUri.setTransportParam(DEFAULT_TRANSPORT); + } catch (ParseException ex) { + } + } + } + } + + /** + * Patch up the request line as necessary. + */ + protected void setRequestLineDefaults() { + String method = requestLine.getMethod(); + if (method == null) { + CSeq cseq = (CSeq) this.getCSeq(); + if (cseq != null) { + method = getCannonicalName(cseq.getMethod()); + requestLine.setMethod(method); + } + } + } + + /** + * A conveniance function to access the Request URI. + * + * @return the requestURI if it exists. + */ + public javax.sip.address.URI getRequestURI() { + if (this.requestLine == null) + return null; + else + return (javax.sip.address.URI) this.requestLine.getUri(); + } + + /** + * Sets the RequestURI of Request. The Request-URI is a SIP or SIPS URI or a general URI. It + * indicates the user or service to which this request is being addressed. SIP elements MAY + * support Request-URIs with schemes other than "sip" and "sips", for example the "tel" URI + * scheme. SIP elements MAY translate non-SIP URIs using any mechanism at their disposal, + * resulting in SIP URI, SIPS URI, or some other scheme. + * + * @param uri the new Request URI of this request message + */ + public void setRequestURI(URI uri) { + if ( uri == null ) { + throw new NullPointerException("Null request URI"); + } + if (this.requestLine == null) { + this.requestLine = new RequestLine(); + } + this.requestLine.setUri((GenericURI) uri); + this.nullRequest = false; + } + + /** + * Set the method. + * + * @param method is the method to set. + * @throws IllegalArgumentException if the method is null + */ + public void setMethod(String method) { + if (method == null) + throw new IllegalArgumentException("null method"); + if (this.requestLine == null) { + this.requestLine = new RequestLine(); + } + + // Set to standard constants to speed up processing. + // this makes equals compares run much faster in the + // stack because then it is just identity comparision + + String meth = getCannonicalName(method); + this.requestLine.setMethod(meth); + + if (this.cSeqHeader != null) { + try { + this.cSeqHeader.setMethod(meth); + } catch (ParseException e) { + } + } + } + + /** + * Get the method from the request line. + * + * @return the method from the request line if the method exits and null if the request line + * or the method does not exist. + */ + public String getMethod() { + if (requestLine == null) + return null; + else + return requestLine.getMethod(); + } + + /** + * Encode the SIP Request as a string. + * + * @return an encoded String containing the encoded SIP Message. + */ + + public String encode() { + String retval; + if (requestLine != null) { + this.setRequestLineDefaults(); + retval = requestLine.encode() + super.encode(); + } else if (this.isNullRequest()) { + retval = "\r\n\r\n"; + } else { + retval = super.encode(); + } + return retval; + } + + /** + * Encode only the headers and not the content. + */ + public String encodeMessage() { + String retval; + if (requestLine != null) { + this.setRequestLineDefaults(); + retval = requestLine.encode() + super.encodeSIPHeaders(); + } else if (this.isNullRequest()) { + retval = "\r\n\r\n"; + } else + retval = super.encodeSIPHeaders(); + return retval; + + } + + /** + * ALias for encode above. + */ + public String toString() { + return this.encode(); + } + + /** + * Make a clone (deep copy) of this object. You can use this if you want to modify a request + * while preserving the original + * + * @return a deep copy of this object. + */ + + public Object clone() { + SIPRequest retval = (SIPRequest) super.clone(); + // Do not copy over the tx pointer -- this is only for internal + // tracking. + retval.transactionPointer = null; + if (this.requestLine != null) + retval.requestLine = (RequestLine) this.requestLine.clone(); + + return retval; + } + + /** + * Compare for equality. + * + * @param other object to compare ourselves with. + */ + public boolean equals(Object other) { + if (!this.getClass().equals(other.getClass())) + return false; + SIPRequest that = (SIPRequest) other; + + return requestLine.equals(that.requestLine) && super.equals(other); + } + + /** + * Get the message as a linked list of strings. Use this if you want to iterate through the + * message. + * + * @return a linked list containing the request line and headers encoded as strings. + */ + public LinkedList getMessageAsEncodedStrings() { + LinkedList retval = super.getMessageAsEncodedStrings(); + if (requestLine != null) { + this.setRequestLineDefaults(); + retval.addFirst(requestLine.encode()); + } + return retval; + + } + + /** + * Match with a template. You can use this if you want to match incoming messages with a + * pattern and do something when you find a match. This is useful for building filters/pattern + * matching responders etc. + * + * @param matchObj object to match ourselves with (null matches wildcard) + * + */ + public boolean match(Object matchObj) { + if (matchObj == null) + return true; + else if (!matchObj.getClass().equals(this.getClass())) + return false; + else if (matchObj == this) + return true; + SIPRequest that = (SIPRequest) matchObj; + RequestLine rline = that.requestLine; + if (this.requestLine == null && rline != null) + return false; + else if (this.requestLine == rline) + return super.match(matchObj); + return requestLine.match(that.requestLine) && super.match(matchObj); + + } + + /** + * Get a dialog identifier. Generates a string that can be used as a dialog identifier. + * + * @param isServer is set to true if this is the UAS and set to false if this is the UAC + */ + public String getDialogId(boolean isServer) { + CallID cid = (CallID) this.getCallId(); + StringBuffer retval = new StringBuffer(cid.getCallId()); + From from = (From) this.getFrom(); + To to = (To) this.getTo(); + if (!isServer) { + // retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + // retval.append(COLON).append(to.getUserAtHostPort()); + if (to.getTag() != null) { + retval.append(COLON); + retval.append(to.getTag()); + } + } else { + // retval.append(COLON).append(to.getUserAtHostPort()); + if (to.getTag() != null) { + retval.append(COLON); + retval.append(to.getTag()); + } + // retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + } + return retval.toString().toLowerCase(); + + } + + /** + * Get a dialog id given the remote tag. + */ + public String getDialogId(boolean isServer, String toTag) { + From from = (From) this.getFrom(); + CallID cid = (CallID) this.getCallId(); + StringBuffer retval = new StringBuffer(cid.getCallId()); + if (!isServer) { + // retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + // retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + retval.append(COLON); + retval.append(toTag); + } + } else { + // retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + retval.append(COLON); + retval.append(toTag); + } + // retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + } + return retval.toString().toLowerCase(); + } + + /** + * Encode this into a byte array. This is used when the body has been set as a binary array + * and you want to encode the body as a byte array for transmission. + * + * @return a byte array containing the SIPRequest encoded as a byte array. + */ + + public byte[] encodeAsBytes(String transport) { + if (this.isNullRequest()) { + // Encoding a null message for keepalive. + return "\r\n\r\n".getBytes(); + } else if ( this.requestLine == null ) { + return new byte[0]; + } + + byte[] rlbytes = null; + if (requestLine != null) { + try { + rlbytes = requestLine.encode().getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + } + byte[] superbytes = super.encodeAsBytes(transport); + byte[] retval = new byte[rlbytes.length + superbytes.length]; + System.arraycopy(rlbytes, 0, retval, 0, rlbytes.length); + System.arraycopy(superbytes, 0, retval, rlbytes.length, superbytes.length); + return retval; + } + + /** + * Creates a default SIPResponse message for this request. Note You must add the necessary + * tags to outgoing responses if need be. For efficiency, this method does not clone the + * incoming request. If you want to modify the outgoing response, be sure to clone the + * incoming request as the headers are shared and any modification to the headers of the + * outgoing response will result in a modification of the incoming request. Tag fields are + * just copied from the incoming request. Contact headers are removed from the incoming + * request. Added by Jeff Keyser. + * + * @param statusCode Status code for the response. Reason phrase is generated. + * + * @return A SIPResponse with the status and reason supplied, and a copy of all the original + * headers from this request. + */ + + public SIPResponse createResponse(int statusCode) { + + String reasonPhrase = SIPResponse.getReasonPhrase(statusCode); + return this.createResponse(statusCode, reasonPhrase); + + } + + /** + * Creates a default SIPResponse message for this request. Note You must add the necessary + * tags to outgoing responses if need be. For efficiency, this method does not clone the + * incoming request. If you want to modify the outgoing response, be sure to clone the + * incoming request as the headers are shared and any modification to the headers of the + * outgoing response will result in a modification of the incoming request. Tag fields are + * just copied from the incoming request. Contact headers are removed from the incoming + * request. Added by Jeff Keyser. Route headers are not added to the response. + * + * @param statusCode Status code for the response. + * @param reasonPhrase Reason phrase for this response. + * + * @return A SIPResponse with the status and reason supplied, and a copy of all the original + * headers from this request except the ones that are not supposed to be part of the + * response . + */ + + public SIPResponse createResponse(int statusCode, String reasonPhrase) { + SIPResponse newResponse; + Iterator headerIterator; + SIPHeader nextHeader; + + newResponse = new SIPResponse(); + try { + newResponse.setStatusCode(statusCode); + } catch (ParseException ex) { + throw new IllegalArgumentException("Bad code " + statusCode); + } + if (reasonPhrase != null) + newResponse.setReasonPhrase(reasonPhrase); + else + newResponse.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode)); + headerIterator = getHeaders(); + while (headerIterator.hasNext()) { + nextHeader = (SIPHeader) headerIterator.next(); + if (nextHeader instanceof From + || nextHeader instanceof To + || nextHeader instanceof ViaList + || nextHeader instanceof CallID + || (nextHeader instanceof RecordRouteList && mustCopyRR(statusCode)) + || nextHeader instanceof CSeq + // We just copy TimeStamp for all headers (not just 100). + || nextHeader instanceof TimeStamp) { + + try { + + newResponse.attachHeader((SIPHeader) nextHeader.clone(), false); + } catch (SIPDuplicateHeaderException e) { + e.printStackTrace(); + } + } + } + if (MessageFactoryImpl.getDefaultServerHeader() != null) { + newResponse.setHeader(MessageFactoryImpl.getDefaultServerHeader()); + + } + if (newResponse.getStatusCode() == 100) { + // Trying is never supposed to have the tag parameter set. + newResponse.getTo().removeParameter("tag"); + + } + ServerHeader server = MessageFactoryImpl.getDefaultServerHeader(); + if (server != null) { + newResponse.setHeader(server); + } + return newResponse; + } + + // Helper method for createResponse, to avoid copying Record-Route unless needed + private final boolean mustCopyRR( int code ) { + // Only for 1xx-2xx, not for 100 or errors + if ( code>100 && code<300 ) { + return isDialogCreating( this.getMethod() ) && getToTag() == null; + } else return false; + } + + /** + * Creates a default SIPResquest message that would cancel this request. Note that tag + * assignment and removal of is left to the caller (we use whatever tags are present in the + * original request). + * + * @return A CANCEL SIPRequest constructed according to RFC3261 section 9.1 + * + * @throws SipException + * @throws ParseException + */ + public SIPRequest createCancelRequest() throws SipException { + + // see RFC3261 9.1 + + // A CANCEL request SHOULD NOT be sent to cancel a request other than + // INVITE + + if (!this.getMethod().equals(Request.INVITE)) + throw new SipException("Attempt to create CANCEL for " + this.getMethod()); + + /* + * The following procedures are used to construct a CANCEL request. The Request-URI, + * Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request + * MUST be identical to those in the request being cancelled, including tags. A CANCEL + * constructed by a client MUST have only a single Via header field value matching the top + * Via value in the request being cancelled. Using the same values for these header fields + * allows the CANCEL to be matched with the request it cancels (Section 9.2 indicates how + * such matching occurs). However, the method part of the CSeq header field MUST have a + * value of CANCEL. This allows it to be identified and processed as a transaction in its + * own right (See Section 17). + */ + SIPRequest cancel = new SIPRequest(); + cancel.setRequestLine((RequestLine) this.requestLine.clone()); + cancel.setMethod(Request.CANCEL); + cancel.setHeader((Header) this.callIdHeader.clone()); + cancel.setHeader((Header) this.toHeader.clone()); + cancel.setHeader((Header) cSeqHeader.clone()); + try { + cancel.getCSeq().setMethod(Request.CANCEL); + } catch (ParseException e) { + e.printStackTrace(); // should not happen + } + cancel.setHeader((Header) this.fromHeader.clone()); + + cancel.addFirst((Header) this.getTopmostVia().clone()); + cancel.setHeader((Header) this.maxForwardsHeader.clone()); + + /* + * If the request being cancelled contains a Route header field, the CANCEL request MUST + * include that Route header field's values. + */ + if (this.getRouteHeaders() != null) { + cancel.setHeader((SIPHeaderList< ? >) this.getRouteHeaders().clone()); + } + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { + cancel.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + + } + return cancel; + } + + /** + * Creates a default ACK SIPRequest message for this original request. Note that the + * defaultACK SIPRequest does not include the content of the original SIPRequest. If + * responseToHeader is null then the toHeader of this request is used to construct the ACK. + * Note that tag fields are just copied from the original SIP Request. Added by Jeff Keyser. + * + * @param responseToHeader To header to use for this request. + * + * @return A SIPRequest with an ACK method. + */ + public SIPRequest createAckRequest(To responseToHeader) { + SIPRequest newRequest; + Iterator headerIterator; + SIPHeader nextHeader; + + newRequest = new SIPRequest(); + newRequest.setRequestLine((RequestLine) this.requestLine.clone()); + newRequest.setMethod(Request.ACK); + headerIterator = getHeaders(); + while (headerIterator.hasNext()) { + nextHeader = (SIPHeader) headerIterator.next(); + if (nextHeader instanceof RouteList) { + // Ack and cancel do not get ROUTE headers. + // Route header for ACK is assigned by the + // Dialog if necessary. + continue; + } else if (nextHeader instanceof ProxyAuthorization) { + // Remove proxy auth header. + // Assigned by the Dialog if necessary. + continue; + } else if (nextHeader instanceof ContentLength) { + // Adding content is responsibility of user. + nextHeader = (SIPHeader) nextHeader.clone(); + try { + ((ContentLength) nextHeader).setContentLength(0); + } catch (InvalidArgumentException e) { + } + } else if (nextHeader instanceof ContentType) { + // Content type header is removed since + // content length is 0. + continue; + } else if (nextHeader instanceof CSeq) { + // The CSeq header field in the + // ACK MUST contain the same value for the + // sequence number as was present in the + // original request, but the method parameter + // MUST be equal to "ACK". + CSeq cseq = (CSeq) nextHeader.clone(); + try { + cseq.setMethod(Request.ACK); + } catch (ParseException e) { + } + nextHeader = cseq; + } else if (nextHeader instanceof To) { + if (responseToHeader != null) { + nextHeader = responseToHeader; + } else { + nextHeader = (SIPHeader) nextHeader.clone(); + } + } else if (nextHeader instanceof ContactList || nextHeader instanceof Expires) { + // CONTACT header does not apply for ACK requests. + continue; + } else if (nextHeader instanceof ViaList) { + // Bug reported by Gianluca Martinello + // The ACK MUST contain a single Via header field, + // and this MUST be equal to the top Via header + // field of the original + // request. + + nextHeader = (SIPHeader) ((ViaList) nextHeader).getFirst().clone(); + } else { + nextHeader = (SIPHeader) nextHeader.clone(); + } + + try { + newRequest.attachHeader(nextHeader, false); + } catch (SIPDuplicateHeaderException e) { + e.printStackTrace(); + } + } + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { + newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + + } + return newRequest; + } + + /** + * Creates an ACK for non-2xx responses according to RFC3261 17.1.1.3 + * + * @return A SIPRequest with an ACK method. + * @throws SipException + * @throws NullPointerException + * @throws ParseException + * + * @author jvb + */ + public final SIPRequest createErrorAck(To responseToHeader) throws SipException, + ParseException { + + /* + * The ACK request constructed by the client transaction MUST contain values for the + * Call-ID, From, and Request-URI that are equal to the values of those header fields in + * the request passed to the transport by the client transaction (call this the "original + * request"). The To header field in the ACK MUST equal the To header field in the + * response being acknowledged, and therefore will usually differ from the To header field + * in the original request by the addition of the tag parameter. The ACK MUST contain a + * single Via header field, and this MUST be equal to the top Via header field of the + * original request. The CSeq header field in the ACK MUST contain the same value for the + * sequence number as was present in the original request, but the method parameter MUST + * be equal to "ACK". + */ + SIPRequest newRequest = new SIPRequest(); + newRequest.setRequestLine((RequestLine) this.requestLine.clone()); + newRequest.setMethod(Request.ACK); + newRequest.setHeader((Header) this.callIdHeader.clone()); + newRequest.setHeader((Header) this.maxForwardsHeader.clone()); // ISSUE + // 130 + // fix + newRequest.setHeader((Header) this.fromHeader.clone()); + newRequest.setHeader((Header) responseToHeader.clone()); + newRequest.addFirst((Header) this.getTopmostVia().clone()); + newRequest.setHeader((Header) cSeqHeader.clone()); + newRequest.getCSeq().setMethod(Request.ACK); + + /* + * If the INVITE request whose response is being acknowledged had Route header fields, + * those header fields MUST appear in the ACK. This is to ensure that the ACK can be + * routed properly through any downstream stateless proxies. + */ + if (this.getRouteHeaders() != null) { + newRequest.setHeader((SIPHeaderList) this.getRouteHeaders().clone()); + } + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { + newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + + } + return newRequest; + } + + /** + * Create a new default SIPRequest from the original request. Warning: the newly created + * SIPRequest, shares the headers of this request but we generate any new headers that we need + * to modify so the original request is umodified. However, if you modify the shared headers + * after this request is created, then the newly created request will also be modified. If you + * want to modify the original request without affecting the returned Request make sure you + * clone it before calling this method. + * + * Only required headers are copied. + * <ul> + * <li> Contact headers are not included in the newly created request. Setting the appropriate + * sequence number is the responsibility of the caller. </li> + * <li> RouteList is not copied for ACK and CANCEL </li> + * <li> Note that we DO NOT copy the body of the argument into the returned header. We do not + * copy the content type header from the original request either. These have to be added + * seperately and the content length has to be correctly set if necessary the content length + * is set to 0 in the returned header. </li> + * <li>Contact List is not copied from the original request.</li> + * <li>RecordRoute List is not included from original request. </li> + * <li>Via header is not included from the original request. </li> + * </ul> + * + * @param requestLine is the new request line. + * + * @param switchHeaders is a boolean flag that causes to and from headers to switch (set this + * to true if you are the server of the transaction and are generating a BYE request). + * If the headers are switched, we generate new From and To headers otherwise we just + * use the incoming headers. + * + * @return a new Default SIP Request which has the requestLine specified. + * + */ + public SIPRequest createSIPRequest(RequestLine requestLine, boolean switchHeaders) { + SIPRequest newRequest = new SIPRequest(); + newRequest.requestLine = requestLine; + Iterator<SIPHeader> headerIterator = this.getHeaders(); + while (headerIterator.hasNext()) { + SIPHeader nextHeader = (SIPHeader) headerIterator.next(); + // For BYE and cancel set the CSeq header to the + // appropriate method. + if (nextHeader instanceof CSeq) { + CSeq newCseq = (CSeq) nextHeader.clone(); + nextHeader = newCseq; + try { + newCseq.setMethod(requestLine.getMethod()); + } catch (ParseException e) { + } + } else if (nextHeader instanceof ViaList) { + Via via = (Via) (((ViaList) nextHeader).getFirst().clone()); + via.removeParameter("branch"); + nextHeader = via; + // Cancel and ACK preserve the branch ID. + } else if (nextHeader instanceof To) { + To to = (To) nextHeader; + if (switchHeaders) { + nextHeader = new From(to); + ((From) nextHeader).removeTag(); + } else { + nextHeader = (SIPHeader) to.clone(); + ((To) nextHeader).removeTag(); + } + } else if (nextHeader instanceof From) { + From from = (From) nextHeader; + if (switchHeaders) { + nextHeader = new To(from); + ((To) nextHeader).removeTag(); + } else { + nextHeader = (SIPHeader) from.clone(); + ((From) nextHeader).removeTag(); + } + } else if (nextHeader instanceof ContentLength) { + ContentLength cl = (ContentLength) nextHeader.clone(); + try { + cl.setContentLength(0); + } catch (InvalidArgumentException e) { + } + nextHeader = cl; + } else if (!(nextHeader instanceof CallID) && !(nextHeader instanceof MaxForwards)) { + // Route is kept by dialog. + // RR is added by the caller. + // Contact is added by the Caller + // Any extension headers must be added + // by the caller. + continue; + } + try { + newRequest.attachHeader(nextHeader, false); + } catch (SIPDuplicateHeaderException e) { + e.printStackTrace(); + } + } + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { + newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + + } + return newRequest; + + } + + /** + * Create a BYE request from this request. + * + * @param switchHeaders is a boolean flag that causes from and isServerTransaction to headers + * to be swapped. Set this to true if you are the server of the dialog and are + * generating a BYE request for the dialog. + * @return a new default BYE request. + */ + public SIPRequest createBYERequest(boolean switchHeaders) { + RequestLine requestLine = (RequestLine) this.requestLine.clone(); + requestLine.setMethod("BYE"); + return this.createSIPRequest(requestLine, switchHeaders); + } + + /** + * Create an ACK request from this request. This is suitable for generating an ACK for an + * INVITE client transaction. + * + * @return an ACK request that is generated from this request. + */ + public SIPRequest createACKRequest() { + RequestLine requestLine = (RequestLine) this.requestLine.clone(); + requestLine.setMethod(Request.ACK); + return this.createSIPRequest(requestLine, false); + } + + /** + * Get the host from the topmost via header. + * + * @return the string representation of the host from the topmost via header. + */ + public String getViaHost() { + Via via = (Via) this.getViaHeaders().getFirst(); + return via.getHost(); + + } + + /** + * Get the port from the topmost via header. + * + * @return the port from the topmost via header (5060 if there is no port indicated). + */ + public int getViaPort() { + Via via = (Via) this.getViaHeaders().getFirst(); + if (via.hasPort()) + return via.getPort(); + else + return 5060; + } + + /** + * Get the first line encoded. + * + * @return a string containing the encoded request line. + */ + public String getFirstLine() { + if (requestLine == null) + return null; + else + return this.requestLine.encode(); + } + + /** + * Set the sip version. + * + * @param sipVersion the sip version to set. + */ + public void setSIPVersion(String sipVersion) throws ParseException { + if (sipVersion == null || !sipVersion.equalsIgnoreCase("SIP/2.0")) + throw new ParseException("sipVersion", 0); + this.requestLine.setSipVersion(sipVersion); + } + + /** + * Get the SIP version. + * + * @return the SIP version from the request line. + */ + public String getSIPVersion() { + return this.requestLine.getSipVersion(); + } + + /** + * Book keeping method to return the current tx for the request if one exists. + * + * @return the assigned tx. + */ + public Object getTransaction() { + // Return an opaque pointer to the transaction object. + // This is for consistency checking and quick lookup. + return this.transactionPointer; + } + + /** + * Book keeping field to set the current tx for the request. + * + * @param transaction + */ + public void setTransaction(Object transaction) { + this.transactionPointer = transaction; + } + + /** + * Book keeping method to get the messasge channel for the request. + * + * @return the message channel for the request. + */ + + public Object getMessageChannel() { + // return opaque ptr to the message chanel on + // which the message was recieved. For consistency + // checking and lookup. + return this.messageChannel; + } + + /** + * Set the message channel for the request ( bookkeeping field ). + * + * @param messageChannel + */ + + public void setMessageChannel(Object messageChannel) { + this.messageChannel = messageChannel; + } + + /** + * Generates an Id for checking potentially merged requests. + * + * @return String to check for merged requests + */ + public String getMergeId() { + /* + * generate an identifier from the From tag, Call-ID, and CSeq + */ + String fromTag = this.getFromTag(); + String cseq = this.cSeqHeader.toString(); + String callId = this.callIdHeader.getCallId(); + /* NOTE : The RFC does NOT specify you need to include a Request URI + * This is added here for the case of Back to Back User Agents. + */ + String requestUri = this.getRequestURI().toString(); + + if (fromTag != null) { + return new StringBuffer().append(requestUri).append(":").append(fromTag).append(":").append(cseq).append(":") + .append(callId).toString(); + } else + return null; + + } + + /** + * @param inviteTransaction the inviteTransaction to set + */ + public void setInviteTransaction(Object inviteTransaction) { + this.inviteTransaction = inviteTransaction; + } + + /** + * @return the inviteTransaction + */ + public Object getInviteTransaction() { + return inviteTransaction; + } + + + + + +} diff --git a/java/gov/nist/javax/sip/message/SIPResponse.java b/java/gov/nist/javax/sip/message/SIPResponse.java new file mode 100644 index 0000000..57fe507 --- /dev/null +++ b/java/gov/nist/javax/sip/message/SIPResponse.java @@ -0,0 +1,735 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + *******************************************************************************/ +package gov.nist.javax.sip.message; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.Utils; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.CSeq; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.header.ContactList; +import gov.nist.javax.sip.header.ContentLength; +import gov.nist.javax.sip.header.ContentType; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.MaxForwards; +import gov.nist.javax.sip.header.ReasonList; +import gov.nist.javax.sip.header.RecordRouteList; +import gov.nist.javax.sip.header.RequireList; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.StatusLine; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.header.extensions.SessionExpires; + +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +import java.util.Iterator; +import java.util.LinkedList; + +import javax.sip.header.ReasonHeader; +import javax.sip.header.ServerHeader; +import javax.sip.message.Request; + + +/** + * SIP Response structure. + * + * @version 1.2 $Revision: 1.29 $ $Date: 2009/10/25 03:07:52 $ + * @since 1.1 + * + * @author M. Ranganathan <br/> + * + * + */ +public final class SIPResponse + extends SIPMessage + implements javax.sip.message.Response, ResponseExt { + protected StatusLine statusLine; + + public static String getReasonPhrase(int rc) { + String retval = null; + switch (rc) { + + case TRYING : + retval = "Trying"; + break; + + case RINGING : + retval = "Ringing"; + break; + + case CALL_IS_BEING_FORWARDED : + retval = "Call is being forwarded"; + break; + + case QUEUED : + retval = "Queued"; + break; + + case SESSION_PROGRESS : + retval = "Session progress"; + break; + + case OK : + retval = "OK"; + break; + + case ACCEPTED : + retval = "Accepted"; + break; + + case MULTIPLE_CHOICES : + retval = "Multiple choices"; + break; + + case MOVED_PERMANENTLY : + retval = "Moved permanently"; + break; + + case MOVED_TEMPORARILY : + retval = "Moved Temporarily"; + break; + + case USE_PROXY : + retval = "Use proxy"; + break; + + case ALTERNATIVE_SERVICE : + retval = "Alternative service"; + break; + + case BAD_REQUEST : + retval = "Bad request"; + break; + + case UNAUTHORIZED : + retval = "Unauthorized"; + break; + + case PAYMENT_REQUIRED : + retval = "Payment required"; + break; + + case FORBIDDEN : + retval = "Forbidden"; + break; + + case NOT_FOUND : + retval = "Not found"; + break; + + case METHOD_NOT_ALLOWED : + retval = "Method not allowed"; + break; + + case NOT_ACCEPTABLE : + retval = "Not acceptable"; + break; + + case PROXY_AUTHENTICATION_REQUIRED : + retval = "Proxy Authentication required"; + break; + + case REQUEST_TIMEOUT : + retval = "Request timeout"; + break; + + case GONE : + retval = "Gone"; + break; + + case TEMPORARILY_UNAVAILABLE : + retval = "Temporarily Unavailable"; + break; + + case REQUEST_ENTITY_TOO_LARGE : + retval = "Request entity too large"; + break; + + case REQUEST_URI_TOO_LONG : + retval = "Request-URI too large"; + break; + + case UNSUPPORTED_MEDIA_TYPE : + retval = "Unsupported media type"; + break; + + case UNSUPPORTED_URI_SCHEME : + retval = "Unsupported URI Scheme"; + break; + + case BAD_EXTENSION : + retval = "Bad extension"; + break; + + case EXTENSION_REQUIRED : + retval = "Etension Required"; + break; + + case INTERVAL_TOO_BRIEF : + retval = "Interval too brief"; + break; + + case CALL_OR_TRANSACTION_DOES_NOT_EXIST : + retval = "Call leg/Transaction does not exist"; + break; + + case LOOP_DETECTED : + retval = "Loop detected"; + break; + + case TOO_MANY_HOPS : + retval = "Too many hops"; + break; + + case ADDRESS_INCOMPLETE : + retval = "Address incomplete"; + break; + + case AMBIGUOUS : + retval = "Ambiguous"; + break; + + case BUSY_HERE : + retval = "Busy here"; + break; + + case REQUEST_TERMINATED : + retval = "Request Terminated"; + break; + + //Issue 168, Typo fix reported by fre on the retval + case NOT_ACCEPTABLE_HERE : + retval = "Not Acceptable here"; + break; + + case BAD_EVENT : + retval = "Bad Event"; + break; + + case REQUEST_PENDING : + retval = "Request Pending"; + break; + + case SERVER_INTERNAL_ERROR : + retval = "Server Internal Error"; + break; + + case UNDECIPHERABLE : + retval = "Undecipherable"; + break; + + case NOT_IMPLEMENTED : + retval = "Not implemented"; + break; + + case BAD_GATEWAY : + retval = "Bad gateway"; + break; + + case SERVICE_UNAVAILABLE : + retval = "Service unavailable"; + break; + + case SERVER_TIMEOUT : + retval = "Gateway timeout"; + break; + + case VERSION_NOT_SUPPORTED : + retval = "SIP version not supported"; + break; + + case MESSAGE_TOO_LARGE : + retval = "Message Too Large"; + break; + + case BUSY_EVERYWHERE : + retval = "Busy everywhere"; + break; + + case DECLINE : + retval = "Decline"; + break; + + case DOES_NOT_EXIST_ANYWHERE : + retval = "Does not exist anywhere"; + break; + + case SESSION_NOT_ACCEPTABLE : + retval = "Session Not acceptable"; + break; + + case CONDITIONAL_REQUEST_FAILED: + retval = "Conditional request failed"; + break; + + default : + retval = "Unknown Status"; + + } + return retval; + + } + + /** set the status code. + *@param statusCode is the status code to set. + *@throws IlegalArgumentException if invalid status code. + */ + public void setStatusCode(int statusCode) throws ParseException { + + // RFC3261 defines statuscode as 3DIGIT, 606 is the highest officially + // defined code but extensions may add others (in theory up to 999, + // but in practice up to 699 since the 6xx range is defined as 'final error') + if (statusCode < 100 || statusCode > 699) + throw new ParseException("bad status code", 0); + if (this.statusLine == null) + this.statusLine = new StatusLine(); + this.statusLine.setStatusCode(statusCode); + } + + /** + * Get the status line of the response. + *@return StatusLine + */ + public StatusLine getStatusLine() { + return statusLine; + } + + /** Get the staus code (conveniance function). + *@return the status code of the status line. + */ + public int getStatusCode() { + return statusLine.getStatusCode(); + } + + /** Set the reason phrase. + *@param reasonPhrase the reason phrase. + *@throws IllegalArgumentException if null string + */ + public void setReasonPhrase(String reasonPhrase) { + if (reasonPhrase == null) + throw new IllegalArgumentException("Bad reason phrase"); + if (this.statusLine == null) + this.statusLine = new StatusLine(); + this.statusLine.setReasonPhrase(reasonPhrase); + } + + /** Get the reason phrase. + *@return the reason phrase. + */ + public String getReasonPhrase() { + if (statusLine == null || statusLine.getReasonPhrase() == null) + return ""; + else + return statusLine.getReasonPhrase(); + } + + /** Return true if the response is a final response. + *@param rc is the return code. + *@return true if the parameter is between the range 200 and 700. + */ + public static boolean isFinalResponse(int rc) { + return rc >= 200 && rc < 700; + } + + /** Is this a final response? + *@return true if this is a final response. + */ + public boolean isFinalResponse() { + return isFinalResponse(statusLine.getStatusCode()); + } + + /** + * Set the status line field. + *@param sl Status line to set. + */ + public void setStatusLine(StatusLine sl) { + statusLine = sl; + } + + /** Constructor. + */ + public SIPResponse() { + super(); + } + /** + * Print formatting function. + *Indent and parenthesize for pretty printing. + * Note -- use the encode method for formatting the message. + * Hack here to XMLize. + * + *@return a string for pretty printing. + */ + public String debugDump() { + String superstring = super.debugDump(); + stringRepresentation = ""; + sprint(SIPResponse.class.getCanonicalName()); + sprint("{"); + if (statusLine != null) { + sprint(statusLine.debugDump()); + } + sprint(superstring); + sprint("}"); + return stringRepresentation; + } + + /** + * Check the response structure. Must have from, to CSEQ and VIA + * headers. + */ + public void checkHeaders() throws ParseException { + if (getCSeq() == null) { + throw new ParseException(CSeq.NAME+ " Is missing ", 0); + } + if (getTo() == null) { + throw new ParseException(To.NAME+ " Is missing ", 0); + } + if (getFrom() == null) { + throw new ParseException(From.NAME+ " Is missing ", 0); + } + if (getViaHeaders() == null) { + throw new ParseException(Via.NAME+ " Is missing ", 0); + } + if (getCallId() == null) { + throw new ParseException(CallID.NAME + " Is missing ", 0); + } + + + if (getStatusCode() > 699) { + throw new ParseException("Unknown error code!" + getStatusCode(), 0); + } + + } + + /** + * Encode the SIP Request as a string. + *@return The string encoded canonical form of the message. + */ + + public String encode() { + String retval; + if (statusLine != null) + retval = statusLine.encode() + super.encode(); + else + retval = super.encode(); + return retval ; + } + + /** Encode the message except for the body. + * + *@return The string except for the body. + */ + + public String encodeMessage() { + String retval; + if (statusLine != null) + retval = statusLine.encode() + super.encodeSIPHeaders(); + else + retval = super.encodeSIPHeaders(); + return retval ; + } + + + + /** Get this message as a list of encoded strings. + *@return LinkedList containing encoded strings for each header in + * the message. + */ + + public LinkedList getMessageAsEncodedStrings() { + LinkedList retval = super.getMessageAsEncodedStrings(); + + if (statusLine != null) + retval.addFirst(statusLine.encode()); + return retval; + + } + + /** + * Make a clone (deep copy) of this object. + *@return a deep copy of this object. + */ + + public Object clone() { + SIPResponse retval = (SIPResponse) super.clone(); + if (this.statusLine != null) + retval.statusLine = (StatusLine) this.statusLine.clone(); + return retval; + } + + + /** + * Compare for equality. + *@param other other object to compare with. + */ + public boolean equals(Object other) { + if (!this.getClass().equals(other.getClass())) + return false; + SIPResponse that = (SIPResponse) other; + return statusLine.equals(that.statusLine) && super.equals(other); + } + + /** + * Match with a template. + *@param matchObj template object to match ourselves with (null + * in any position in the template object matches wildcard) + */ + public boolean match(Object matchObj) { + if (matchObj == null) + return true; + else if (!matchObj.getClass().equals(this.getClass())) { + return false; + } else if (matchObj == this) + return true; + SIPResponse that = (SIPResponse) matchObj; + + StatusLine rline = that.statusLine; + if (this.statusLine == null && rline != null) + return false; + else if (this.statusLine == rline) + return super.match(matchObj); + else { + + return statusLine.match(that.statusLine) && super.match(matchObj); + } + + } + + /** Encode this into a byte array. + * This is used when the body has been set as a binary array + * and you want to encode the body as a byte array for transmission. + * + *@return a byte array containing the SIPRequest encoded as a byte + * array. + */ + + public byte[] encodeAsBytes( String transport ) { + byte[] slbytes = null; + if (statusLine != null) { + try { + slbytes = statusLine.encode().getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + InternalErrorHandler.handleException(ex); + } + } + byte[] superbytes = super.encodeAsBytes( transport ); + byte[] retval = new byte[slbytes.length + superbytes.length]; + System.arraycopy(slbytes, 0, retval, 0, slbytes.length); + System.arraycopy(superbytes, 0, retval, slbytes.length, + superbytes.length); + return retval; + } + + + + /** Get a dialog identifier. + * Generates a string that can be used as a dialog identifier. + * + * @param isServer is set to true if this is the UAS + * and set to false if this is the UAC + */ + public String getDialogId(boolean isServer) { + CallID cid = (CallID) this.getCallId(); + From from = (From) this.getFrom(); + To to = (To) this.getTo(); + StringBuffer retval = new StringBuffer(cid.getCallId()); + if (!isServer) { + //retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + //retval.append(COLON).append(to.getUserAtHostPort()); + if (to.getTag() != null) { + retval.append(COLON); + retval.append(to.getTag()); + } + } else { + //retval.append(COLON).append(to.getUserAtHostPort()); + if (to.getTag() != null) { + retval.append(COLON); + retval.append(to.getTag()); + } + //retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + } + return retval.toString().toLowerCase(); + } + + public String getDialogId(boolean isServer, String toTag) { + CallID cid = (CallID) this.getCallId(); + From from = (From) this.getFrom(); + StringBuffer retval = new StringBuffer(cid.getCallId()); + if (!isServer) { + //retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + //retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + retval.append(COLON); + retval.append(toTag); + } + } else { + //retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + retval.append(COLON); + retval.append(toTag); + } + //retval.append(COLON).append(from.getUserAtHostPort()); + if (from.getTag() != null) { + retval.append(COLON); + retval.append(from.getTag()); + } + } + return retval.toString().toLowerCase(); + } + + /** + * Sets the Via branch for CANCEL or ACK requests + * + * @param via + * @param method + * @throws ParseException + */ + private final void setBranch( Via via, String method ) { + String branch; + if (method.equals( Request.ACK ) ) { + if (statusLine.getStatusCode() >= 300 ) { + branch = getTopmostVia().getBranch(); // non-2xx ACK uses same branch + } else { + branch = Utils.getInstance().generateBranchId(); // 2xx ACK gets new branch + } + } else if (method.equals( Request.CANCEL )) { + branch = getTopmostVia().getBranch(); // CANCEL uses same branch + } else return; + + try { + via.setBranch( branch ); + } catch (ParseException e) { + e.printStackTrace(); + } + } + + + /** + * Get the encoded first line. + * + *@return the status line encoded. + * + */ + public String getFirstLine() { + if (this.statusLine == null) + return null; + else + return this.statusLine.encode(); + } + + public void setSIPVersion(String sipVersion) { + this.statusLine.setSipVersion(sipVersion); + } + + public String getSIPVersion() { + return this.statusLine.getSipVersion(); + } + + public String toString() { + if (statusLine == null) return ""; + else return statusLine.encode() + super.encode(); + } + + /** + * Generate a request from a response. + * + * @param requestURI -- the request URI to assign to the request. + * @param via -- the Via header to assign to the request + * @param cseq -- the CSeq header to assign to the request + * @param from -- the From header to assign to the request + * @param to -- the To header to assign to the request + * @return -- the newly generated sip request. + */ + public SIPRequest createRequest(SipUri requestURI, Via via, CSeq cseq, From from, To to) { + SIPRequest newRequest = new SIPRequest(); + String method = cseq.getMethod(); + + newRequest.setMethod(method); + newRequest.setRequestURI(requestURI); + this.setBranch( via, method ); + newRequest.setHeader(via); + newRequest.setHeader(cseq); + Iterator headerIterator = getHeaders(); + while (headerIterator.hasNext()) { + SIPHeader nextHeader = (SIPHeader) headerIterator.next(); + // Some headers do not belong in a Request .... + if (SIPMessage.isResponseHeader(nextHeader) + || nextHeader instanceof ViaList + || nextHeader instanceof CSeq + || nextHeader instanceof ContentType + || nextHeader instanceof ContentLength + || nextHeader instanceof RecordRouteList + || nextHeader instanceof RequireList + || nextHeader instanceof ContactList // JvB: added + || nextHeader instanceof ContentLength + || nextHeader instanceof ServerHeader + || nextHeader instanceof ReasonHeader + || nextHeader instanceof SessionExpires + || nextHeader instanceof ReasonList) { + continue; + } + if (nextHeader instanceof To) + nextHeader = (SIPHeader) to; + else if (nextHeader instanceof From) + nextHeader = (SIPHeader) from; + try { + newRequest.attachHeader(nextHeader, false); + } catch (SIPDuplicateHeaderException e) { + //Should not happen! + e.printStackTrace(); + } + } + + try { + // JvB: all requests need a Max-Forwards + newRequest.attachHeader( new MaxForwards(70), false); + } catch (Exception d) { + + } + + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { + newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + } + return newRequest; + + } +} diff --git a/java/gov/nist/javax/sip/message/package.html b/java/gov/nist/javax/sip/message/package.html new file mode 100644 index 0000000..5488c74 --- /dev/null +++ b/java/gov/nist/javax/sip/message/package.html @@ -0,0 +1,4 @@ + +<body> +Class definitions for SIP messages and message factory. +</body> diff --git a/java/gov/nist/javax/sip/package.html b/java/gov/nist/javax/sip/package.html new file mode 100644 index 0000000..f700dc7 --- /dev/null +++ b/java/gov/nist/javax/sip/package.html @@ -0,0 +1,42 @@ +<body> +This is the root of the JAIN implementation of SIP. It contains an +implementation of the Provider, Listener and Stack. Implementation of the +headers is contained in header and implementation of the parser in the +parser subdirectory. The SIP Protocol specific abstractions are implemented +in the stack subdirectory. + +<p> +The RI contains several additional Features that are not required by the JAIN-SIP spec + and that can be enabled by RI-specific properties that are specified when the SipStack + is created. The purpose of these additional properties is to enable the following: + +<ul> +<li> Message Logging features - permits the application to log messages in +a format that are suitable for trace viewing using the trace viewer facility. +<li> TCP starvation attack prevention - Limit the size and timeout for + tcp connections. +<li> UDP Flooding attack prevention -- limit the size of queues and transaction + table size. +<li> TCP message size limitation -- limit the size of TCP messages to prevent +TCP flooding attacks. +<li> Connection caching and reuse for TCP connections -- reduce latency by re-using + TCP connections on client and server transactions. +<li> Address resolution -- resolve addresses that are not direct DNS lookups or IP addresses + using a custom address resolver. +<li> Network Layer -- allows your application code to have direct access to the + Sockets that are used by the stack (use this feature with caution!). +</li> +</ul> + +See the javadoc for gov.nist.javax.sip.SipStackImpl for a detailed explanation of +these features. + +<p> +The interfaces that are suffixed with Ext in this package will not be altered and will +be included in the next specification revision. These are provided here for those who +wish to use these extensions and do not want to wait until the next spec revision +becomes available. + +</body> + +</a> diff --git a/java/gov/nist/javax/sip/parser/AcceptEncodingParser.java b/java/gov/nist/javax/sip/parser/AcceptEncodingParser.java new file mode 100644 index 0000000..c85de3c --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AcceptEncodingParser.java @@ -0,0 +1,205 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Accept-Encoding SIP (HTTP) Header parser. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:56 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + * + * <pre> + * + * The Accept-Encoding request-header field is similar to Accept, but + * restricts the content-codings (section 3.5) that are acceptable in + * the response. + * + * + * Accept-Encoding = "Accept-Encoding" ":" + * ( encoding *( "," encoding) ) + * encoding = ( codings *[ ";" "q" "=" qvalue ] ) + * codings = ( content-coding | "*" ) + * + * Examples of its use are: + * + * Accept-Encoding: compress, gzip + * Accept-Encoding: + * Accept-Encoding: * + * Accept-Encoding: compress;q=0.5, gzip;q=1.0 + * Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 + * </pre> + * + */ +public class AcceptEncodingParser extends HeaderParser { + + /** + * Constructor + * @param acceptEncoding message to parse + */ + public AcceptEncodingParser(String acceptEncoding) { + super(acceptEncoding); + } + + /** + * Constructor + * @param lexer Lexer to set + */ + protected AcceptEncodingParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (AcceptEncoding object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + AcceptEncodingList acceptEncodingList = new AcceptEncodingList(); + if (debug) + dbg_enter("AcceptEncodingParser.parse"); + + try { + headerName(TokenTypes.ACCEPT_ENCODING); + // empty body is fine for this header. + if (lexer.lookAhead(0) == '\n') { + AcceptEncoding acceptEncoding = new AcceptEncoding(); + acceptEncodingList.add(acceptEncoding); + } else { + while (lexer.lookAhead(0) != '\n') { + AcceptEncoding acceptEncoding = new AcceptEncoding(); + if (lexer.lookAhead(0) != ';') { + // Content-Coding: + lexer.match(TokenTypes.ID); + Token value = lexer.getNextToken(); + acceptEncoding.setEncoding(value.getTokenValue()); + } + + while (lexer.lookAhead(0) == ';') { + this.lexer.match(';'); + this.lexer.SPorHT(); + this.lexer.match('q'); + this.lexer.SPorHT(); + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token value = lexer.getNextToken(); + try { + float qv = Float.parseFloat(value.getTokenValue()); + acceptEncoding.setQValue(qv); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + } + + acceptEncodingList.add(acceptEncoding); + if (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } + + } + } + return acceptEncodingList; + } finally { + if (debug) + dbg_leave("AcceptEncodingParser.parse"); + } + } +} +/* + * $Log: AcceptEncodingParser.java,v $ + * Revision 1.7 2009/07/17 18:57:56 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:03 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AcceptLanguageParser.java b/java/gov/nist/javax/sip/parser/AcceptLanguageParser.java new file mode 100644 index 0000000..14720dd --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AcceptLanguageParser.java @@ -0,0 +1,206 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * AcceptLanguageParser.java + * + * Created on June 10, 2002, 3:31 PM + */ + +package gov.nist.javax.sip.parser; +import gov.nist.core.*; +import gov.nist.javax.sip.header.*; +import javax.sip.*; +import java.text.ParseException; + + +/** + * Parser for Accept Language Headers. + * + * Accept Language body. + * <pre> + * + * Accept-Language = "Accept-Language" ":" + * 1#( language-range [ ";" "q" "=" qvalue ] ) + * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) + * + * HTTP RFC 2616 Section 14.4 + * </pre> + * + * Accept-Language: da, en-gb;q=0.8, en;q=0.7 + * + * @see AcceptLanguageList + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:56 $ + * + * @author Olivier Deruelle + * + */ +public class AcceptLanguageParser extends HeaderParser { + + /** + * Constructor + * @param acceptLanguage AcceptLanguage message to parse + */ + public AcceptLanguageParser(String acceptLanguage) { + super(acceptLanguage); + } + + /** + * Constructor + * @param lexer Lexer to set + */ + protected AcceptLanguageParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (AcceptLanguage object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + AcceptLanguageList acceptLanguageList = new AcceptLanguageList(); + if (debug) + dbg_enter("AcceptLanguageParser.parse"); + + try { + headerName(TokenTypes.ACCEPT_LANGUAGE); + + while (lexer.lookAhead(0) != '\n') { + AcceptLanguage acceptLanguage = new AcceptLanguage(); + acceptLanguage.setHeaderName(SIPHeaderNames.ACCEPT_LANGUAGE); + if (lexer.lookAhead(0) != ';') { + // Content-Coding: + lexer.match(TokenTypes.ID); + Token value = lexer.getNextToken(); + acceptLanguage.setLanguageRange(value.getTokenValue()); + } + + while (lexer.lookAhead(0) == ';') { + this.lexer.match(';'); + this.lexer.SPorHT(); + this.lexer.match('q'); + this.lexer.SPorHT(); + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token value = lexer.getNextToken(); + try { + float fl = Float.parseFloat(value.getTokenValue()); + acceptLanguage.setQValue(fl); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + } + + acceptLanguageList.add(acceptLanguage); + if (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else + this.lexer.SPorHT(); + + } + } finally { + if (debug) + dbg_leave("AcceptLanguageParser.parse"); + } + + return acceptLanguageList; + } +} +/* + * $Log: AcceptLanguageParser.java,v $ + * Revision 1.8 2009/07/17 18:57:56 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:11 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AcceptParser.java b/java/gov/nist/javax/sip/parser/AcceptParser.java new file mode 100644 index 0000000..ed0c784 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AcceptParser.java @@ -0,0 +1,178 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Accept header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:56 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan <br/> + * + * + */ +public class AcceptParser extends ParametersParser { + + /** + * Creates a new instance of Accept Parser + * @param accept the header to parse + */ + public AcceptParser(String accept) { + super(accept); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected AcceptParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the Accept String header + * @return SIPHeader (AcceptList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AcceptParser.parse"); + AcceptList list = new AcceptList(); + + try { + headerName(TokenTypes.ACCEPT); + + Accept accept = new Accept(); + accept.setHeaderName(SIPHeaderNames.ACCEPT); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + accept.setContentType(token.getTokenValue()); + this.lexer.match('/'); + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + accept.setContentSubType(token.getTokenValue()); + this.lexer.SPorHT(); + + super.parse(accept); + list.add(accept); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + accept = new Accept(); + + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + accept.setContentType(token.getTokenValue()); + this.lexer.match('/'); + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + accept.setContentSubType(token.getTokenValue()); + this.lexer.SPorHT(); + super.parse(accept); + list.add(accept); + + } + return list; + } finally { + if (debug) + dbg_leave("AcceptParser.parse"); + } + } +} +/* + * $Log: AcceptParser.java,v $ + * Revision 1.7 2009/07/17 18:57:56 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AddressParametersParser.java b/java/gov/nist/javax/sip/parser/AddressParametersParser.java new file mode 100644 index 0000000..869c894 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AddressParametersParser.java @@ -0,0 +1,75 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.address.*; +import java.text.ParseException; + +/** + * Address parameters parser. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/10/22 10:25:57 $ + * @author M. Ranganathan + * @since 1.1 + * + */ +public class AddressParametersParser extends ParametersParser { + + protected AddressParametersParser(Lexer lexer) { + super(lexer); + } + + protected AddressParametersParser(String buffer) { + super(buffer); + } + + protected void parse(AddressParametersHeader addressParametersHeader) + throws ParseException { + dbg_enter("AddressParametersParser.parse"); + try { + AddressParser addressParser = new AddressParser(this.getLexer()); + AddressImpl addr = addressParser.address(false); + addressParametersHeader.setAddress(addr); + lexer.SPorHT(); + char la = this.lexer.lookAhead(0); + if ( this.lexer.hasMoreChars() && + la != '\0' && + la != '\n' && + this.lexer.startsId()) { + + super.parseNameValueList(addressParametersHeader); + + + } else super.parse(addressParametersHeader); + + } catch (ParseException ex) { + throw ex; + } finally { + dbg_leave("AddressParametersParser.parse"); + } + } +} diff --git a/java/gov/nist/javax/sip/parser/AddressParser.java b/java/gov/nist/javax/sip/parser/AddressParser.java new file mode 100644 index 0000000..f7be6e2 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AddressParser.java @@ -0,0 +1,216 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.address.*; +import java.text.ParseException; + +/** Parser for addresses. + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/10/22 10:26:27 $ + * @author M. Ranganathan + * + * + */ +public class AddressParser extends Parser { + + public AddressParser(Lexer lexer) { + this.lexer = lexer; + this.lexer.selectLexer("charLexer"); + } + + public AddressParser(String address) { + this.lexer = new Lexer("charLexer", address); + } + + protected AddressImpl nameAddr() throws ParseException { + if (debug) + dbg_enter("nameAddr"); + try { + if (this.lexer.lookAhead(0) == '<') { + this.lexer.consume(1); + this.lexer.selectLexer("sip_urlLexer"); + this.lexer.SPorHT(); + URLParser uriParser = new URLParser((Lexer) lexer); + GenericURI uri = uriParser.uriReference( true ); + AddressImpl retval = new AddressImpl(); + retval.setAddressType(AddressImpl.NAME_ADDR); + retval.setURI(uri); + this.lexer.SPorHT(); + this.lexer.match('>'); + return retval; + } else { + AddressImpl addr = new AddressImpl(); + addr.setAddressType(AddressImpl.NAME_ADDR); + String name = null; + if (this.lexer.lookAhead(0) == '\"') { + name = this.lexer.quotedString(); + this.lexer.SPorHT(); + } else + name = this.lexer.getNextToken('<'); + addr.setDisplayName(name.trim()); + this.lexer.match('<'); + this.lexer.SPorHT(); + URLParser uriParser = new URLParser((Lexer) lexer); + GenericURI uri = uriParser.uriReference( true ); + AddressImpl retval = new AddressImpl(); + addr.setAddressType(AddressImpl.NAME_ADDR); + addr.setURI(uri); + this.lexer.SPorHT(); + this.lexer.match('>'); + return addr; + } + } finally { + if (debug) + dbg_leave("nameAddr"); + } + } + + public AddressImpl address( boolean inclParams ) throws ParseException { + if (debug) + dbg_enter("address"); + AddressImpl retval = null; + try { + int k = 0; + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(k); + if (la == '<' + || la == '\"' + || la == ':' + || la == '/') + break; + else if (la == '\0') + throw createParseException("unexpected EOL"); + else + k++; + } + char la = lexer.lookAhead(k); + if (la == '<' || la == '\"') { + retval = nameAddr(); + } else if (la == ':' || la == '/') { + retval = new AddressImpl(); + URLParser uriParser = new URLParser((Lexer) lexer); + GenericURI uri = uriParser.uriReference( inclParams ); + retval.setAddressType(AddressImpl.ADDRESS_SPEC); + retval.setURI(uri); + } else { + throw createParseException("Bad address spec"); + } + return retval; + } finally { + if (debug) + dbg_leave("address"); + } + + } + + /* + + */ +} +/* + * $Log: AddressParser.java,v $ + * Revision 1.11 2009/10/22 10:26:27 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.10 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.9 2007/02/12 15:19:26 belangery + * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase. + * + * Revision 1.8 2007/02/06 16:40:02 belangery + * Introduced simple code optimizations. + * + * Revision 1.7 2006/07/13 09:01:57 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2006/03/08 23:32:54 mranga + * *** empty log message *** + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AlertInfoParser.java b/java/gov/nist/javax/sip/parser/AlertInfoParser.java new file mode 100644 index 0000000..18e96de --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AlertInfoParser.java @@ -0,0 +1,193 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.address.GenericURI; +import gov.nist.javax.sip.header.AlertInfo; +import gov.nist.javax.sip.header.AlertInfoList; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.SIPHeaderNames; + +import java.text.ParseException; + +/** + * Parser for AlertInfo header. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/07 23:35:49 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + */ +public class AlertInfoParser extends ParametersParser { + + /** + * Creates a new instance of AlertInfo Parser + * @param alertInfo the header to parse + */ + public AlertInfoParser(String alertInfo) { + super(alertInfo); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected AlertInfoParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the AlertInfo String header + * @return SIPHeader (AlertInfoList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AlertInfoParser.parse"); + AlertInfoList list = new AlertInfoList(); + + try { + headerName(TokenTypes.ALERT_INFO); + + while (lexer.lookAhead(0) != '\n') { + AlertInfo alertInfo = new AlertInfo(); + alertInfo.setHeaderName(SIPHeaderNames.ALERT_INFO); + URLParser urlParser; + GenericURI uri; + + do { + this.lexer.SPorHT(); + if (this.lexer.lookAhead(0) == '<') { + this.lexer.match('<'); + urlParser = new URLParser((Lexer) this.lexer); + uri = urlParser.uriReference( true ); + alertInfo.setAlertInfo(uri); + this.lexer.match('>'); + } else { + /* This is non standard for Polycom support. + * I know it is bad grammar but please do not remove. mranga + */ + String alertInfoStr = this.lexer.byteStringNoSemicolon(); + alertInfo.setAlertInfo(alertInfoStr); + } + + this.lexer.SPorHT(); + + super.parse(alertInfo); + list.add(alertInfo); + + if ( lexer.lookAhead(0) == ',' ) { + this.lexer.match(','); + } else break; + } while (true); + } + return list; + } finally { + if (debug) + dbg_leave("AlertInfoParser.parse"); + } + } +} +/* + * $Log: AlertInfoParser.java,v $ + * Revision 1.10 2009/11/07 23:35:49 mranga + * Fix Alert-Info ( loosen up parsing). Define AUTOMATIC_DIALOG_ERROR_HANDLING flag. + * + * Revision 1.9 2009/10/22 10:27:36 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.8 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2007/10/18 17:48:09 mranga + * Issue number: + * Obtained from: + * Submitted by: mardy + * Reviewed by: mranga + * Alert info patch to accept non standard alert info headers. + * + * Revision 1.6 2006/07/13 09:02:19 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AllowEventsParser.java b/java/gov/nist/javax/sip/parser/AllowEventsParser.java new file mode 100644 index 0000000..9adec6d --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AllowEventsParser.java @@ -0,0 +1,177 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for AllowEvents header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + * + */ +public class AllowEventsParser extends HeaderParser { + + /** + * Creates a new instance of AllowEventsParser + * @param allowEvents the header to parse + */ + public AllowEventsParser(String allowEvents) { + super(allowEvents); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected AllowEventsParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the AllowEvents String header + * @return SIPHeader (AllowEventsList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AllowEventsParser.parse"); + AllowEventsList list = new AllowEventsList(); + + try { + headerName(TokenTypes.ALLOW_EVENTS); + + AllowEvents allowEvents = new AllowEvents(); + allowEvents.setHeaderName(SIPHeaderNames.ALLOW_EVENTS); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + allowEvents.setEventType(token.getTokenValue()); + + list.add(allowEvents); + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + allowEvents = new AllowEvents(); + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + allowEvents.setEventType(token.getTokenValue()); + + list.add(allowEvents); + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return list; + } finally { + if (debug) + dbg_leave("AllowEventsParser.parse"); + } + } + + +} +/* + * $Log: AllowEventsParser.java,v $ + * Revision 1.8 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:01 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AllowParser.java b/java/gov/nist/javax/sip/parser/AllowParser.java new file mode 100644 index 0000000..c0d334f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AllowParser.java @@ -0,0 +1,176 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Allow header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + */ +public class AllowParser extends HeaderParser { + + /** + * Creates a new instance of AllowParser + * @param allow the header to parse + */ + public AllowParser(String allow) { + super(allow); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected AllowParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the Allow String header + * @return SIPHeader (AllowList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AllowParser.parse"); + AllowList list = new AllowList(); + + try { + headerName(TokenTypes.ALLOW); + + Allow allow = new Allow(); + allow.setHeaderName(SIPHeaderNames.ALLOW); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + allow.setMethod(token.getTokenValue()); + + list.add(allow); + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + allow = new Allow(); + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + allow.setMethod(token.getTokenValue()); + + list.add(allow); + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return list; + } finally { + if (debug) + dbg_leave("AllowParser.parse"); + } + } + + +} +/* + * $Log: AllowParser.java,v $ + * Revision 1.8 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:01:58 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AuthenticationInfoParser.java b/java/gov/nist/javax/sip/parser/AuthenticationInfoParser.java new file mode 100644 index 0000000..6d3574f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AuthenticationInfoParser.java @@ -0,0 +1,172 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Authentication-Info header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:57 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + */ +public class AuthenticationInfoParser extends ParametersParser { + + /** + * Creates a new instance of AuthenticationInfoParser + * @param authenticationInfo the header to parse + */ + public AuthenticationInfoParser(String authenticationInfo) { + super(authenticationInfo); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected AuthenticationInfoParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the AuthenticationInfo String header + * @return SIPHeader (AuthenticationInfoList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AuthenticationInfoParser.parse"); + + try { + headerName(TokenTypes.AUTHENTICATION_INFO); + + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + authenticationInfo.setHeaderName( + SIPHeaderNames.AUTHENTICATION_INFO); + + this.lexer.SPorHT(); + + NameValue nv = super.nameValue(); + authenticationInfo.setParameter(nv); + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + nv = super.nameValue(); + authenticationInfo.setParameter(nv); + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + //this.lexer.match('\n'); + + return authenticationInfo; + } finally { + if (debug) + dbg_leave("AuthenticationInfoParser.parse"); + } + } + + /* + + **/ +} +/* + * $Log: AuthenticationInfoParser.java,v $ + * Revision 1.9 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.8 2006/07/13 09:02:06 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.6 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.5 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/AuthorizationParser.java b/java/gov/nist/javax/sip/parser/AuthorizationParser.java new file mode 100644 index 0000000..7100d0c --- /dev/null +++ b/java/gov/nist/javax/sip/parser/AuthorizationParser.java @@ -0,0 +1,147 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for authorization headers. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + * + */ +public class AuthorizationParser extends ChallengeParser { + + /** + * Constructor + * @param authorization Authorization message to parse + */ + public AuthorizationParser(String authorization) { + super(authorization); + } + + /** + * Cosntructor + * @param lexer Lexer to set + */ + protected AuthorizationParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (Authorization object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + dbg_enter("parse"); + try { + headerName(TokenTypes.AUTHORIZATION); + Authorization auth = new Authorization(); + super.parse(auth); + return auth; + } finally { + dbg_leave("parse"); + } + } + + +} +/* + * $Log: AuthorizationParser.java,v $ + * Revision 1.8 2009/07/17 18:57:57 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:22 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/CSeqParser.java b/java/gov/nist/javax/sip/parser/CSeqParser.java new file mode 100644 index 0000000..823fae8 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/CSeqParser.java @@ -0,0 +1,204 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.message.SIPRequest; + +import java.text.ParseException; +import javax.sip.*; + +import gov.nist.core.*; + +/** + * Parser for CSeq headers. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2006/08/15 21:44:50 $ + * + * @author M. Ranganathan + * @author Olivier Deruelle + * + */ +public class CSeqParser extends HeaderParser { + + public CSeqParser(String cseq) { + super(cseq); + } + + protected CSeqParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + try { + CSeq c = new CSeq(); + + this.lexer.match(TokenTypes.CSEQ); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + String number = this.lexer.number(); + c.setSeqNumber(Long.parseLong(number)); + this.lexer.SPorHT(); + String m = SIPRequest.getCannonicalName( method() ); + + + + c.setMethod(m); + this.lexer.SPorHT(); + this.lexer.match('\n'); + return c; + } catch (NumberFormatException ex) { + Debug.printStackTrace(ex); + throw createParseException("Number format exception"); + } catch (InvalidArgumentException ex) { + Debug.printStackTrace(ex); + throw createParseException(ex.getMessage()); + } + } + + /** + * + */ +} +/* + * $Log: CSeqParser.java,v $ + * Revision 1.10 2006/08/15 21:44:50 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Incorporating the latest API changes from Phelim + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.9 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.5 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.4 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.3 2006/05/22 08:16:15 mranga + * Added tests for retransmissionAlert flag + * Added tests for transaction terminated event + * + * Revision 1.2 2006/04/17 17:45:01 jeroen + * - Using SIPRequest method to canonicalize request name (current code was omitting some) + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.7 2005/04/27 14:12:04 mranga + * Submitted by: Mario Mantak + * Reviewed by: mranga + * + * Added a missing "short form" for event header. + * + * Revision 1.6 2005/04/21 00:01:59 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * + * Adjust remote sequence number when sending out a 491 + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * Revision 1.5 2004/07/28 14:13:54 mranga Submitted + * by: mranga + * + * Move out the test code to a separate test/unit class. Fixed some encode + * methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker Issue number: Obtained from: + * Submitted by: sverker Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and + * javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: CVS: If this change addresses one or more issues, CVS: + * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change + * has been taken from another system, CVS: then name the system in this line, + * otherwise delete it. CVS: Submitted by: CVS: If this code has been + * contributed to the project by someone else; i.e., CVS: they sent us a patch + * or a set of diffs, then include their name/email CVS: address here. If this + * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing + * pre-commit code reviews and someone else has CVS: reviewed your changes, + * include their name(s) here. CVS: If you have not had it reviewed then delete + * this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/CallIDParser.java b/java/gov/nist/javax/sip/parser/CallIDParser.java new file mode 100644 index 0000000..71848ce --- /dev/null +++ b/java/gov/nist/javax/sip/parser/CallIDParser.java @@ -0,0 +1,158 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.*; + +/** Parser for CALL ID header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * + * @author M. Ranganathan + * @author Olivier Deruelle + * + */ +public class CallIDParser extends HeaderParser { + + /** + * Creates new CallIDParser + * @param callID message to parse + */ + public CallIDParser(String callID) { + super(callID); + } + + /** + * Constructor + * @param lexer Lexer to set + */ + protected CallIDParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (CallID object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + this.lexer.match(TokenTypes.CALL_ID); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + CallID callID = new CallID(); + + this.lexer.SPorHT(); + String rest = lexer.getRest(); + callID.setCallId(rest.trim()); + return callID; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + /* + + + } + */ +} +/* + * $Log: CallIDParser.java,v $ + * Revision 1.8 2009/07/17 18:57:58 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/CallInfoParser.java b/java/gov/nist/javax/sip/parser/CallInfoParser.java new file mode 100644 index 0000000..57b0b6c --- /dev/null +++ b/java/gov/nist/javax/sip/parser/CallInfoParser.java @@ -0,0 +1,185 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.address.*; +import java.text.ParseException; + +/** + * Parser for CallInfo header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/22 10:27:36 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + */ +public class CallInfoParser extends ParametersParser{ + + /** + * Creates a new instance of CallInfoParser + * @param callInfo the header to parse + */ + public CallInfoParser(String callInfo) { + super(callInfo); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected CallInfoParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the CallInfo String header + * @return SIPHeader (CallInfoList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) dbg_enter("CallInfoParser.parse"); + CallInfoList list=new CallInfoList(); + + try { + headerName(TokenTypes.CALL_INFO); + + while (lexer.lookAhead(0) != '\n') { + CallInfo callInfo= new CallInfo(); + callInfo.setHeaderName(SIPHeaderNames.CALL_INFO); + + this.lexer.SPorHT(); + this.lexer.match('<'); + URLParser urlParser=new URLParser((Lexer)this.lexer); + GenericURI uri=urlParser.uriReference(true); + callInfo.setInfo(uri); + this.lexer.match('>'); + this.lexer.SPorHT(); + + super.parse(callInfo); + list.add(callInfo); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + callInfo= new CallInfo(); + + this.lexer.SPorHT(); + this.lexer.match('<'); + urlParser=new URLParser((Lexer)this.lexer); + uri=urlParser.uriReference(true); + callInfo.setInfo(uri); + this.lexer.match('>'); + this.lexer.SPorHT(); + + super.parse(callInfo); + list.add(callInfo); + } + } + + return list; + } + finally { + if (debug) dbg_leave("CallInfoParser.parse"); + } + } + + +} +/* + * $Log: CallInfoParser.java,v $ + * Revision 1.8 2009/10/22 10:27:36 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.7 2006/07/13 09:02:15 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:54 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ChallengeParser.java b/java/gov/nist/javax/sip/parser/ChallengeParser.java new file mode 100644 index 0000000..9382fa3 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ChallengeParser.java @@ -0,0 +1,109 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for the challenge portion of the authentication header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * @since 1.1 + * + * @author Olivier Deruelle <br/> + * + * + */ + +public abstract class ChallengeParser extends HeaderParser { + + /** + * Constructor + * @param String challenge message to parse to set + */ + protected ChallengeParser(String challenge) { + super(challenge); + } + + /** + * Constructor + * @param String challenge message to parse to set + */ + protected ChallengeParser(Lexer lexer) { + super(lexer); + } + + /** + * Get the parameter of the challenge string + * @return NameValue containing the parameter + */ + protected void parseParameter(AuthenticationHeader header) + throws ParseException { + + if (debug) + dbg_enter("parseParameter"); + try { + NameValue nv = this.nameValue('='); + header.setParameter(nv); + } finally { + if (debug) + dbg_leave("parseParameter"); + } + + } + + /** + * parser the String message. + * @param header - header structure to fill in. + * @throws ParseException if the message does not respect the spec. + */ + public void parse(AuthenticationHeader header) throws ParseException { + + // the Scheme: + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token type = lexer.getNextToken(); + this.lexer.SPorHT(); + header.setScheme(type.getTokenValue()); + + // The parameters: + try { + while (lexer.lookAhead(0) != '\n') { + this.parseParameter(header); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == '\n' || la == '\0') + break; + this.lexer.match(','); + this.lexer.SPorHT(); + } + } catch (ParseException ex) { + throw ex; + } + } +} diff --git a/java/gov/nist/javax/sip/parser/ContactParser.java b/java/gov/nist/javax/sip/parser/ContactParser.java new file mode 100644 index 0000000..b74ba89 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContactParser.java @@ -0,0 +1,85 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + * + */ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.ContactList; +import gov.nist.javax.sip.header.SIPHeader; + +import javax.sip.address.URI; +import java.text.ParseException; +import java.util.HashSet; +import java.util.Iterator; + +/** + * A parser for The SIP contact header. + * + * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/22 10:27:37 $ + * @since 1.1 + */ +public class ContactParser extends AddressParametersParser { + + public ContactParser(String contact) { + super(contact); + } + + protected ContactParser(Lexer lexer) { + super(lexer); + this.lexer = lexer; + } + + public SIPHeader parse() throws ParseException { + // past the header name and the colon. + headerName(TokenTypes.CONTACT); + ContactList retval = new ContactList(); + while (true) { + Contact contact = new Contact(); + if (lexer.lookAhead(0) == '*') { + final char next = lexer.lookAhead(1); + if (next == ' ' || next == '\t' || next == '\r' || next == '\n') { + this.lexer.match('*'); + contact.setWildCardFlag(true); + } else { + super.parse(contact); + } + } else { + super.parse(contact); + } + retval.add(contact); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (la == '\n' || la == '\0') + break; + else + throw createParseException("unexpected char"); + } + return retval; + } + +} diff --git a/java/gov/nist/javax/sip/parser/ContentDispositionParser.java b/java/gov/nist/javax/sip/parser/ContentDispositionParser.java new file mode 100644 index 0000000..b1fc908 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContentDispositionParser.java @@ -0,0 +1,167 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for ContentLanguage header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ContentDispositionParser extends ParametersParser { + + /** + * Creates a new instance of ContentDispositionParser + * @param contentDisposition the header to parse + */ + public ContentDispositionParser(String contentDisposition) { + super(contentDisposition); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ContentDispositionParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the ContentDispositionHeader String header + * @return SIPHeader (ContentDispositionList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ContentDispositionParser.parse"); + + try { + headerName(TokenTypes.CONTENT_DISPOSITION); + + ContentDisposition cd = new ContentDisposition(); + cd.setHeaderName(SIPHeaderNames.CONTENT_DISPOSITION); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + + Token token = lexer.getNextToken(); + cd.setDispositionType(token.getTokenValue()); + this.lexer.SPorHT(); + super.parse(cd); + + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return cd; + } catch (ParseException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("ContentDispositionParser.parse"); + } + } + + +} +/* + * $Log: ContentDispositionParser.java,v $ + * Revision 1.8 2009/07/17 18:57:58 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:15 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:55 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ContentEncodingParser.java b/java/gov/nist/javax/sip/parser/ContentEncodingParser.java new file mode 100644 index 0000000..326f994 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContentEncodingParser.java @@ -0,0 +1,182 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for ContentLanguage header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class ContentEncodingParser extends HeaderParser { + + /** + * Creates a new instance of ContentEncodingParser + * @param contentEncoding the header to parse + */ + public ContentEncodingParser(String contentEncoding) { + super(contentEncoding); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ContentEncodingParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the ContentEncodingHeader String header + * @return SIPHeader (ContentEncodingList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ContentEncodingParser.parse"); + ContentEncodingList list = new ContentEncodingList(); + + try { + headerName(TokenTypes.CONTENT_ENCODING); + + while (lexer.lookAhead(0) != '\n') { + ContentEncoding cl = new ContentEncoding(); + cl.setHeaderName(SIPHeaderNames.CONTENT_ENCODING); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + + Token token = lexer.getNextToken(); + cl.setEncoding(token.getTokenValue()); + + this.lexer.SPorHT(); + list.add(cl); + + while (lexer.lookAhead(0) == ',') { + cl = new ContentEncoding(); + this.lexer.match(','); + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + this.lexer.SPorHT(); + token = lexer.getNextToken(); + cl.setEncoding(token.getTokenValue()); + this.lexer.SPorHT(); + list.add(cl); + } + } + + return list; + } catch (ParseException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("ContentEncodingParser.parse"); + } + } + + +} +/* + * $Log: ContentEncodingParser.java,v $ + * Revision 1.8 2009/07/17 18:57:58 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:01:56 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:55 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ContentLanguageParser.java b/java/gov/nist/javax/sip/parser/ContentLanguageParser.java new file mode 100644 index 0000000..5eabc10 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContentLanguageParser.java @@ -0,0 +1,178 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for ContentLanguage header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ContentLanguageParser extends HeaderParser { + + /** + * Creates a new instance of ContentLanguageParser + * @param contentLanguage the header to parse + */ + public ContentLanguageParser(String contentLanguage) { + super(contentLanguage); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ContentLanguageParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the ContentLanguageHeader String header + * @return SIPHeader (ContentLanguageList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ContentLanguageParser.parse"); + ContentLanguageList list = new ContentLanguageList(); + + try { + headerName(TokenTypes.CONTENT_LANGUAGE); + + while (lexer.lookAhead(0) != '\n') { + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + + Token token = lexer.getNextToken(); + ContentLanguage cl = new ContentLanguage( token.getTokenValue() ); + this.lexer.SPorHT(); + list.add(cl); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + this.lexer.SPorHT(); + token = lexer.getNextToken(); + cl = new ContentLanguage( token.getTokenValue() ); + this.lexer.SPorHT(); + list.add(cl); + } + } + + return list; + } catch (ParseException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("ContentLanguageParser.parse"); + } + } + + +} +/* + * $Log: ContentLanguageParser.java,v $ + * Revision 1.8 2009/07/17 18:57:58 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:24 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2005/10/16 15:47:41 jeroen + * fixed language sub tag handling + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:55 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ContentLengthParser.java b/java/gov/nist/javax/sip/parser/ContentLengthParser.java new file mode 100644 index 0000000..3b68a6d --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContentLengthParser.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import javax.sip.*; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for Content-Length Header. + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + */ +public class ContentLengthParser extends HeaderParser { + + public ContentLengthParser(String contentLength) { + super(contentLength); + } + + protected ContentLengthParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("ContentLengthParser.enter"); + try { + ContentLength contentLength = new ContentLength(); + headerName(TokenTypes.CONTENT_LENGTH); + String number = this.lexer.number(); + contentLength.setContentLength(Integer.parseInt(number)); + this.lexer.SPorHT(); + this.lexer.match('\n'); + return contentLength; + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("ContentLengthParser.leave"); + } + } + + +} +/* + * $Log: ContentLengthParser.java,v $ + * Revision 1.8 2009/07/17 18:57:58 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:14 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/07/28 14:13:55 mranga + * Submitted by: mranga + * + * Move out the test code to a separate test/unit class. + * Fixed some encode methods. + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ContentTypeParser.java b/java/gov/nist/javax/sip/parser/ContentTypeParser.java new file mode 100644 index 0000000..6c46456 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ContentTypeParser.java @@ -0,0 +1,89 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/* + * ContentTypeParser.java + * + * Created on February 26, 2002, 2:42 PM + */ + +package gov.nist.javax.sip.parser; +import gov.nist.core.*; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for content type header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:59 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class ContentTypeParser extends ParametersParser { + + public ContentTypeParser(String contentType) { + super(contentType); + } + + protected ContentTypeParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + + ContentType contentType = new ContentType(); + if (debug) + dbg_enter("ContentTypeParser.parse"); + + try { + this.headerName(TokenTypes.CONTENT_TYPE); + + // The type: + lexer.match(TokenTypes.ID); + Token type = lexer.getNextToken(); + this.lexer.SPorHT(); + contentType.setContentType(type.getTokenValue()); + + // The sub-type: + lexer.match('/'); + lexer.match(TokenTypes.ID); + Token subType = lexer.getNextToken(); + this.lexer.SPorHT(); + contentType.setContentSubType(subType.getTokenValue()); + super.parse(contentType); + this.lexer.match('\n'); + } finally { + if (debug) + dbg_leave("ContentTypeParser.parse"); + } + return contentType; + + } + + +} + diff --git a/java/gov/nist/javax/sip/parser/DateParser.java b/java/gov/nist/javax/sip/parser/DateParser.java new file mode 100644 index 0000000..1898129 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/DateParser.java @@ -0,0 +1,84 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.header.*; +import java.util.*; +import java.text.ParseException; + +/** + * Parser for SIP Date field. Converts from SIP Date to the + * internal storage (Calendar) + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:59 $ + */ +public class DateParser extends HeaderParser { + + /** + * Constructor + * @param date message to parse to set + */ + public DateParser(String date) { + super(date); + } + + protected DateParser(Lexer lexer) { + super(lexer); + } + + /** + * Parse method. + * @throws ParseException + * @return the parsed Date header/ + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("DateParser.parse"); + try { + headerName(TokenTypes.DATE); + wkday(); + lexer.match(','); + lexer.match(' '); + Calendar cal = date(); + lexer.match(' '); + time(cal); + lexer.match(' '); + String tzone = this.lexer.ttoken().toLowerCase(); + if (!"gmt".equals(tzone)) + throw createParseException("Bad Time Zone " + tzone); + this.lexer.match('\n'); + SIPDateHeader retval = new SIPDateHeader(); + retval.setDate(cal); + return retval; + } finally { + if (debug) + dbg_leave("DateParser.parse"); + + } + + } + + +} diff --git a/java/gov/nist/javax/sip/parser/ErrorInfoParser.java b/java/gov/nist/javax/sip/parser/ErrorInfoParser.java new file mode 100644 index 0000000..ac16466 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ErrorInfoParser.java @@ -0,0 +1,176 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.address.*; +import java.text.ParseException; + +/** + * Parser for ErrorInfo header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/22 10:27:37 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ErrorInfoParser extends ParametersParser { + + /** + * Creates a new instance of ErrorInfoParser + * @param errorInfo the header to parse + */ + public ErrorInfoParser(String errorInfo) { + super(errorInfo); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ErrorInfoParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the ErrorInfo String header + * @return SIPHeader (ErrorInfoList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ErrorInfoParser.parse"); + ErrorInfoList list = new ErrorInfoList(); + + try { + headerName(TokenTypes.ERROR_INFO); + + while (lexer.lookAhead(0) != '\n') { + do { + ErrorInfo errorInfo = new ErrorInfo(); + errorInfo.setHeaderName(SIPHeaderNames.ERROR_INFO); + + this.lexer.SPorHT(); + this.lexer.match('<'); + URLParser urlParser = new URLParser((Lexer) this.lexer); + GenericURI uri = urlParser.uriReference( true ); + errorInfo.setErrorInfo(uri); + this.lexer.match('>'); + this.lexer.SPorHT(); + + super.parse(errorInfo); + list.add(errorInfo); + + if ( lexer.lookAhead(0) == ',' ) { + this.lexer.match(','); + } else break; + } while (true); + } + + return list; + } finally { + if (debug) + dbg_leave("ErrorInfoParser.parse"); + } + } + + +} +/* + * $Log: ErrorInfoParser.java,v $ + * Revision 1.9 2009/10/22 10:27:37 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.8 2009/07/17 18:57:59 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:43 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/EventParser.java b/java/gov/nist/javax/sip/parser/EventParser.java new file mode 100644 index 0000000..d0d6e19 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/EventParser.java @@ -0,0 +1,164 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Event header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:59 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class EventParser extends ParametersParser { + + /** + * Creates a new instance of EventParser + * @param event the header to parse + */ + public EventParser(String event) { + super(event); + } + + /** + * Cosntructor + * @param lexer the lexer to use to parse the header + */ + protected EventParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (Event object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("EventParser.parse"); + + try { + headerName(TokenTypes.EVENT); + this.lexer.SPorHT(); + + Event event = new Event(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + String value = token.getTokenValue(); + + event.setEventType(value); + super.parse(event); + + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return event; + + } catch (ParseException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("EventParser.parse"); + } + } + + +} +/* + * $Log: EventParser.java,v $ + * Revision 1.8 2009/07/17 18:57:59 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:14 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:43 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ExpiresParser.java b/java/gov/nist/javax/sip/parser/ExpiresParser.java new file mode 100644 index 0000000..a157283 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ExpiresParser.java @@ -0,0 +1,160 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for SIP Expires Parser. Converts from SIP Date to the + * internal storage (Calendar). + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:00 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class ExpiresParser extends HeaderParser { + + /** + * protected constructor. + * @param text is the text of the header to parse + */ + public ExpiresParser(String text) { + super(text); + } + + /** + * constructor. + * @param lexer is the lexer passed in from the enclosing parser. + */ + protected ExpiresParser(Lexer lexer) { + super(lexer); + } + + /** + * Parse the header. + */ + public SIPHeader parse() throws ParseException { + Expires expires = new Expires(); + if (debug) + dbg_enter("parse"); + try { + lexer.match(TokenTypes.EXPIRES); + lexer.SPorHT(); + lexer.match(':'); + lexer.SPorHT(); + String nextId = lexer.getNextId(); + lexer.match('\n'); + try { + int delta = Integer.parseInt(nextId); + expires.setExpires(delta); + return expires; + } catch (NumberFormatException ex) { + throw createParseException("bad integer format"); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + } finally { + if (debug) + dbg_leave("parse"); + } + + } + + + +} +/* + * $Log: ExpiresParser.java,v $ + * Revision 1.8 2009/07/17 18:58:00 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:12 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/FromParser.java b/java/gov/nist/javax/sip/parser/FromParser.java new file mode 100644 index 0000000..6067c24 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/FromParser.java @@ -0,0 +1,151 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.SIPHeader; + +import java.text.ParseException; + +/** From header parser. + * + * @version 1.2 $Revision: 1.12 $ $Date: 2009/10/22 10:27:37 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class FromParser extends AddressParametersParser { + + public FromParser(String from) { + super(from); + } + + protected FromParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + + From from = new From(); + + this.lexer.match(TokenTypes.FROM); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + super.parse(from); + this.lexer.match('\n'); + return from; + } + + +} +/* + * $Log: FromParser.java,v $ + * Revision 1.12 2009/10/22 10:27:37 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.11 2009/07/17 18:58:00 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.10 2007/10/23 17:34:55 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * + * Refactored header collections. + * + * Revision 1.9 2006/07/13 09:02:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.7 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.6 2004/04/22 22:51:17 mranga + * Submitted by: Thomas Froment + * Reviewed by: mranga + * + * Fixed corner cases. + * + * Revision 1.5 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/HeaderParser.java b/java/gov/nist/javax/sip/parser/HeaderParser.java new file mode 100644 index 0000000..3d1624f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/HeaderParser.java @@ -0,0 +1,190 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.util.*; +import java.text.ParseException; + +/** + * Generic header parser class. The parsers for various headers extend this + * class. To create a parser for a new header, extend this class and change + * the createParser class. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:00 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class HeaderParser extends Parser { + + /** + * Parse the weekday field + * @return an integer with the calendar content for wkday. + */ + protected int wkday() throws ParseException { + dbg_enter("wkday"); + try { + String tok = lexer.ttoken(); + String id = tok.toLowerCase(); + + if (TokenNames.MON.equalsIgnoreCase(id)) + return Calendar.MONDAY; + else if (TokenNames.TUE.equalsIgnoreCase(id)) + return Calendar.TUESDAY; + else if (TokenNames.WED.equalsIgnoreCase(id)) + return Calendar.WEDNESDAY; + else if (TokenNames.THU.equalsIgnoreCase(id)) + return Calendar.THURSDAY; + else if (TokenNames.FRI.equalsIgnoreCase(id)) + return Calendar.FRIDAY; + else if (TokenNames.SAT.equalsIgnoreCase(id)) + return Calendar.SATURDAY; + else if (TokenNames.SUN.equalsIgnoreCase(id)) + return Calendar.SUNDAY; + else + throw createParseException("bad wkday"); + } finally { + dbg_leave("wkday"); + } + + } + + /** + * parse and return a date field. + * @return a date structure with the parsed value. + */ + protected Calendar date() throws ParseException { + try { + Calendar retval = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + String s1 = lexer.number(); + int day = Integer.parseInt(s1); + if (day <= 0 || day > 31) + throw createParseException("Bad day "); + retval.set(Calendar.DAY_OF_MONTH, day); + lexer.match(' '); + String month = lexer.ttoken().toLowerCase(); + if (month.equals("jan")) { + retval.set(Calendar.MONTH, Calendar.JANUARY); + } else if (month.equals("feb")) { + retval.set(Calendar.MONTH, Calendar.FEBRUARY); + } else if (month.equals("mar")) { + retval.set(Calendar.MONTH, Calendar.MARCH); + } else if (month.equals("apr")) { + retval.set(Calendar.MONTH, Calendar.APRIL); + } else if (month.equals("may")) { + retval.set(Calendar.MONTH, Calendar.MAY); + } else if (month.equals("jun")) { + retval.set(Calendar.MONTH, Calendar.JUNE); + } else if (month.equals("jul")) { + retval.set(Calendar.MONTH, Calendar.JULY); + } else if (month.equals("aug")) { + retval.set(Calendar.MONTH, Calendar.AUGUST); + } else if (month.equals("sep")) { + retval.set(Calendar.MONTH, Calendar.SEPTEMBER); + } else if (month.equals("oct")) { + retval.set(Calendar.MONTH, Calendar.OCTOBER); + } else if (month.equals("nov")) { + retval.set(Calendar.MONTH, Calendar.NOVEMBER); + } else if (month.equals("dec")) { + retval.set(Calendar.MONTH, Calendar.DECEMBER); + } + lexer.match(' '); + String s2 = lexer.number(); + int yr = Integer.parseInt(s2); + retval.set(Calendar.YEAR, yr); + return retval; + + } catch (Exception ex) { + throw createParseException("bad date field"); + } + + } + + /** + * Set the time field. This has the format hour:minute:second + */ + protected void time(Calendar calendar) throws ParseException { + try { + String s = lexer.number(); + int hour = Integer.parseInt(s); + calendar.set(Calendar.HOUR_OF_DAY, hour); + lexer.match(':'); + s = lexer.number(); + int min = Integer.parseInt(s); + calendar.set(Calendar.MINUTE, min); + lexer.match(':'); + s = lexer.number(); + int sec = Integer.parseInt(s); + calendar.set(Calendar.SECOND, sec); + } catch (Exception ex) { + throw createParseException("error processing time "); + + } + + } + + /** + * Creates new HeaderParser + * @param String to parse. + */ + protected HeaderParser(String header) { + this.lexer = new Lexer("command_keywordLexer", header); + } + + protected HeaderParser(Lexer lexer) { + this.lexer = lexer; + this.lexer.selectLexer("command_keywordLexer"); + } + + /** + * Parse the SIP header from the buffer and return a parsed + * structure. + * @throws ParseException if there was an error parsing. + */ + public SIPHeader parse() throws ParseException { + String name = lexer.getNextToken(':'); + lexer.consume(1); + String body = lexer.getLine().trim(); + // we dont set any fields because the header is + // ok + ExtensionHeaderImpl retval = new ExtensionHeaderImpl(name); + retval.setValue(body); + return retval; + + } + + /** + * Parse the header name until the colon and chew WS after that. + */ + protected void headerName(int tok) throws ParseException { + this.lexer.match(tok); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + } +} diff --git a/java/gov/nist/javax/sip/parser/InReplyToParser.java b/java/gov/nist/javax/sip/parser/InReplyToParser.java new file mode 100644 index 0000000..42fdf3a --- /dev/null +++ b/java/gov/nist/javax/sip/parser/InReplyToParser.java @@ -0,0 +1,194 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for InReplyTo header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:00 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class InReplyToParser extends HeaderParser { + + /** + * Creates a new instance of InReplyToParser + * @param inReplyTo the header to parse + */ + public InReplyToParser(String inReplyTo) { + super(inReplyTo); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected InReplyToParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (InReplyToList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("InReplyToParser.parse"); + InReplyToList list = new InReplyToList(); + + try { + headerName(TokenTypes.IN_REPLY_TO); + + while (lexer.lookAhead(0) != '\n') { + InReplyTo inReplyTo = new InReplyTo(); + inReplyTo.setHeaderName(SIPHeaderNames.IN_REPLY_TO); + + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + if (lexer.lookAhead(0) == '@') { + this.lexer.match('@'); + this.lexer.match(TokenTypes.ID); + Token secToken = lexer.getNextToken(); + inReplyTo.setCallId( + token.getTokenValue() + "@" + secToken.getTokenValue()); + } else { + inReplyTo.setCallId(token.getTokenValue()); + } + + this.lexer.SPorHT(); + + list.add(inReplyTo); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + inReplyTo = new InReplyTo(); + + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + if (lexer.lookAhead(0) == '@') { + this.lexer.match('@'); + this.lexer.match(TokenTypes.ID); + Token secToken = lexer.getNextToken(); + inReplyTo.setCallId( + token.getTokenValue() + + "@" + + secToken.getTokenValue()); + } else { + inReplyTo.setCallId(token.getTokenValue()); + } + + list.add(inReplyTo); + } + } + + return list; + } finally { + if (debug) + dbg_leave("InReplyToParser.parse"); + } + } + + +} +/* + * $Log: InReplyToParser.java,v $ + * Revision 1.8 2009/07/17 18:58:00 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:18 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/Lexer.java b/java/gov/nist/javax/sip/parser/Lexer.java new file mode 100644 index 0000000..628d858 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/Lexer.java @@ -0,0 +1,324 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.parser; + +import gov.nist.core.*; + +import gov.nist.javax.sip.header.extensions.*; + +import gov.nist.javax.sip.header.ims.*; + +import javax.sip.header.*; +import java.util.Hashtable; + +/** + * Lexer class for the parser. + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + */ +public class Lexer extends LexerCore { + /** + * get the header name of the line + * + * @return the header name (stuff before the :) bug fix submitted by + * zvali@dev.java.net + */ + public static String getHeaderName(String line) { + if (line == null) + return null; + String headerName = null; + try { + int begin = line.indexOf(":"); + headerName = null; + if (begin >= 1) + headerName = line.substring(0, begin).trim(); + } catch (IndexOutOfBoundsException e) { + return null; + } + return headerName; + } + + public Lexer(String lexerName, String buffer) { + super(lexerName, buffer); + this.selectLexer(lexerName); + } + + /** + * get the header value of the line + * + * @return String + */ + public static String getHeaderValue(String line) { + if (line == null) + return null; + String headerValue = null; + try { + int begin = line.indexOf(":"); + headerValue = line.substring(begin + 1); + } catch (IndexOutOfBoundsException e) { + return null; + } + return headerValue; + } + + public void selectLexer(String lexerName) { + synchronized (lexerTables) { + // Synchronization Bug fix by Robert Rosen. + currentLexer = (Hashtable) lexerTables.get(lexerName); + this.currentLexerName = lexerName; + if (currentLexer == null) { + addLexer(lexerName); + if (lexerName.equals("method_keywordLexer")) { + addKeyword(TokenNames.REGISTER, TokenTypes.REGISTER); + addKeyword(TokenNames.ACK, TokenTypes.ACK); + addKeyword(TokenNames.OPTIONS, TokenTypes.OPTIONS); + addKeyword(TokenNames.BYE, TokenTypes.BYE); + addKeyword(TokenNames.INVITE, TokenTypes.INVITE); + addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP); + addKeyword(TokenNames.SIPS.toUpperCase(), TokenTypes.SIPS); + addKeyword(TokenNames.SUBSCRIBE, TokenTypes.SUBSCRIBE); + addKeyword(TokenNames.NOTIFY, TokenTypes.NOTIFY); + addKeyword(TokenNames.MESSAGE, TokenTypes.MESSAGE); + + // JvB: added to support RFC3903 + addKeyword(TokenNames.PUBLISH, TokenTypes.PUBLISH); + + } else if (lexerName.equals("command_keywordLexer")) { + addKeyword(ErrorInfoHeader.NAME.toUpperCase(), + TokenTypes.ERROR_INFO); + addKeyword(AllowEventsHeader.NAME.toUpperCase(), + TokenTypes.ALLOW_EVENTS); + addKeyword(AuthenticationInfoHeader.NAME.toUpperCase(), + TokenTypes.AUTHENTICATION_INFO); + addKeyword(EventHeader.NAME.toUpperCase(), TokenTypes.EVENT); + addKeyword(MinExpiresHeader.NAME.toUpperCase(), + TokenTypes.MIN_EXPIRES); + addKeyword(RSeqHeader.NAME.toUpperCase(), TokenTypes.RSEQ); + addKeyword(RAckHeader.NAME.toUpperCase(), TokenTypes.RACK); + addKeyword(ReasonHeader.NAME.toUpperCase(), + TokenTypes.REASON); + addKeyword(ReplyToHeader.NAME.toUpperCase(), + TokenTypes.REPLY_TO); + addKeyword(SubscriptionStateHeader.NAME.toUpperCase(), + TokenTypes.SUBSCRIPTION_STATE); + addKeyword(TimeStampHeader.NAME.toUpperCase(), + TokenTypes.TIMESTAMP); + addKeyword(InReplyToHeader.NAME.toUpperCase(), + TokenTypes.IN_REPLY_TO); + addKeyword(MimeVersionHeader.NAME.toUpperCase(), + TokenTypes.MIME_VERSION); + addKeyword(AlertInfoHeader.NAME.toUpperCase(), + TokenTypes.ALERT_INFO); + addKeyword(FromHeader.NAME.toUpperCase(), TokenTypes.FROM); + addKeyword(ToHeader.NAME.toUpperCase(), TokenTypes.TO); + addKeyword(ReferToHeader.NAME.toUpperCase(), + TokenTypes.REFER_TO); + addKeyword(ViaHeader.NAME.toUpperCase(), TokenTypes.VIA); + addKeyword(UserAgentHeader.NAME.toUpperCase(), + TokenTypes.USER_AGENT); + addKeyword(ServerHeader.NAME.toUpperCase(), + TokenTypes.SERVER); + addKeyword(AcceptEncodingHeader.NAME.toUpperCase(), + TokenTypes.ACCEPT_ENCODING); + addKeyword(AcceptHeader.NAME.toUpperCase(), + TokenTypes.ACCEPT); + addKeyword(AllowHeader.NAME.toUpperCase(), TokenTypes.ALLOW); + addKeyword(RouteHeader.NAME.toUpperCase(), TokenTypes.ROUTE); + addKeyword(AuthorizationHeader.NAME.toUpperCase(), + TokenTypes.AUTHORIZATION); + addKeyword(ProxyAuthorizationHeader.NAME.toUpperCase(), + TokenTypes.PROXY_AUTHORIZATION); + addKeyword(RetryAfterHeader.NAME.toUpperCase(), + TokenTypes.RETRY_AFTER); + addKeyword(ProxyRequireHeader.NAME.toUpperCase(), + TokenTypes.PROXY_REQUIRE); + addKeyword(ContentLanguageHeader.NAME.toUpperCase(), + TokenTypes.CONTENT_LANGUAGE); + addKeyword(UnsupportedHeader.NAME.toUpperCase(), + TokenTypes.UNSUPPORTED); + addKeyword(SupportedHeader.NAME.toUpperCase(), + TokenTypes.SUPPORTED); + addKeyword(WarningHeader.NAME.toUpperCase(), + TokenTypes.WARNING); + addKeyword(MaxForwardsHeader.NAME.toUpperCase(), + TokenTypes.MAX_FORWARDS); + addKeyword(DateHeader.NAME.toUpperCase(), TokenTypes.DATE); + addKeyword(PriorityHeader.NAME.toUpperCase(), + TokenTypes.PRIORITY); + addKeyword(ProxyAuthenticateHeader.NAME.toUpperCase(), + TokenTypes.PROXY_AUTHENTICATE); + addKeyword(ContentEncodingHeader.NAME.toUpperCase(), + TokenTypes.CONTENT_ENCODING); + addKeyword(ContentLengthHeader.NAME.toUpperCase(), + TokenTypes.CONTENT_LENGTH); + addKeyword(SubjectHeader.NAME.toUpperCase(), + TokenTypes.SUBJECT); + addKeyword(ContentTypeHeader.NAME.toUpperCase(), + TokenTypes.CONTENT_TYPE); + addKeyword(ContactHeader.NAME.toUpperCase(), + TokenTypes.CONTACT); + addKeyword(CallIdHeader.NAME.toUpperCase(), + TokenTypes.CALL_ID); + addKeyword(RequireHeader.NAME.toUpperCase(), + TokenTypes.REQUIRE); + addKeyword(ExpiresHeader.NAME.toUpperCase(), + TokenTypes.EXPIRES); + addKeyword(RecordRouteHeader.NAME.toUpperCase(), + TokenTypes.RECORD_ROUTE); + addKeyword(OrganizationHeader.NAME.toUpperCase(), + TokenTypes.ORGANIZATION); + addKeyword(CSeqHeader.NAME.toUpperCase(), TokenTypes.CSEQ); + addKeyword(AcceptLanguageHeader.NAME.toUpperCase(), + TokenTypes.ACCEPT_LANGUAGE); + addKeyword(WWWAuthenticateHeader.NAME.toUpperCase(), + TokenTypes.WWW_AUTHENTICATE); + addKeyword(CallInfoHeader.NAME.toUpperCase(), + TokenTypes.CALL_INFO); + addKeyword(ContentDispositionHeader.NAME.toUpperCase(), + TokenTypes.CONTENT_DISPOSITION); + // And now the dreaded short forms.... + addKeyword(TokenNames.K.toUpperCase(), TokenTypes.SUPPORTED); + addKeyword(TokenNames.C.toUpperCase(), + TokenTypes.CONTENT_TYPE); + addKeyword(TokenNames.E.toUpperCase(), + TokenTypes.CONTENT_ENCODING); + addKeyword(TokenNames.F.toUpperCase(), TokenTypes.FROM); + addKeyword(TokenNames.I.toUpperCase(), TokenTypes.CALL_ID); + addKeyword(TokenNames.M.toUpperCase(), TokenTypes.CONTACT); + addKeyword(TokenNames.L.toUpperCase(), + TokenTypes.CONTENT_LENGTH); + addKeyword(TokenNames.S.toUpperCase(), TokenTypes.SUBJECT); + addKeyword(TokenNames.T.toUpperCase(), TokenTypes.TO); + addKeyword(TokenNames.U.toUpperCase(), + TokenTypes.ALLOW_EVENTS); // JvB: added + addKeyword(TokenNames.V.toUpperCase(), TokenTypes.VIA); + addKeyword(TokenNames.R.toUpperCase(), TokenTypes.REFER_TO); + addKeyword(TokenNames.O.toUpperCase(), TokenTypes.EVENT); // Bug + // fix + // by + // Mario + // Mantak + addKeyword(TokenNames.X.toUpperCase(), TokenTypes.SESSIONEXPIRES_TO); // Bug fix by Jozef Saniga + + // JvB: added to support RFC3903 + addKeyword(SIPETagHeader.NAME.toUpperCase(), + TokenTypes.SIP_ETAG); + addKeyword(SIPIfMatchHeader.NAME.toUpperCase(), + TokenTypes.SIP_IF_MATCH); + + // pmusgrave: Add RFC4028 and ReferredBy + addKeyword(SessionExpiresHeader.NAME.toUpperCase(), + TokenTypes.SESSIONEXPIRES_TO); + addKeyword(MinSEHeader.NAME.toUpperCase(), + TokenTypes.MINSE_TO); + addKeyword(ReferredByHeader.NAME.toUpperCase(), + TokenTypes.REFERREDBY_TO); + + // pmusgrave RFC3891 + addKeyword(ReplacesHeader.NAME.toUpperCase(), + TokenTypes.REPLACES_TO); + //jean deruelle RFC3911 + addKeyword(JoinHeader.NAME.toUpperCase(), + TokenTypes.JOIN_TO); + + // IMS Headers + addKeyword(PathHeader.NAME.toUpperCase(), TokenTypes.PATH); + addKeyword(ServiceRouteHeader.NAME.toUpperCase(), + TokenTypes.SERVICE_ROUTE); + addKeyword(PAssertedIdentityHeader.NAME.toUpperCase(), + TokenTypes.P_ASSERTED_IDENTITY); + addKeyword(PPreferredIdentityHeader.NAME.toUpperCase(), + TokenTypes.P_PREFERRED_IDENTITY); + addKeyword(PrivacyHeader.NAME.toUpperCase(), + TokenTypes.PRIVACY); + + // issued by Miguel Freitas + addKeyword(PCalledPartyIDHeader.NAME.toUpperCase(), + TokenTypes.P_CALLED_PARTY_ID); + addKeyword(PAssociatedURIHeader.NAME.toUpperCase(), + TokenTypes.P_ASSOCIATED_URI); + addKeyword(PVisitedNetworkIDHeader.NAME.toUpperCase(), + TokenTypes.P_VISITED_NETWORK_ID); + addKeyword(PChargingFunctionAddressesHeader.NAME + .toUpperCase(), + TokenTypes.P_CHARGING_FUNCTION_ADDRESSES); + addKeyword(PChargingVectorHeader.NAME.toUpperCase(), + TokenTypes.P_VECTOR_CHARGING); + addKeyword(PAccessNetworkInfoHeader.NAME.toUpperCase(), + TokenTypes.P_ACCESS_NETWORK_INFO); + addKeyword(PMediaAuthorizationHeader.NAME.toUpperCase(), + TokenTypes.P_MEDIA_AUTHORIZATION); + + addKeyword(SecurityServerHeader.NAME.toUpperCase(), + TokenTypes.SECURITY_SERVER); + addKeyword(SecurityVerifyHeader.NAME.toUpperCase(), + TokenTypes.SECURITY_VERIFY); + addKeyword(SecurityClientHeader.NAME.toUpperCase(), + TokenTypes.SECURITY_CLIENT); + + // added by aayush@rancore + addKeyword(PUserDatabaseHeader.NAME.toUpperCase(), + TokenTypes.P_USER_DATABASE); + + // added by aayush@rancore + addKeyword(PProfileKeyHeader.NAME.toUpperCase(), + TokenTypes.P_PROFILE_KEY); + + // added by aayush@rancore + addKeyword(PServedUserHeader.NAME.toUpperCase(), + TokenTypes.P_SERVED_USER); + + // added by aayush@rancore + addKeyword(PPreferredServiceHeader.NAME.toUpperCase(), + TokenTypes.P_PREFERRED_SERVICE); + + // added by aayush@rancore + addKeyword(PAssertedServiceHeader.NAME.toUpperCase(), + TokenTypes.P_ASSERTED_SERVICE); + + // added References header + addKeyword(ReferencesHeader.NAME.toUpperCase(),TokenTypes.REFERENCES); + + // end // + + + } else if (lexerName.equals("status_lineLexer")) { + addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP); + } else if (lexerName.equals("request_lineLexer")) { + addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP); + } else if (lexerName.equals("sip_urlLexer")) { + addKeyword(TokenNames.TEL.toUpperCase(), TokenTypes.TEL); + addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP); + addKeyword(TokenNames.SIPS.toUpperCase(), TokenTypes.SIPS); + } + } + } + } +} diff --git a/java/gov/nist/javax/sip/parser/MaxForwardsParser.java b/java/gov/nist/javax/sip/parser/MaxForwardsParser.java new file mode 100644 index 0000000..d447cd8 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/MaxForwardsParser.java @@ -0,0 +1,141 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import javax.sip.*; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for Max Forwards Header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:00 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class MaxForwardsParser extends HeaderParser { + + public MaxForwardsParser(String contentLength) { + super(contentLength); + } + + protected MaxForwardsParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("MaxForwardsParser.enter"); + try { + MaxForwards contentLength = new MaxForwards(); + headerName(TokenTypes.MAX_FORWARDS); + String number = this.lexer.number(); + contentLength.setMaxForwards(Integer.parseInt(number)); + this.lexer.SPorHT(); + this.lexer.match('\n'); + return contentLength; + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } finally { + if (debug) + dbg_leave("MaxForwardsParser.leave"); + } + } + + +} +/* + * $Log: MaxForwardsParser.java,v $ + * Revision 1.7 2009/07/17 18:58:00 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:05 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.3 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/MimeVersionParser.java b/java/gov/nist/javax/sip/parser/MimeVersionParser.java new file mode 100644 index 0000000..14c641f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/MimeVersionParser.java @@ -0,0 +1,165 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for MimeVersion header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * +*/ +public class MimeVersionParser extends HeaderParser { + + /** + * Creates a new instance of MimeVersionParser + * @param mimeVersion the header to parse + */ + public MimeVersionParser(String mimeVersion) { + super(mimeVersion); + } + + /** + * Cosntructor + * @param lexer the lexer to use to parse the header + */ + protected MimeVersionParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (MimeVersion object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("MimeVersionParser.parse"); + MimeVersion mimeVersion = new MimeVersion(); + try { + headerName(TokenTypes.MIME_VERSION); + + mimeVersion.setHeaderName(SIPHeaderNames.MIME_VERSION); + + try { + String majorVersion = this.lexer.number(); + mimeVersion.setMajorVersion(Integer.parseInt(majorVersion)); + this.lexer.match('.'); + String minorVersion = this.lexer.number(); + mimeVersion.setMinorVersion(Integer.parseInt(minorVersion)); + + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + + this.lexer.match('\n'); + + return mimeVersion; + } finally { + if (debug) + dbg_leave("MimeVersionParser.parse"); + } + } + + +} +/* + * $Log: MimeVersionParser.java,v $ + * Revision 1.8 2009/07/17 18:58:01 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/MinExpiresParser.java b/java/gov/nist/javax/sip/parser/MinExpiresParser.java new file mode 100644 index 0000000..971ccc8 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/MinExpiresParser.java @@ -0,0 +1,162 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for MinExpires header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class MinExpiresParser extends HeaderParser { + + /** + * Creates a new instance of MinExpiresParser + * @param minExpires the header to parse + */ + public MinExpiresParser(String minExpires) { + super(minExpires); + } + + /** + * Cosntructor + * @param lexer the lexer to use to parse the header + */ + protected MinExpiresParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (MinExpiresParser) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("MinExpiresParser.parse"); + MinExpires minExpires = new MinExpires(); + try { + headerName(TokenTypes.MIN_EXPIRES); + + minExpires.setHeaderName(SIPHeaderNames.MIN_EXPIRES); + + String number = this.lexer.number(); + try { + minExpires.setExpires(Integer.parseInt(number)); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + + this.lexer.match('\n'); + + return minExpires; + } finally { + if (debug) + dbg_leave("MinExpiresParser.parse"); + } + } + + +} +/* + * $Log: MinExpiresParser.java,v $ + * Revision 1.8 2009/07/17 18:58:01 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:03 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2004/08/10 21:35:44 mranga + * Reviewed by: mranga + * move test cases out to another package + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/OrganizationParser.java b/java/gov/nist/javax/sip/parser/OrganizationParser.java new file mode 100644 index 0000000..a18748b --- /dev/null +++ b/java/gov/nist/javax/sip/parser/OrganizationParser.java @@ -0,0 +1,86 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** Parser for Organization header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class OrganizationParser extends HeaderParser { + + /** + * Creates a new instance of OrganizationParser + * @param organization the header to parse + */ + public OrganizationParser(String organization) { + super(organization); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected OrganizationParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String header + * @return SIPHeader (Organization object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("OrganizationParser.parse"); + Organization organization = new Organization(); + try { + headerName(TokenTypes.ORGANIZATION); + + organization.setHeaderName(SIPHeaderNames.ORGANIZATION); + + this.lexer.SPorHT(); + String value = this.lexer.getRest(); + + organization.setOrganization(value.trim()); + + return organization; + } finally { + if (debug) + dbg_leave("OrganizationParser.parse"); + } + } + + +} diff --git a/java/gov/nist/javax/sip/parser/ParametersParser.java b/java/gov/nist/javax/sip/parser/ParametersParser.java new file mode 100644 index 0000000..dce2697 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ParametersParser.java @@ -0,0 +1,80 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** parameters parser header. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:58:01 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public abstract class ParametersParser extends HeaderParser { + + protected ParametersParser(Lexer lexer) { + super((Lexer) lexer); + } + + protected ParametersParser(String buffer) { + super(buffer); + } + + protected void parse(ParametersHeader parametersHeader) + throws ParseException { + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ';') { + this.lexer.consume(1); + // eat white space + this.lexer.SPorHT(); + NameValue nv = nameValue(); + parametersHeader.setParameter(nv); + // eat white space + this.lexer.SPorHT(); + } + } + + + + protected void parseNameValueList(ParametersHeader parametersHeader) + throws ParseException{ + parametersHeader.removeParameters(); + while (true) { + this.lexer.SPorHT(); + NameValue nv = nameValue(); + parametersHeader.setParameter(nv.getName(), (String) nv.getValueAsObject()); + // eat white space + this.lexer.SPorHT(); + if (lexer.lookAhead(0) != ';') break; + else lexer.consume(1); + } + } +} diff --git a/java/gov/nist/javax/sip/parser/ParseExceptionListener.java b/java/gov/nist/javax/sip/parser/ParseExceptionListener.java new file mode 100644 index 0000000..f451ecd --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ParseExceptionListener.java @@ -0,0 +1,129 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.message.*; +import java.text.ParseException; + +/** + * A listener interface that enables customization of parse error handling. + * An class that implements this interface is registered with the + * parser and is called back from the parser handle parse errors. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:01 $ + */ +public interface ParseExceptionListener { + /** + * This gets called from the parser when a parse error is generated. + * The handler is supposed to introspect on the error class and + * header name to handle the error appropriately. The error can + * be handled by : + *<ul> + * <li>1. Re-throwing an exception and aborting the parse. + * <li>2. Ignoring the header (attach the unparseable header to + * the SIPMessage being parsed). + * <li>3. Re-Parsing the bad header and adding it to the sipMessage + * </ul> + * + * @param ex - parse exception being processed. + * @param sipMessage -- sip message being processed. + * @param headerText -- header/RL/SL text being parsed. + * @param messageText -- message where this header was detected. + */ + public void handleException( + ParseException ex, + SIPMessage sipMessage, + Class headerClass, + String headerText, + String messageText) + throws ParseException; +} +/* + * $Log: ParseExceptionListener.java,v $ + * Revision 1.7 2009/07/17 18:58:01 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:01:55 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/Parser.java b/java/gov/nist/javax/sip/parser/Parser.java new file mode 100644 index 0000000..4447a7d --- /dev/null +++ b/java/gov/nist/javax/sip/parser/Parser.java @@ -0,0 +1,223 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.core.Debug; +import gov.nist.core.LexerCore; +import gov.nist.core.ParserCore; +import gov.nist.core.Token; +import java.text.ParseException; + +/** + * Base parser class. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:58:01 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public abstract class Parser extends ParserCore implements TokenTypes { + + protected ParseException createParseException(String exceptionString) { + return new ParseException( + lexer.getBuffer() + ":" + exceptionString, + lexer.getPtr()); + } + + protected Lexer getLexer() { + return (Lexer) this.lexer; + } + + protected String sipVersion() throws ParseException { + if (debug) + dbg_enter("sipVersion"); + try { + Token tok = lexer.match(SIP); + if (!tok.getTokenValue().equalsIgnoreCase("SIP")) + createParseException("Expecting SIP"); + lexer.match('/'); + tok = lexer.match(ID); + if (!tok.getTokenValue().equals("2.0")) + createParseException("Expecting SIP/2.0"); + + return "SIP/2.0"; + } finally { + if (debug) + dbg_leave("sipVersion"); + } + } + + /** + * parses a method. Consumes if a valid method has been found. + */ + protected String method() throws ParseException { + try { + if (debug) + dbg_enter("method"); + Token[] tokens = this.lexer.peekNextToken(1); + Token token = (Token) tokens[0]; + if (token.getTokenType() == INVITE + || token.getTokenType() == ACK + || token.getTokenType() == OPTIONS + || token.getTokenType() == BYE + || token.getTokenType() == REGISTER + || token.getTokenType() == CANCEL + || token.getTokenType() == SUBSCRIBE + || token.getTokenType() == NOTIFY + || token.getTokenType() == PUBLISH + || token.getTokenType() == MESSAGE + || token.getTokenType() == ID) { + lexer.consume(); + return token.getTokenValue(); + } else { + throw createParseException("Invalid Method"); + } + } finally { + if (Debug.debug) + dbg_leave("method"); + } + } + + /** + * Verifies that a given string matches the 'token' production in RFC3261 + * + * @param token + * @throws ParseException - if there are invalid characters + * + * @author JvB + */ + public static final void checkToken( String token ) throws ParseException { + + if (token == null || token.length()==0 ) { + throw new ParseException("null or empty token", -1 ); + } else { + // JvB: check that it is a valid token + for ( int i=0; i<token.length(); ++i ) { + if ( !LexerCore.isTokenChar( token.charAt(i) )) { + throw new ParseException( "Invalid character(s) in string (not allowed in 'token')", i ); + } + } + } + } +} +/* + * $Log: Parser.java,v $ + * Revision 1.10 2009/07/17 18:58:01 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.9 2008/01/18 11:19:24 jbemmel + * added a method to check strings for valid token characters + * + * Revision 1.8 2007/02/23 14:56:05 belangery + * Added performance improvement around header name lowercase conversion. + * + * Revision 1.7 2006/09/27 15:02:43 mranga + * Issue number: + * Obtained from: + * Submitted by: + * Reviewed by: mranga + * rfc 2543 transaction matching. fix for MESSAGE request type parsing. + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.6 2006/07/13 09:02:18 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.5 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.4 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.3 2005/11/21 23:24:49 jeroen + * "SIP" is case insensitive + * + * Revision 1.2 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.3 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ParserFactory.java b/java/gov/nist/javax/sip/parser/ParserFactory.java new file mode 100644 index 0000000..e38cbf9 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ParserFactory.java @@ -0,0 +1,480 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.parser.ims.*; +import gov.nist.javax.sip.header.ims.*; +import java.util.Hashtable; +import java.lang.reflect.*; +import javax.sip.header.*; +import java.text.ParseException; +import gov.nist.core.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.header.SIPHeaderNamesCache; +import gov.nist.javax.sip.parser.extensions.*; + +/** + * A factory class that does a name lookup on a registered parser and + * returns a header parser for the given name. + * + * @version 1.2 $Revision: 1.17 $ $Date: 2010/01/12 00:05:25 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ParserFactory { + + private static Hashtable<String,Class<? extends HeaderParser>> parserTable; + private static Class[] constructorArgs; + private static Hashtable parserConstructorCache; + + static { + parserTable = new Hashtable<String,Class<? extends HeaderParser>>(); + parserConstructorCache = new Hashtable(); + constructorArgs = new Class[1]; + constructorArgs[0] = String.class; + parserTable.put(ReplyToHeader.NAME.toLowerCase(), ReplyToParser.class); + + parserTable.put( + InReplyToHeader.NAME.toLowerCase(), + InReplyToParser.class); + + parserTable.put( + AcceptEncodingHeader.NAME.toLowerCase(), + AcceptEncodingParser.class); + + parserTable.put( + AcceptLanguageHeader.NAME.toLowerCase(), + AcceptLanguageParser.class); + + parserTable.put("t", ToParser.class); + parserTable.put(ToHeader.NAME.toLowerCase(), ToParser.class); + + parserTable.put(FromHeader.NAME.toLowerCase(), FromParser.class); + parserTable.put("f", FromParser.class); + + parserTable.put(CSeqHeader.NAME.toLowerCase(), CSeqParser.class); + + parserTable.put(ViaHeader.NAME.toLowerCase(), ViaParser.class); + parserTable.put("v", ViaParser.class); + + parserTable.put(ContactHeader.NAME.toLowerCase(), ContactParser.class); + parserTable.put("m", ContactParser.class); + + parserTable.put( + ContentTypeHeader.NAME.toLowerCase(), + ContentTypeParser.class); + parserTable.put("c", ContentTypeParser.class); + + parserTable.put( + ContentLengthHeader.NAME.toLowerCase(), + ContentLengthParser.class); + parserTable.put("l", ContentLengthParser.class); + + parserTable.put( + AuthorizationHeader.NAME.toLowerCase(), + AuthorizationParser.class); + + parserTable.put( + WWWAuthenticateHeader.NAME.toLowerCase(), + WWWAuthenticateParser.class); + + parserTable.put(CallIdHeader.NAME.toLowerCase(), CallIDParser.class); + parserTable.put("i", CallIDParser.class); + + parserTable.put(RouteHeader.NAME.toLowerCase(), RouteParser.class); + + parserTable.put( + RecordRouteHeader.NAME.toLowerCase(), + RecordRouteParser.class); + + parserTable.put(DateHeader.NAME.toLowerCase(), DateParser.class); + + parserTable.put( + ProxyAuthorizationHeader.NAME.toLowerCase(), + ProxyAuthorizationParser.class); + + parserTable.put( + ProxyAuthenticateHeader.NAME.toLowerCase(), + ProxyAuthenticateParser.class); + + parserTable.put( + RetryAfterHeader.NAME.toLowerCase(), + RetryAfterParser.class); + + parserTable.put(RequireHeader.NAME.toLowerCase(), RequireParser.class); + + parserTable.put( + ProxyRequireHeader.NAME.toLowerCase(), + ProxyRequireParser.class); + + parserTable.put( + TimeStampHeader.NAME.toLowerCase(), + TimeStampParser.class); + + parserTable.put( + UnsupportedHeader.NAME.toLowerCase(), + UnsupportedParser.class); + + parserTable.put( + UserAgentHeader.NAME.toLowerCase(), + UserAgentParser.class); + + parserTable.put( + SupportedHeader.NAME.toLowerCase(), + SupportedParser.class); + // bug fix by Steve Crosley + parserTable.put("k", SupportedParser.class); + + parserTable.put(ServerHeader.NAME.toLowerCase(), ServerParser.class); + + parserTable.put(SubjectHeader.NAME.toLowerCase(), SubjectParser.class); + parserTable.put( "s", SubjectParser.class); // JvB: added + + parserTable.put( + SubscriptionStateHeader.NAME.toLowerCase(), + SubscriptionStateParser.class); + + parserTable.put( + MaxForwardsHeader.NAME.toLowerCase(), + MaxForwardsParser.class); + + parserTable.put( + MimeVersionHeader.NAME.toLowerCase(), + MimeVersionParser.class); + + parserTable.put( + MinExpiresHeader.NAME.toLowerCase(), + MinExpiresParser.class); + + parserTable.put( + OrganizationHeader.NAME.toLowerCase(), + OrganizationParser.class); + + parserTable.put( + PriorityHeader.NAME.toLowerCase(), + PriorityParser.class); + + parserTable.put(RAckHeader.NAME.toLowerCase(), RAckParser.class); + + parserTable.put(RSeqHeader.NAME.toLowerCase(), RSeqParser.class); + + parserTable.put(ReasonHeader.NAME.toLowerCase(), ReasonParser.class); + + parserTable.put(WarningHeader.NAME.toLowerCase(), WarningParser.class); + + parserTable.put(ExpiresHeader.NAME.toLowerCase(), ExpiresParser.class); + + parserTable.put(EventHeader.NAME.toLowerCase(), EventParser.class); + parserTable.put("o", EventParser.class); + + parserTable.put( + ErrorInfoHeader.NAME.toLowerCase(), + ErrorInfoParser.class); + + parserTable.put( + ContentLanguageHeader.NAME.toLowerCase(), + ContentLanguageParser.class); + + parserTable.put( + ContentEncodingHeader.NAME.toLowerCase(), + ContentEncodingParser.class); + parserTable.put("e", ContentEncodingParser.class); + + parserTable.put( + ContentDispositionHeader.NAME.toLowerCase(), + ContentDispositionParser.class); + + parserTable.put( + CallInfoHeader.NAME.toLowerCase(), + CallInfoParser.class); + + parserTable.put( + AuthenticationInfoHeader.NAME.toLowerCase(), + AuthenticationInfoParser.class); + + parserTable.put(AllowHeader.NAME.toLowerCase(), AllowParser.class); + + parserTable.put( + AllowEventsHeader.NAME.toLowerCase(), + AllowEventsParser.class); + parserTable.put("u", AllowEventsParser.class); + + parserTable.put( + AlertInfoHeader.NAME.toLowerCase(), + AlertInfoParser.class); + + parserTable.put(AcceptHeader.NAME.toLowerCase(), AcceptParser.class); + + parserTable.put(ReferToHeader.NAME.toLowerCase(), ReferToParser.class); + // Was missing (bug noticed by Steve Crossley) + parserTable.put("r", ReferToParser.class); + + // JvB: added to support RFC3903 PUBLISH + parserTable.put(SIPETagHeader.NAME.toLowerCase(), SIPETagParser.class); + parserTable.put(SIPIfMatchHeader.NAME.toLowerCase(), SIPIfMatchParser.class); + + //IMS headers + parserTable.put(PAccessNetworkInfoHeader.NAME.toLowerCase(), PAccessNetworkInfoParser.class); + parserTable.put(PAssertedIdentityHeader.NAME.toLowerCase(), PAssertedIdentityParser.class); + parserTable.put(PPreferredIdentityHeader.NAME.toLowerCase(), PPreferredIdentityParser.class); + parserTable.put(PChargingVectorHeader.NAME.toLowerCase(), PChargingVectorParser.class); + parserTable.put(PChargingFunctionAddressesHeader.NAME.toLowerCase(), PChargingFunctionAddressesParser.class); + parserTable.put(PMediaAuthorizationHeader.NAME.toLowerCase(), PMediaAuthorizationParser.class); + parserTable.put(PathHeader.NAME.toLowerCase(), PathParser.class); + parserTable.put(PrivacyHeader.NAME.toLowerCase(), PrivacyParser.class); + parserTable.put(ServiceRouteHeader.NAME.toLowerCase(), ServiceRouteParser.class); + parserTable.put(PVisitedNetworkIDHeader.NAME.toLowerCase(), PVisitedNetworkIDParser.class); + + parserTable.put(PAssociatedURIHeader.NAME.toLowerCase(), PAssociatedURIParser.class); + parserTable.put(PCalledPartyIDHeader.NAME.toLowerCase(), PCalledPartyIDParser.class); + + parserTable.put(SecurityServerHeader.NAME.toLowerCase(), SecurityServerParser.class); + parserTable.put(SecurityClientHeader.NAME.toLowerCase(), SecurityClientParser.class); + parserTable.put(SecurityVerifyHeader.NAME.toLowerCase(), SecurityVerifyParser.class); + + + // Per RFC 3892 (pmusgrave) + parserTable.put(ReferredBy.NAME.toLowerCase(), ReferredByParser.class); + parserTable.put("b", ReferToParser.class); + + // Per RFC4028 Session Timers (pmusgrave) + parserTable.put(SessionExpires.NAME.toLowerCase(), SessionExpiresParser.class); + parserTable.put("x", SessionExpiresParser.class); + parserTable.put(MinSE.NAME.toLowerCase(), MinSEParser.class); + // (RFC4028 does not give a short form header for MinSE) + + // Per RFC3891 (pmusgrave) + parserTable.put(Replaces.NAME.toLowerCase(), ReplacesParser.class); + + // Per RFC3911 (jean deruelle) + parserTable.put(Join.NAME.toLowerCase(), JoinParser.class); + + //http://tools.ietf.org/html/draft-worley-references-05 + parserTable.put(References.NAME.toLowerCase(), ReferencesParser.class); + } + + /** + * create a parser for a header. This is the parser factory. + */ + public static HeaderParser createParser(String line) + throws ParseException { + String headerName = Lexer.getHeaderName(line); + String headerValue = Lexer.getHeaderValue(line); + if (headerName == null || headerValue == null) + throw new ParseException("The header name or value is null", 0); + + Class parserClass = (Class) parserTable.get(SIPHeaderNamesCache.toLowerCase(headerName)); + if (parserClass != null) { + try { + Constructor cons = (Constructor) parserConstructorCache.get(parserClass); + if (cons == null) { + cons = parserClass.getConstructor(constructorArgs); + parserConstructorCache.put(parserClass, cons); + } + Object[] args = new Object[1]; + args[0] = line; + HeaderParser retval = (HeaderParser) cons.newInstance(args); + return retval; + + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + return null; // to placate the compiler. + } + + } else { + // Just generate a generic SIPHeader. We define + // parsers only for the above. + return new HeaderParser(line); + } + } +} +/* + * $Log: ParserFactory.java,v $ + * Revision 1.17 2010/01/12 00:05:25 mranga + * Add support for References header draft-worley-references-05 + * + * Revision 1.16 2009/07/17 18:58:01 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.15 2009/01/22 19:33:48 deruelle_jean + * Add support for JOIN (RFC 3911) + * Issue number: 186 + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: Ranga, The high priest and grand poobah of Jain-SIP + * + * Revision 1.14 2007/03/07 14:29:46 belangery + * Yet another bunch of improvements in the parsing code. + * + * Revision 1.13 2007/02/23 14:56:06 belangery + * Added performance improvement around header name lowercase conversion. + * + * Revision 1.12 2007/01/08 19:24:21 mranga + * Issue number: + * Obtained from: + * Submitted by: Miguel Freitas + * Reviewed by: mranga + * + * Miguel -- please implement a deep clone method for the IMS headers. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.11 2006/10/12 11:57:54 pmusgrave + * Issue number: 79, 80 + * Submitted by: pmusgrave@newheights.com + * Reviewed by: mranga + * + * Revision 1.10 2006/09/29 19:40:50 jbemmel + * fixed missing IMS header parsing plumbing + * + * Revision 1.9 2006/09/11 18:41:32 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: + * Tighter integration of IMS headers. + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.8 2006/08/15 21:44:50 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Incorporating the latest API changes from Phelim + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.7 2006/07/13 09:02:06 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.5 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.4 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.3 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * Revision 1.2 2005/10/14 19:59:00 jeroen + * bugfix: missing parser for shortform of Subject (s) + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2005/04/04 09:29:03 dmuresan + * Replaced new String().getClass() with String.class. + * + * Revision 1.3 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/Pipeline.java b/java/gov/nist/javax/sip/parser/Pipeline.java new file mode 100644 index 0000000..26dbfb6 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/Pipeline.java @@ -0,0 +1,196 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.parser; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.stack.SIPStackTimerTask; + +import java.io.*; +import java.util.*; + +/** + * Input class for the pipelined parser. Buffer all bytes read from the socket + * and make them available to the message parser. + * + * @author M. Ranganathan (Contains a bug fix contributed by Rob Daugherty ( + * Lucent Technologies) ) + * + */ + +public class Pipeline extends InputStream { + private LinkedList buffList; + + private Buffer currentBuffer; + + private boolean isClosed; + + private Timer timer; + + private InputStream pipe; + + private int readTimeout; + + private TimerTask myTimerTask; + + class MyTimer extends SIPStackTimerTask { + Pipeline pipeline; + + private boolean isCancelled; + + protected MyTimer(Pipeline pipeline) { + this.pipeline = pipeline; + } + + protected void runTask() { + if (this.isCancelled) + return; + + try { + pipeline.close(); + } catch (IOException ex) { + InternalErrorHandler.handleException(ex); + } + } + + public boolean cancel() { + boolean retval = super.cancel(); + this.isCancelled = true; + return retval; + } + + } + + class Buffer { + byte[] bytes; + + int length; + + int ptr; + + public Buffer(byte[] bytes, int length) { + ptr = 0; + this.length = length; + this.bytes = bytes; + } + + public int getNextByte() { + int retval = bytes[ptr++] & 0xFF; + return retval; + } + + } + + public void startTimer() { + if (this.readTimeout == -1) + return; + // TODO make this a tunable number. For now 4 seconds + // between reads seems reasonable upper limit. + this.myTimerTask = new MyTimer(this); + this.timer.schedule(this.myTimerTask, this.readTimeout); + } + + public void stopTimer() { + if (this.readTimeout == -1) + return; + if (this.myTimerTask != null) + this.myTimerTask.cancel(); + } + + public Pipeline(InputStream pipe, int readTimeout, Timer timer) { + // pipe is the Socket stream + // this is recorded here to implement a timeout. + this.timer = timer; + this.pipe = pipe; + buffList = new LinkedList(); + this.readTimeout = readTimeout; + } + + public void write(byte[] bytes, int start, int length) throws IOException { + if (this.isClosed) + throw new IOException("Closed!!"); + Buffer buff = new Buffer(bytes, length); + buff.ptr = start; + synchronized (this.buffList) { + buffList.add(buff); + buffList.notifyAll(); + } + } + + public void write(byte[] bytes) throws IOException { + if (this.isClosed) + throw new IOException("Closed!!"); + Buffer buff = new Buffer(bytes, bytes.length); + synchronized (this.buffList) { + buffList.add(buff); + buffList.notifyAll(); + } + } + + public void close() throws IOException { + this.isClosed = true; + synchronized (this.buffList) { + this.buffList.notifyAll(); + } + + // JvB: added + this.pipe.close(); + } + + public int read() throws IOException { + // if (this.isClosed) return -1; + synchronized (this.buffList) { + if (currentBuffer != null + && currentBuffer.ptr < currentBuffer.length) { + int retval = currentBuffer.getNextByte(); + if (currentBuffer.ptr == currentBuffer.length) + this.currentBuffer = null; + return retval; + } + // Bug fix contributed by Rob Daugherty. + if (this.isClosed && this.buffList.isEmpty()) + return -1; + try { + // wait till something is posted. + while (this.buffList.isEmpty()) { + this.buffList.wait(); + if (this.isClosed) + return -1; + } + currentBuffer = (Buffer) this.buffList.removeFirst(); + int retval = currentBuffer.getNextByte(); + if (currentBuffer.ptr == currentBuffer.length) + this.currentBuffer = null; + return retval; + } catch (InterruptedException ex) { + throw new IOException(ex.getMessage()); + } catch (NoSuchElementException ex) { + ex.printStackTrace(); + throw new IOException(ex.getMessage()); + } + } + } + +} diff --git a/java/gov/nist/javax/sip/parser/PipelinedMsgParser.java b/java/gov/nist/javax/sip/parser/PipelinedMsgParser.java new file mode 100644 index 0000000..20ecce3 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/PipelinedMsgParser.java @@ -0,0 +1,505 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + ******************************************************************************/ +package gov.nist.javax.sip.parser; + +/* + * + * Lamine Brahimi and Yann Duponchel (IBM Zurich) noticed that the parser was + * blocking so I threw out some cool pipelining which ran fast but only worked + * when the phase of the moon matched its mood. Now things are serialized and + * life goes slower but more reliably. + * + */ +import gov.nist.core.*; +import gov.nist.javax.sip.message.*; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import java.io.*; + +/** + * This implements a pipelined message parser suitable for use with a stream - + * oriented input such as TCP. The client uses this class by instatiating with + * an input stream from which input is read and fed to a message parser. It + * keeps reading from the input stream and process messages in a never ending + * interpreter loop. The message listener interface gets called for processing + * messages or for processing errors. The payload specified by the + * content-length header is read directly from the input stream. This can be + * accessed from the SIPMessage using the getContent and getContentBytes methods + * provided by the SIPMessage class. + * + * @version 1.2 $Revision: 1.23 $ $Date: 2009/08/16 17:28:28 $ + * + * @author M. Ranganathan + * + * @see SIPMessageListener + */ +public final class PipelinedMsgParser implements Runnable { + + + + /** + * The message listener that is registered with this parser. (The message + * listener has methods that can process correct and erroneous messages.) + */ + protected SIPMessageListener sipMessageListener; + private Thread mythread; // Preprocessor thread + //private byte[] messageBody; + //private boolean errorFlag; + private Pipeline rawInputStream; + private int maxMessageSize; + private int sizeCounter; + //private int messageSize; + + /** + * default constructor. + */ + protected PipelinedMsgParser() { + super(); + + } + + private static int uid = 0; + + private static synchronized int getNewUid() { + return uid++; + } + + /** + * Constructor when we are given a message listener and an input stream + * (could be a TCP connection or a file) + * + * @param sipMessageListener + * Message listener which has methods that get called back from + * the parser when a parse is complete + * @param in + * Input stream from which to read the input. + * @param debug + * Enable/disable tracing or lexical analyser switch. + */ + public PipelinedMsgParser(SIPMessageListener sipMessageListener, + Pipeline in, boolean debug, int maxMessageSize) { + this(); + this.sipMessageListener = sipMessageListener; + rawInputStream = in; + this.maxMessageSize = maxMessageSize; + mythread = new Thread(this); + mythread.setName("PipelineThread-" + getNewUid()); + + } + + /** + * This is the constructor for the pipelined parser. + * + * @param mhandler + * a SIPMessageListener implementation that provides the message + * handlers to handle correctly and incorrectly parsed messages. + * @param in + * An input stream to read messages from. + */ + + public PipelinedMsgParser(SIPMessageListener mhandler, Pipeline in, + int maxMsgSize) { + this(mhandler, in, false, maxMsgSize); + } + + /** + * This is the constructor for the pipelined parser. + * + * @param in - + * An input stream to read messages from. + */ + + public PipelinedMsgParser(Pipeline in) { + this(null, in, false, 0); + } + + /** + * Start reading and processing input. + */ + public void processInput() { + mythread.start(); + } + + /** + * Create a new pipelined parser from an existing one. + * + * @return A new pipelined parser that reads from the same input stream. + */ + protected Object clone() { + PipelinedMsgParser p = new PipelinedMsgParser(); + + p.rawInputStream = this.rawInputStream; + p.sipMessageListener = this.sipMessageListener; + Thread mythread = new Thread(p); + mythread.setName("PipelineThread"); + return p; + } + + /** + * Add a class that implements a SIPMessageListener interface whose methods + * get called * on successful parse and error conditons. + * + * @param mlistener + * a SIPMessageListener implementation that can react to correct + * and incorrect pars. + */ + + public void setMessageListener(SIPMessageListener mlistener) { + sipMessageListener = mlistener; + } + + /** + * read a line of input (I cannot use buffered reader because we may need to + * switch encodings mid-stream! + */ + private String readLine(InputStream inputStream) throws IOException { + StringBuffer retval = new StringBuffer(""); + while (true) { + char ch; + int i = inputStream.read(); + if (i == -1) { + throw new IOException("End of stream"); + } else + ch = (char) i; + // reduce the available read size by 1 ("size" of a char). + if (this.maxMessageSize > 0) { + this.sizeCounter--; + if (this.sizeCounter <= 0) + throw new IOException("Max size exceeded!"); + } + if (ch != '\r') + retval.append(ch); + if (ch == '\n') { + break; + } + } + return retval.toString(); + } + + /** + * This is input reading thread for the pipelined parser. You feed it input + * through the input stream (see the constructor) and it calls back an event + * listener interface for message processing or error. It cleans up the + * input - dealing with things like line continuation + */ + public void run() { + + Pipeline inputStream = this.rawInputStream; + // inputStream = new MyFilterInputStream(this.rawInputStream); + // I cannot use buffered reader here because we may need to switch + // encodings to read the message body. + try { + while (true) { + this.sizeCounter = this.maxMessageSize; + // this.messageSize = 0; + StringBuffer inputBuffer = new StringBuffer(); + + if (Debug.parserDebug) + Debug.println("Starting parse!"); + + String line1; + String line2 = null; + + while (true) { + try { + line1 = readLine(inputStream); + // ignore blank lines. + if (line1.equals("\n")) { + if (Debug.parserDebug) { + Debug.println("Discarding blank line. "); + } + continue; + } else + break; + } catch (IOException ex) { + Debug.printStackTrace(ex); + this.rawInputStream.stopTimer(); + return; + + } + } + + inputBuffer.append(line1); + // Guard against bad guys. + this.rawInputStream.startTimer(); + + Debug.println("Reading Input Stream"); + while (true) { + try { + line2 = readLine(inputStream); + inputBuffer.append(line2); + if (line2.trim().equals("")) + break; + } catch (IOException ex) { + this.rawInputStream.stopTimer(); + Debug.printStackTrace(ex); + return; + + } + } + + // Stop the timer that will kill the read. + this.rawInputStream.stopTimer(); + inputBuffer.append(line2); + StringMsgParser smp = new StringMsgParser(sipMessageListener); + smp.readBody = false; + SIPMessage sipMessage = null; + + try { + if (Debug.debug) { + Debug.println("About to parse : " + inputBuffer.toString()); + } + sipMessage = smp.parseSIPMessage(inputBuffer.toString()); + if (sipMessage == null) { + this.rawInputStream.stopTimer(); + continue; + } + } catch (ParseException ex) { + // Just ignore the parse exception. + Debug.logError("Detected a parse error", ex); + continue; + } + + if (Debug.debug) { + Debug.println("Completed parsing message"); + } + ContentLength cl = (ContentLength) sipMessage + .getContentLength(); + int contentLength = 0; + if (cl != null) { + contentLength = cl.getContentLength(); + } else { + contentLength = 0; + } + + if (Debug.debug) { + Debug.println("contentLength " + contentLength); + } + + if (contentLength == 0) { + sipMessage.removeContent(); + } else if (maxMessageSize == 0 + || contentLength < this.sizeCounter) { + byte[] message_body = new byte[contentLength]; + int nread = 0; + while (nread < contentLength) { + // Start my starvation timer. + // This ensures that the other end + // writes at least some data in + // or we will close the pipe from + // him. This prevents DOS attack + // that takes up all our connections. + this.rawInputStream.startTimer(); + try { + + int readlength = inputStream.read(message_body, + nread, contentLength - nread); + if (readlength > 0) { + nread += readlength; + } else { + break; + } + } catch (IOException ex) { + Debug.logError("Exception Reading Content",ex); + break; + } finally { + // Stop my starvation timer. + this.rawInputStream.stopTimer(); + } + } + sipMessage.setMessageContent(message_body); + } + // Content length too large - process the message and + // return error from there. + if (sipMessageListener != null) { + try { + sipMessageListener.processMessage(sipMessage); + } catch (Exception ex) { + // fatal error in processing - close the + // connection. + break; + } + } + } + } finally { + try { + inputStream.close(); + } catch (IOException e) { + InternalErrorHandler.handleException(e); + } + } + } + + public void close() { + try { + this.rawInputStream.close(); + } catch (IOException ex) { + // Ignore. + } + } +} +/* + * $Log: PipelinedMsgParser.java,v $ + * Revision 1.23 2009/08/16 17:28:28 mranga + * Issue number: 208 + * Obtained from: + * Submitted by: + * Reviewed by: + * + * Add authentication mechanism that uses H(username:domain:password) + * + * Revision 1.22 2009/07/17 18:58:02 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.21 2008/05/24 04:10:01 mranga + * + * Issue number: 158 + * Obtained from: + * Submitted by: + * Reviewed by: mranga + * + * Deliver tx timeout for Canceled INVITE. Fix pipeline thread exit. + * + * Revision 1.20 2008/05/22 19:38:07 jbemmel + * Fix for issue 149: the logic wasn't always closing the internal socket pipe, + * causing the pipe reader thread to block indefinitely + * + * Repeatedly starting/stopping the stack then gives hanging threads + * Revision 1.19 2007/01/28 13:06:21 mranga + * Issue number: 99 Obtained from: Submitted by: Reviewed by: mranga + * + * Fixed PRACK handling null pointer exception (for proxy case) and cleanup of + * unused variables. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: CVS: If this change addresses one or more issues, CVS: + * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change + * has been taken from another system, CVS: then name the system in this line, + * otherwise delete it. CVS: Submitted by: CVS: If this code has been + * contributed to the project by someone else; i.e., CVS: they sent us a patch + * or a set of diffs, then include their name/email CVS: address here. If this + * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing + * pre-commit code reviews and someone else has CVS: reviewed your changes, + * include their name(s) here. CVS: If you have not had it reviewed then delete + * this line. + * + * Revision 1.18 2006/07/13 09:02:10 mranga Issue number: Obtained from: + * Submitted by: jeroen van bemmel Reviewed by: mranga Moved some changes from + * jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: CVS: If this change addresses one or more issues, CVS: + * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change + * has been taken from another system, CVS: then name the system in this line, + * otherwise delete it. CVS: Submitted by: CVS: If this code has been + * contributed to the project by someone else; i.e., CVS: they sent us a patch + * or a set of diffs, then include their name/email CVS: address here. If this + * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing + * pre-commit code reviews and someone else has CVS: reviewed your changes, + * include their name(s) here. CVS: If you have not had it reviewed then delete + * this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga javadoc fixups + * + * Revision 1.3 2006/06/17 10:18:14 mranga Added some synchronization to the + * sequence number checking. Small javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga Added NIST disclaimer to all public + * domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.16 2004/11/30 23:28:14 mranga Issue number: 44 Submitted by: Rob + * Daugherty Reviewed by: M. Ranganathan + * + * TCP Pipelining truncates content when other end of pipe is closed. + * + * Revision 1.15 2004/05/30 18:55:56 mranga Reviewed by: mranga Move to timers + * and eliminate the Transaction scanner Thread to improve scalability and + * reduce cpu usage. + * + * Revision 1.14 2004/05/16 14:13:22 mranga Reviewed by: mranga Fixed the + * use-count issue reported by Peter Parnes. Added property to prevent against + * content-length dos attacks. + * + * Revision 1.13 2004/03/19 04:22:22 mranga Reviewed by: mranga Added IO Pacing + * for long writes - split write into chunks and flush after each chunk to avoid + * socket back pressure. + * + * Revision 1.12 2004/03/18 22:01:19 mranga Reviewed by: mranga Get rid of the + * PipedInputStream from pipelined parser to avoid a copy. + * + * Revision 1.11 2004/03/07 22:25:23 mranga Reviewed by: mranga Added a new + * configuration parameter that instructs the stack to drop a server connection + * after server transaction termination set + * gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS=false for this Default behavior + * is true. + * + * Revision 1.10 2004/02/29 15:32:58 mranga Reviewed by: mranga bug fixes on + * limiting the max message size. + * + * Revision 1.9 2004/02/29 00:46:34 mranga Reviewed by: mranga Added new + * configuration property to limit max message size for TCP transport. The + * property is gov.nist.javax.sip.MAX_MESSAGE_SIZE + * + * Revision 1.8 2004/02/25 21:43:03 mranga Reviewed by: mranga Added a couple of + * todo's and removed some debug printlns that could slow code down by a bit. + * + * Revision 1.7 2004/02/25 20:52:46 mranga Reviewed by: mranga Fix TCP transport + * so messages in excess of 8192 bytes are accepted. + * + * Revision 1.6 2004/01/22 18:39:41 mranga Reviewed by: M. Ranganathan Moved the + * ifdef SIMULATION and associated tags to the first column so Prep preprocessor + * can deal with them. + * + * Revision 1.5 2004/01/22 14:23:45 mranga Reviewed by: mranga Fixed some minor + * formatting issues. + * + * Revision 1.4 2004/01/22 13:26:31 sverker Issue number: Obtained from: + * Submitted by: sverker Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and + * javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: CVS: If this change addresses one or more issues, CVS: + * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change + * has been taken from another system, CVS: then name the system in this line, + * otherwise delete it. CVS: Submitted by: CVS: If this code has been + * contributed to the project by someone else; i.e., CVS: they sent us a patch + * or a set of diffs, then include their name/email CVS: address here. If this + * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing + * pre-commit code reviews and someone else has CVS: reviewed your changes, + * include their name(s) here. CVS: If you have not had it reviewed then delete + * this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/PriorityParser.java b/java/gov/nist/javax/sip/parser/PriorityParser.java new file mode 100644 index 0000000..5f3ad85 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/PriorityParser.java @@ -0,0 +1,112 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Priority header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:02 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class PriorityParser extends HeaderParser { + + /** + * Creates a new instance of PriorityParser + * @param priority the header to parse + */ + public PriorityParser(String priority) { + super(priority); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected PriorityParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String header + * @return SIPHeader (Priority object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("PriorityParser.parse"); + Priority priority = new Priority(); + try { + headerName(TokenTypes.PRIORITY); + + priority.setHeaderName(SIPHeaderNames.PRIORITY); + + this.lexer.SPorHT(); + /*this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + + priority.setPriority(token.getTokenValue()); + */ + // This is in violation of the RFC but + // let us be generous in what we accept. + priority.setPriority(this.lexer.ttokenSafe()); + + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return priority; + } finally { + if (debug) + dbg_leave("PriorityParser.parse"); + } + } + + + public static void main(String args[]) throws ParseException { + String p[] = { + "Priority: 8;a\n" + }; + + for (int i = 0; i < p.length; i++ ) { + PriorityParser parser = + new PriorityParser(p[i]); + Priority prio= (Priority) parser.parse(); + System.out.println("encoded = " + prio.encode()); + } + } + +} + diff --git a/java/gov/nist/javax/sip/parser/ProxyAuthenticateParser.java b/java/gov/nist/javax/sip/parser/ProxyAuthenticateParser.java new file mode 100644 index 0000000..160ae5f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ProxyAuthenticateParser.java @@ -0,0 +1,154 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for ProxyAuthenticate headers. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class ProxyAuthenticateParser extends ChallengeParser { + + /** + * Constructor + * @param proxyAuthenticate message to parse + */ + public ProxyAuthenticateParser(String proxyAuthenticate) { + super(proxyAuthenticate); + } + + /** + * Cosntructor + * @param Lexer lexer to set + */ + protected ProxyAuthenticateParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (ProxyAuthenticate object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + headerName(TokenTypes.PROXY_AUTHENTICATE); + ProxyAuthenticate proxyAuthenticate = new ProxyAuthenticate(); + super.parse(proxyAuthenticate); + return proxyAuthenticate; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String paAuth[] = { + "Proxy-Authenticate: Digest realm=\"MCI WorldCom SIP\","+ + "domain=\"sip:ss2.wcom.com\", nonce=\"ea9c8e88df84f1cec4341ae6cbe5a359\","+ + "opaque=\"\", stale=FALSE, algorithm=MD5\n", + + "Proxy-Authenticate: Digest realm=\"MCI WorldCom SIP\","+ + "qop=\"auth\" , nonce-value=\"oli\"\n" + }; + + for (int i = 0; i < paAuth.length; i++ ) { + ProxyAuthenticateParser pap = + new ProxyAuthenticateParser(paAuth[i]); + ProxyAuthenticate pa= (ProxyAuthenticate) pap.parse(); + System.out.println("encoded = " + pa.encode()); + } + + } + */ +} +/* + * $Log: ProxyAuthenticateParser.java,v $ + * Revision 1.7 2009/07/17 18:58:02 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ProxyAuthorizationParser.java b/java/gov/nist/javax/sip/parser/ProxyAuthorizationParser.java new file mode 100644 index 0000000..3a1a6ca --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ProxyAuthorizationParser.java @@ -0,0 +1,166 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for ProxyAuthorization headers. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class ProxyAuthorizationParser extends ChallengeParser { + + /** + * Constructor + * @param proxyAuthorization -- header to parse + */ + public ProxyAuthorizationParser(String proxyAuthorization) { + super(proxyAuthorization); + } + + /** + * Cosntructor + * @param Lexer lexer to set + */ + protected ProxyAuthorizationParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (ProxyAuthenticate object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + headerName(TokenTypes.PROXY_AUTHORIZATION); + ProxyAuthorization proxyAuth = new ProxyAuthorization(); + super.parse(proxyAuth); + return proxyAuth; + } + +/** + + public static void main(String args[]) throws ParseException { + String paAuth[] = { + "Proxy-Authorization: Digest realm=\"MCI WorldCom SIP\","+ + "domain=\"sip:ss2.wcom.com\",nonce=\"ea9c8e88df84f1cec4341ae6cbe5a359\","+ + "opaque=\"\",stale=FALSE,algorithm=MD5\n", + + "Proxy-Authorization: Digest realm=\"MCI WorldCom SIP\","+ + "qop=\"auth\" , nonce-value=\"oli\"\n" + }; + + for (int i = 0; i < paAuth.length; i++ ) { + ProxyAuthorizationParser pap = + new ProxyAuthorizationParser(paAuth[i]); + ProxyAuthorization pa= (ProxyAuthorization) pap.parse(); + String encoded = pa.encode(); + System.out.println ("original = \n" + paAuth[i]); + System.out.println("encoded = \n" + encoded); + pap = new ProxyAuthorizationParser(encoded.trim() + "\n"); + pap.parse(); + } + + } +**/ + +} +/* + * $Log: ProxyAuthorizationParser.java,v $ + * Revision 1.7 2009/07/17 18:58:02 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:18 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2005/02/24 16:13:11 mranga + * Submitted by: mranga + * Reviewed by: mranga + * Just some additional testing on the parser. + * + * Revision 1.3 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ProxyRequireParser.java b/java/gov/nist/javax/sip/parser/ProxyRequireParser.java new file mode 100644 index 0000000..e6714e1 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ProxyRequireParser.java @@ -0,0 +1,187 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for ProxyRequire header. + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ProxyRequireParser extends HeaderParser { + + /** + * Creates a new instance of ProxyRequireParser + * @param require the header to parse + */ + public ProxyRequireParser(String require) { + super(require); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ProxyRequireParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (ProxyRequireList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + ProxyRequireList list = new ProxyRequireList(); + if (debug) + dbg_enter("ProxyRequireParser.parse"); + + try { + headerName(TokenTypes.PROXY_REQUIRE); + + while (lexer.lookAhead(0) != '\n') { + ProxyRequire r = new ProxyRequire(); + r.setHeaderName(SIPHeaderNames.PROXY_REQUIRE); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + r.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + list.add(r); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + r = new ProxyRequire(); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + r.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + list.add(r); + } + + } + } finally { + if (debug) + dbg_leave("ProxyRequireParser.parse"); + } + + return list; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String r[] = { + "Proxy-Require: foo \n", + "Proxy-Require: foo1, foo2 , 389\n" + }; + + for (int i = 0; i < r.length; i++ ) { + ProxyRequireParser parser = + new ProxyRequireParser(r[i]); + ProxyRequireList rl= (ProxyRequireList) parser.parse(); + System.out.println("encoded = " + rl.encode()); + } + } + */ +} +/* + * $Log: ProxyRequireParser.java,v $ + * Revision 1.7 2009/07/17 18:58:02 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:15 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RAckParser.java b/java/gov/nist/javax/sip/parser/RAckParser.java new file mode 100644 index 0000000..b830330 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RAckParser.java @@ -0,0 +1,205 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for RAck header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:02 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class RAckParser extends HeaderParser { + + /** + * Creates a new instance of RAckParser + * @param rack the header to parse + */ + public RAckParser(String rack) { + super(rack); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected RAckParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (RAck object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("RAckParser.parse"); + RAck rack = new RAck(); + try { + headerName(TokenTypes.RACK); + + rack.setHeaderName(SIPHeaderNames.RACK); + + try { + String number = this.lexer.number(); + rack.setRSequenceNumber(Long.parseLong(number)); + this.lexer.SPorHT(); + number = this.lexer.number(); + rack.setCSequenceNumber(Long.parseLong(number)); + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + rack.setMethod(token.getTokenValue()); + + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return rack; + } finally { + if (debug) + dbg_leave("RAckParser.parse"); + } + } + + /** Test program + public static void main(String args[]) throws ParseException { + String r[] = { + "RAck: 776656 1 INVITE\n" + }; + + for (int i = 0; i < r.length; i++ ) { + RAckParser parser = + new RAckParser(r[i]); + RAck ra= (RAck) parser.parse(); + System.out.println("encoded = " + ra.encode()); + } + } + */ +} +/* + * $Log: RAckParser.java,v $ + * Revision 1.8 2009/07/17 18:58:02 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/08/15 21:44:50 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Incorporating the latest API changes from Phelim + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.6 2006/07/13 09:02:24 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2006/05/24 06:21:43 mranga + * change to use the long setter + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RSeqParser.java b/java/gov/nist/javax/sip/parser/RSeqParser.java new file mode 100644 index 0000000..f8168de --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RSeqParser.java @@ -0,0 +1,196 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for RSeq header. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:03 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class RSeqParser extends HeaderParser { + + /** + * Creates a new instance of RSeqParser + * @param rseq the header to parse + */ + public RSeqParser(String rseq) { + super(rseq); + } + + /** + * Constructor + * param lexer the lexer to use to parse the header + */ + protected RSeqParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader ( RSeq object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("RSeqParser.parse"); + RSeq rseq = new RSeq(); + try { + headerName(TokenTypes.RSEQ); + + rseq.setHeaderName(SIPHeaderNames.RSEQ); + + String number = this.lexer.number(); + try { + rseq.setSeqNumber(Long.parseLong(number)); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + + this.lexer.match('\n'); + + return rseq; + } finally { + if (debug) + dbg_leave("RSeqParser.parse"); + } + } + + /** Test program + public static void main(String args[]) throws ParseException { + String r[] = { + "RSeq: 988789 \n" + }; + + for (int i = 0; i < r.length; i++ ) { + RSeqParser parser = + new RSeqParser(r[i]); + RSeq rs= (RSeq) parser.parse(); + System.out.println("encoded = " + rs.encode()); + } + } + */ + +} +/* + * $Log: RSeqParser.java,v $ + * Revision 1.8 2009/07/17 18:58:03 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/08/15 21:44:49 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Incorporating the latest API changes from Phelim + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.6 2006/07/13 09:01:53 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2006/05/24 06:21:43 mranga + * change to use the long setter + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ReasonParser.java b/java/gov/nist/javax/sip/parser/ReasonParser.java new file mode 100644 index 0000000..7a7c4f4 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ReasonParser.java @@ -0,0 +1,183 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Reason header. + * + * @version 1.2 + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ReasonParser extends ParametersParser { + + /** + * Creates a new instance of ReasonParser + * @param reason the header to parse + */ + public ReasonParser(String reason) { + super(reason); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ReasonParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (ReasonParserList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + ReasonList reasonList = new ReasonList(); + if (debug) + dbg_enter("ReasonParser.parse"); + + try { + headerName(TokenTypes.REASON); + this.lexer.SPorHT(); + while (lexer.lookAhead(0) != '\n') { + Reason reason = new Reason(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + String value = token.getTokenValue(); + + reason.setProtocol(value); + super.parse(reason); + reasonList.add(reason); + if (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else + this.lexer.SPorHT(); + + } + } finally { + if (debug) + dbg_leave("ReasonParser.parse"); + } + + return reasonList; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String r[] = { + "Reason: SIP ;cause=200 ;text=\"Call completed elsewhere\"\n", + "Reason: Q.850 ;cause=16 ;text=\"Terminated\"\n", + "Reason: SIP ;cause=600 ;text=\"Busy Everywhere\"\n", + "Reason: SIP ;cause=580 ;text=\"Precondition Failure\","+ + "SIP ;cause=530 ;text=\"Pre Failure\"\n", + "Reason: SIP \n" + }; + + for (int i = 0; i < r.length; i++ ) { + ReasonParser parser = + new ReasonParser(r[i]); + ReasonList rl= (ReasonList) parser.parse(); + System.out.println("encoded = " + rl.encode()); + } + } + */ +} +/* + * $Log: ReasonParser.java,v $ + * Revision 1.8 2009/07/17 18:58:03 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2008/11/19 10:10:50 jbemmel + * Don't catch ParseException but throw it + * + * Revision 1.6 2006/07/13 09:02:12 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RecordRouteParser.java b/java/gov/nist/javax/sip/parser/RecordRouteParser.java new file mode 100644 index 0000000..381f1ae --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RecordRouteParser.java @@ -0,0 +1,96 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.RecordRoute; +import gov.nist.javax.sip.header.RecordRouteList; +import gov.nist.javax.sip.header.SIPHeader; + +import java.text.ParseException; + +/** + * Parser for a list of route headers. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:03 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + */ +public class RecordRouteParser extends AddressParametersParser { + + /** + * Constructor + * @param recordRoute message to parse to set + */ + public RecordRouteParser(String recordRoute) { + super(recordRoute); + } + + protected RecordRouteParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message and generate the RecordRoute List Object + * @return SIPHeader the RecordRoute List object + * @throws ParseException if errors occur during the parsing + */ + public SIPHeader parse() throws ParseException { + RecordRouteList recordRouteList = new RecordRouteList(); + + if (debug) + dbg_enter("RecordRouteParser.parse"); + + try { + this.lexer.match(TokenTypes.RECORD_ROUTE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + while (true) { + RecordRoute recordRoute = new RecordRoute(); + super.parse(recordRoute); + recordRouteList.add(recordRoute); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (la == '\n') + break; + else + throw createParseException("unexpected char"); + } + return recordRouteList; + } finally { + if (debug) + dbg_leave("RecordRouteParser.parse"); + } + + } + + +} diff --git a/java/gov/nist/javax/sip/parser/ReferToParser.java b/java/gov/nist/javax/sip/parser/ReferToParser.java new file mode 100644 index 0000000..a4d7d01 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ReferToParser.java @@ -0,0 +1,190 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +/** + * To Header parser. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:03 $ + * + * @author Olivier Deruelle <br/> + * + * + * + */ +public class ReferToParser extends AddressParametersParser { + + /** + * Creates new ToParser + * @param referTo String to set + */ + public ReferToParser(String referTo) { + super(referTo); + } + + protected ReferToParser(Lexer lexer) { + super(lexer); + } + public SIPHeader parse() throws ParseException { + + headerName(TokenTypes.REFER_TO); + ReferTo referTo = new ReferTo(); + super.parse(referTo); + this.lexer.match('\n'); + return referTo; + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Refer-To: <sip:dave@denver.example.org?" + + "Replaces=12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994>\n", + "Refer-To: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\n", + "Refer-To: T. A. Watson <sip:watson@bell-telephone.com>\n", + "Refer-To: LittleGuy <sip:UserB@there.com>\n", + "Refer-To: sip:mranga@120.6.55.9\n", + "Refer-To: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\n" }; + + for (int i = 0; i < to.length; i++) { + ReferToParser tp = new ReferToParser(to[i]); + ReferTo t = (ReferTo) tp.parse(); + System.out.println("encoded = " + t.encode()); + + } + } +} +/* + * $Log: ReferToParser.java,v $ + * Revision 1.8 2009/07/17 18:58:03 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:21 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.5 2005/03/29 03:50:01 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * + * Remove transaction for early bye. + * Reviewed by: + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2005/03/27 14:00:14 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * + * Added example + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ReplyToParser.java b/java/gov/nist/javax/sip/parser/ReplyToParser.java new file mode 100644 index 0000000..356ca26 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ReplyToParser.java @@ -0,0 +1,162 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +/** + * Parser for a list of RelpyTo headers. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:03 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + */ +public class ReplyToParser extends AddressParametersParser { + + /** + * Creates a new instance of ReplyToParser + * @param replyTo the header to parse + */ + public ReplyToParser(String replyTo) { + super(replyTo); + } + + /** + * Cosntructor + * param lexer the lexer to use to parse the header + */ + protected ReplyToParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message and generate the ReplyTo List Object + * @return SIPHeader the ReplyTo List object + * @throws SIPParseException if errors occur during the parsing + */ + public SIPHeader parse() throws ParseException { + ReplyTo replyTo = new ReplyTo(); + if (debug) + dbg_enter("ReplyTo.parse"); + + try { + headerName(TokenTypes.REPLY_TO); + + replyTo.setHeaderName(SIPHeaderNames.REPLY_TO); + + super.parse(replyTo); + + return replyTo; + } finally { + if (debug) + dbg_leave("ReplyTo.parse"); + } + + } + + /** + public static void main(String args[]) throws ParseException { + String r[] = { + "Reply-To: Bob <sip:bob@biloxi.com>\n" + }; + + for (int i = 0; i < r.length; i++ ) { + ReplyToParser rt = + new ReplyToParser(r[i]); + ReplyTo re = (ReplyTo) rt.parse(); + System.out.println("encoded = " +re.encode()); + } + + } + */ +} +/* + * $Log: ReplyToParser.java,v $ + * Revision 1.7 2009/07/17 18:58:03 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RequestLineParser.java b/java/gov/nist/javax/sip/parser/RequestLineParser.java new file mode 100644 index 0000000..01ae13d --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RequestLineParser.java @@ -0,0 +1,181 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.address.*; +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +/** + * Parser for the SIP request line. + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + */ +public class RequestLineParser extends Parser { + public RequestLineParser(String requestLine) { + this.lexer = new Lexer("method_keywordLexer", requestLine); + } + public RequestLineParser(Lexer lexer) { + this.lexer = lexer; + this.lexer.selectLexer("method_keywordLexer"); + } + + public RequestLine parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + RequestLine retval = new RequestLine(); + String m = method(); + lexer.SPorHT(); + retval.setMethod(m); + this.lexer.selectLexer("sip_urlLexer"); + URLParser urlParser = new URLParser(this.getLexer()); + GenericURI url = urlParser.uriReference(true); + lexer.SPorHT(); + retval.setUri(url); + this.lexer.selectLexer("request_lineLexer"); + String v = sipVersion(); + retval.setSipVersion(v); + lexer.SPorHT(); + lexer.match('\n'); + return retval; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + public static void main(String args[]) throws ParseException { + String requestLines[] = { + "REGISTER sip:192.168.0.68 SIP/2.0\n", + "REGISTER sip:company.com SIP/2.0\n", + "INVITE sip:3660@166.35.231.140 SIP/2.0\n", + "INVITE sip:user@company.com SIP/2.0\n", + "REGISTER sip:[2001::1]:5060;transport=tcp SIP/2.0\n", // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + "REGISTER sip:[2002:800:700:600:30:4:6:1]:5060;transport=udp SIP/2.0\n", // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + "REGISTER sip:[3ffe:800:700::30:4:6:1]:5060;transport=tls SIP/2.0\n", // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + "REGISTER sip:[2001:720:1710:0:201:29ff:fe21:f403]:5060;transport=udp SIP/2.0\n", + "OPTIONS sip:135.180.130.133 SIP/2.0\n" }; + for (int i = 0; i < requestLines.length; i++ ) { + RequestLineParser rlp = + new RequestLineParser(requestLines[i]); + RequestLine rl = rlp.parse(); + System.out.println("encoded = " + rl.encode()); + } + + } + +} +/* + * $Log: RequestLineParser.java,v $ + * Revision 1.11 2009/10/22 10:27:38 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.10 2009/09/15 02:55:27 mranga + * Issue number: 222 + * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String) + * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies + * during call transfer). + * + * Revision 1.9 2009/07/17 18:58:03 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.8 2006/07/13 09:02:14 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:35 mranga + * + * Import + * + * + * Revision 1.6 2004/10/28 19:02:50 mranga + * Submitted by: Daniel Martinez + * Reviewed by: M. Ranganathan + * + * Added changes for TLS support contributed by Daniel Martinez + * + * Revision 1.5 2004/06/27 00:41:51 mranga + * Submitted by: Thomas Froment and Pierre De Rop + * Reviewed by: mranga + * Performance improvements + * (auxiliary data structure for fast lookup of transactions). + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RequireParser.java b/java/gov/nist/javax/sip/parser/RequireParser.java new file mode 100644 index 0000000..ed942b5 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RequireParser.java @@ -0,0 +1,191 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Require header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:04 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class RequireParser extends HeaderParser { + + /** + * Creates a new instance of RequireParser + * @param require the header to parse + */ + public RequireParser(String require) { + super(require); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected RequireParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (RequireList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + RequireList requireList = new RequireList(); + if (debug) + dbg_enter("RequireParser.parse"); + + try { + headerName(TokenTypes.REQUIRE); + + while (lexer.lookAhead(0) != '\n') { + Require r = new Require(); + r.setHeaderName(SIPHeaderNames.REQUIRE); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + r.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + requireList.add(r); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + r = new Require(); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + r.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + requireList.add(r); + } + + } + } finally { + if (debug) + dbg_leave("RequireParser.parse"); + } + + return requireList; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String r[] = { + "Require: 100rel \n", + "Require: 100rel, 200ok , 389\n" + }; + + for (int i = 0; i < r.length; i++ ) { + RequireParser parser = + new RequireParser(r[i]); + RequireList rl= (RequireList) parser.parse(); + System.out.println("encoded = " + rl.encode()); + } + } + */ + +} +/* + * $Log: RequireParser.java,v $ + * Revision 1.7 2009/07/17 18:58:04 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:18 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:31 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/RetryAfterParser.java b/java/gov/nist/javax/sip/parser/RetryAfterParser.java new file mode 100644 index 0000000..9419186 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RetryAfterParser.java @@ -0,0 +1,131 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for RetryAfter header. + * + * @version 1.2 + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/04 17:23:00 $ + */ +public class RetryAfterParser extends HeaderParser { + + /** + * Creates a new instance of RetryAfterParser + * @param retryAfter the header to parse + */ + public RetryAfterParser(String retryAfter) { + super(retryAfter); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected RetryAfterParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (RetryAfter object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("RetryAfterParser.parse"); + + RetryAfter retryAfter = new RetryAfter(); + try { + headerName(TokenTypes.RETRY_AFTER); + + // mandatory delatseconds: + String value = lexer.number(); + try { + int ds = Integer.parseInt(value); + retryAfter.setRetryAfter(ds); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + + this.lexer.SPorHT(); + if (lexer.lookAhead(0) == '(') { + String comment = this.lexer.comment(); + retryAfter.setComment(comment); + } + this.lexer.SPorHT(); + + while (lexer.lookAhead(0) == ';') { + this.lexer.match(';'); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + value = token.getTokenValue(); + if (value.equalsIgnoreCase("duration")) { + this.lexer.match('='); + this.lexer.SPorHT(); + value = lexer.number(); + try { + int duration = Integer.parseInt(value); + retryAfter.setDuration(duration); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + } else { + this.lexer.SPorHT(); + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token secondToken = lexer.getNextToken(); + String secondValue = secondToken.getTokenValue(); + retryAfter.setParameter(value, secondValue); + } + this.lexer.SPorHT(); + } + } finally { + if (debug) + dbg_leave("RetryAfterParser.parse"); + } + + return retryAfter; + } + +} diff --git a/java/gov/nist/javax/sip/parser/RouteParser.java b/java/gov/nist/javax/sip/parser/RouteParser.java new file mode 100644 index 0000000..a47eb9a --- /dev/null +++ b/java/gov/nist/javax/sip/parser/RouteParser.java @@ -0,0 +1,176 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +/** + * Parser for a list of route headers. + * + * @version 1.2 + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + *@version 1.0 + */ +public class RouteParser extends AddressParametersParser { + + /** + * Constructor + * @param route message to parse to set + */ + public RouteParser(String route) { + super(route); + } + + protected RouteParser(Lexer lexer) { + super(lexer); + } + + /** parse the String message and generate the Route List Object + * @return SIPHeader the Route List object + * @throws SIPParseException if errors occur during the parsing + */ + public SIPHeader parse() throws ParseException { + RouteList routeList = new RouteList(); + if (debug) + dbg_enter("parse"); + + try { + this.lexer.match(TokenTypes.ROUTE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + while (true) { + Route route = new Route(); + super.parse(route); + routeList.add(route); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (la == '\n') + break; + else + throw createParseException("unexpected char"); + } + return routeList; + } finally { + if (debug) + dbg_leave("parse"); + } + + } + + /** + public static void main(String args[]) throws ParseException { + String rou[] = { + "Route: <sip:alice@atlanta.com>\n", + "Route: sip:bob@biloxi.com \n", + "Route: sip:alice@atlanta.com, sip:bob@biloxi.com, sip:carol@chicago.com\n" + }; + + for (int i = 0; i < rou.length; i++ ) { + RouteParser rp = + new RouteParser(rou[i]); + RouteList routeList = (RouteList) rp.parse(); + System.out.println("encoded = " +routeList.encode()); + } + + } + + */ +} +/* + * $Log: RouteParser.java,v $ + * Revision 1.8 2009/07/17 18:58:04 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2007/02/06 16:40:03 belangery + * Introduced simple code optimizations. + * + * Revision 1.6 2006/07/13 09:02:07 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/SIPETagParser.java b/java/gov/nist/javax/sip/parser/SIPETagParser.java new file mode 100644 index 0000000..be02312 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SIPETagParser.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for SIP-ETag header. + * + * + * @author Jeroen van Bemmel <br/> + * + * + * + * @version 1.2 + * @since 1.2 + */ +public class SIPETagParser extends HeaderParser { + + /** + * Creates a new instance of PriorityParser + * @param etag the header to parse + */ + public SIPETagParser(String etag) { + super(etag); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected SIPETagParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String header + * @return SIPHeader (Priority object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("SIPEtag.parse"); + + SIPETag sipEtag = new SIPETag(); + try { + headerName(TokenTypes.SIP_ETAG); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + + sipEtag.setETag(token.getTokenValue()); + + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return sipEtag; + } finally { + if (debug) + dbg_leave("SIPEtag.parse"); + } + } +} +/* + * $Log: SIPETagParser.java,v $ + * Revision 1.3 2009/07/17 18:58:04 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.2 2006/07/13 09:01:58 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/SIPIfMatchParser.java b/java/gov/nist/javax/sip/parser/SIPIfMatchParser.java new file mode 100644 index 0000000..0162449 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SIPIfMatchParser.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for SIP-If-Match header. + * + * + * @author Jeroen van Bemmel <br/> + * + * + * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:58:04 $ + * + * @since 1.2 + */ +public class SIPIfMatchParser extends HeaderParser { + + /** + * Creates a new instance of PriorityParser + * @param etag the header to parse + */ + public SIPIfMatchParser(String etag) { + super(etag); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected SIPIfMatchParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String header + * @return SIPHeader (Priority object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("SIPIfMatch.parse"); + + SIPIfMatch sipIfMatch = new SIPIfMatch(); + try { + headerName(TokenTypes.SIP_IF_MATCH); + + this.lexer.SPorHT(); + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + + sipIfMatch.setETag(token.getTokenValue()); + + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return sipIfMatch; + } finally { + if (debug) + dbg_leave("SIPIfMatch.parse"); + } + } +} +/* + * $Log: SIPIfMatchParser.java,v $ + * Revision 1.3 2009/07/17 18:58:04 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.2 2006/07/13 09:02:08 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/SIPMessageListener.java b/java/gov/nist/javax/sip/parser/SIPMessageListener.java new file mode 100644 index 0000000..e4d6dde --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SIPMessageListener.java @@ -0,0 +1,116 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * +*******************************************************************************/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.message.*; + +/** + * Interface that provides methods for processing good + * and bad messages for the PipelinedMessageParser. + * + * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:04 $ + * @see PipelinedMsgParser + */ +public interface SIPMessageListener extends ParseExceptionListener { + /** + * This is called from the parser on successful message processing. + * @see ParseExceptionListener for the method that gets called + * on parse exception. + * @param msg SIP Message structure that is generated by the parser. + */ + public void processMessage(SIPMessage msg) throws Exception; +} +/* + * $Log: SIPMessageListener.java,v $ + * Revision 1.8 2009/07/17 18:58:04 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.5 2004/02/29 00:46:34 mranga + * Reviewed by: mranga + * Added new configuration property to limit max message size for TCP transport. + * The property is gov.nist.javax.sip.MAX_MESSAGE_SIZE + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ServerParser.java b/java/gov/nist/javax/sip/parser/ServerParser.java new file mode 100644 index 0000000..413ac53 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ServerParser.java @@ -0,0 +1,205 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for Server header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:05 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class ServerParser extends HeaderParser { + + /** + * Creates a new instance of ServerParser + * @param server the header to parse + */ + public ServerParser(String server) { + super(server); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ServerParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String server + * @return SIPHeader (Server object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ServerParser.parse"); + Server server = new Server(); + try { + headerName(TokenTypes.SERVER); + if (this.lexer.lookAhead(0) == '\n') + throw createParseException("empty header"); + + // mandatory token: product[/product-version] | (comment) + while (this.lexer.lookAhead(0) != '\n' + && this.lexer.lookAhead(0) != '\0') { + if (this.lexer.lookAhead(0) == '(') { + String comment = this.lexer.comment(); + server.addProductToken('(' + comment + ')'); + } else { + String tok; + int marker = 0; + try { + marker = this.lexer.markInputPosition(); + tok = this.lexer.getString('/'); + + if (tok.charAt(tok.length() - 1) == '\n') + tok = tok.trim(); + server.addProductToken(tok); + } catch (ParseException ex) { + this.lexer.rewindInputPosition(marker); + tok = this.lexer.getRest().trim(); + server.addProductToken(tok); + break; + } + } + } + + } finally { + if (debug) + dbg_leave("ServerParser.parse"); + } + + return server; + } + +/* + public static void main(String args[]) throws ParseException { + String server[] = { + "Server: Softphone/Beta1.5 \n", + "Server: HomeServer v2\n", + "Server: Nist/Beta1 (beta version) \n", + "Server: Nist proxy (beta version)\n", + "Server: Nist1.0/Beta2 UbiServer/vers.1.0 (new stuff) (Cool) \n", + "Server: Sip EXpress router (0.8.11 (sparc64/solaris))\n" + }; + + for (int i = 0; i < server.length; i++ ) { + ServerParser parser = + new ServerParser(server[i]); + Server s= (Server) parser.parse(); + System.out.println("encoded = " + s.encode()); + } + + } +*/ + +} +/* + * $Log: ServerParser.java,v $ + * Revision 1.9 2009/07/17 18:58:05 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.8 2006/07/13 09:02:16 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/17 10:18:14 mranga + * Added some synchronization to the sequence number checking. + * Small javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.6 2004/01/30 17:10:47 mranga + * Reviewed by: mranga + * Server and user agent parser leave an extra Linefeed at the end of token. + * + * Revision 1.5 2004/01/27 13:52:11 mranga + * Reviewed by: mranga + * Fixed server/user-agent parser. + * suppress sending ack to TU when retransFilter is enabled and ack is retransmitted. + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/StatusLineParser.java b/java/gov/nist/javax/sip/parser/StatusLineParser.java new file mode 100644 index 0000000..3f088b5 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/StatusLineParser.java @@ -0,0 +1,175 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for the SIP status line. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:05 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public class StatusLineParser extends Parser { + public StatusLineParser(String statusLine) { + this.lexer = new Lexer("status_lineLexer", statusLine); + } + + public StatusLineParser(Lexer lexer) { + this.lexer = lexer; + this.lexer.selectLexer("status_lineLexer"); + } + + protected int statusCode() throws ParseException { + String scode = this.lexer.number(); + if (debug) + dbg_enter("statusCode"); + try { + int retval = Integer.parseInt(scode); + return retval; + } catch (NumberFormatException ex) { + throw new ParseException( + lexer.getBuffer() + ":" + ex.getMessage(), + lexer.getPtr()); + } finally { + if (debug) + dbg_leave("statusCode"); + } + + } + + protected String reasonPhrase() throws ParseException { + return this.lexer.getRest().trim(); + } + + public StatusLine parse() throws ParseException { + try { + if (debug) + dbg_enter("parse"); + StatusLine retval = new StatusLine(); + String version = this.sipVersion(); + retval.setSipVersion(version); + lexer.SPorHT(); + int scode = statusCode(); + retval.setStatusCode(scode); + lexer.SPorHT(); + String rp = reasonPhrase(); + retval.setReasonPhrase(rp); + lexer.SPorHT(); + return retval; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + /** + public static void main(String[] args) throws ParseException { + String[] statusLines = { + "SIP/2.0 200 OK\n", + "BOO 200 OK\n", + "SIP/2.0 500 OK bad things happened \n" + }; + for (int i = 0 ; i < statusLines.length; i++) { + try { + StatusLineParser slp = new StatusLineParser(statusLines[i]); + StatusLine sl = slp.parse(); + System.out.println("encoded = " + sl.encode()); + } catch (ParseException ex) { + System.out.println("error message " + ex.getMessage()); + } + } + } + */ +} +/* + * $Log: StatusLineParser.java,v $ + * Revision 1.7 2009/07/17 18:58:05 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:20 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/StringMsgParser.java b/java/gov/nist/javax/sip/parser/StringMsgParser.java new file mode 100644 index 0000000..9e46d12 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/StringMsgParser.java @@ -0,0 +1,709 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ + +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD) * + ******************************************************************************/ + +package gov.nist.javax.sip.parser; + +import gov.nist.core.Host; +import gov.nist.core.HostNameParser; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.GenericURI; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.address.TelephoneNumber; +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +/* + * Acknowledgement: 1/12/2007: Yanick Belanger rewrote the parsing loops to make them + * simpler and quicker. + */ + +/** + * Parse SIP message and parts of SIP messages such as URI's etc from memory and + * return a structure. Intended use: UDP message processing. This class is used + * when you have an entire SIP message or SIPHeader or SIP URL in memory and you + * want to generate a parsed structure from it. For SIP messages, the payload + * can be binary or String. If you have a binary payload, use + * parseSIPMessage(byte[]) else use parseSIPMessage(String) The payload is + * accessible from the parsed message using the getContent and getContentBytes + * methods provided by the SIPMessage class. If SDP parsing is enabled using the + * parseContent method, then the SDP body is also parsed and can be accessed + * from the message using the getSDPAnnounce method. Currently only eager + * parsing of the message is supported (i.e. the entire message is parsed in one + * feld swoop). + * + * + * @version 1.2 $Revision: 1.26 $ $Date: 2009/10/22 10:27:38 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class StringMsgParser { + + protected boolean readBody; + private ParseExceptionListener parseExceptionListener; + private String rawStringMessage; + private boolean strict; + + private static boolean computeContentLengthFromMessage = false; + + /** + * @since v0.9 + */ + public StringMsgParser() { + super(); + readBody = true; + } + + /** + * Constructor (given a parse exception handler). + * + * @since 1.0 + * @param exhandler + * is the parse exception listener for the message parser. + */ + public StringMsgParser(ParseExceptionListener exhandler) { + this(); + parseExceptionListener = exhandler; + } + + /** + * Add a handler for header parsing errors. + * + * @param pexhandler + * is a class that implements the ParseExceptionListener + * interface. + */ + public void setParseExceptionListener(ParseExceptionListener pexhandler) { + parseExceptionListener = pexhandler; + } + + /** + * Parse a buffer containing a single SIP Message where the body is an array + * of un-interpreted bytes. This is intended for parsing the message from a + * memory buffer when the buffer. Incorporates a bug fix for a bug that was + * noted by Will Sullin of Callcast + * + * @param msgBuffer + * a byte buffer containing the messages to be parsed. This can + * consist of multiple SIP Messages concatenated together. + * @return a SIPMessage[] structure (request or response) containing the + * parsed SIP message. + * @exception ParseException + * is thrown when an illegal message has been encountered + * (and the rest of the buffer is discarded). + * @see ParseExceptionListener + */ + public SIPMessage parseSIPMessage(byte[] msgBuffer) throws ParseException { + if (msgBuffer == null || msgBuffer.length == 0) + return null; + + int i = 0; + + // Squeeze out any leading control character. + try { + while (msgBuffer[i] < 0x20) + i++; + } + catch (ArrayIndexOutOfBoundsException e) { + // Array contains only control char, return null. + return null; + } + + // Iterate thru the request/status line and headers. + String currentLine = null; + String currentHeader = null; + boolean isFirstLine = true; + SIPMessage message = null; + do + { + int lineStart = i; + + // Find the length of the line. + try { + while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n') + i++; + } + catch (ArrayIndexOutOfBoundsException e) { + // End of the message. + break; + } + int lineLength = i - lineStart; + + // Make it a String. + try { + currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new ParseException("Bad message encoding!", 0); + } + + currentLine = trimEndOfLine(currentLine); + + if (currentLine.length() == 0) { + // Last header line, process the previous buffered header. + if (currentHeader != null && message != null) { + processHeader(currentHeader, message); + } + + } + else { + if (isFirstLine) { + message = processFirstLine(currentLine); + } else { + char firstChar = currentLine.charAt(0); + if (firstChar == '\t' || firstChar == ' ') { + if (currentHeader == null) + throw new ParseException("Bad header continuation.", 0); + + // This is a continuation, append it to the previous line. + currentHeader += currentLine.substring(1); + } + else { + if (currentHeader != null && message != null) { + processHeader(currentHeader, message); + } + currentHeader = currentLine; + } + } + } + + if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n') + i++; + + i++; + + isFirstLine = false; + } while (currentLine.length() > 0); // End do - while + + if (message == null) throw new ParseException("Bad message", 0); + message.setSize(i); + + if (readBody && message.getContentLength() != null && + message.getContentLength().getContentLength() != 0) { + + int bodyLength = msgBuffer.length - i; + + byte[] body = new byte[bodyLength]; + System.arraycopy(msgBuffer, i, body, 0, bodyLength); + message.setMessageContent(body,computeContentLengthFromMessage ,message.getContentLength().getContentLength() ); + } + + return message; + } + + /** + * Parse a buffer containing one or more SIP Messages and return an array of + * SIPMessage parsed structures. + * + * @param msgString + * a String containing the messages to be parsed. This can + * consist of multiple SIP Messages concatenated together. + * @return a SIPMessage structure (request or response) containing the + * parsed SIP message. + * @exception ParseException + * is thrown when an illegal message has been encountered + * (and the rest of the buffer is discarded). + * @see ParseExceptionListener + */ + public SIPMessage parseSIPMessage(String msgString) throws ParseException { + if (msgString == null || msgString.length() == 0) + return null; + + rawStringMessage = msgString; + + int i = 0; + + // Squeeze out any leading control character. + try { + while (msgString.charAt(i) < 0x20) + i++; + } + catch (ArrayIndexOutOfBoundsException e) { + // Array contains only control char, return null. + return null; + } catch (StringIndexOutOfBoundsException ex) { + return null; + } + + // Iterate thru the request/status line and headers. + String currentLine = null; + String currentHeader = null; + boolean isFirstLine = true; + SIPMessage message = null; + do + { + int lineStart = i; + + // Find the length of the line. + try { + char c = msgString.charAt(i); + while (c != '\r' && c != '\n') + c = msgString.charAt(++i); + } + catch (ArrayIndexOutOfBoundsException e) { + // End of the message. + break; + } catch ( StringIndexOutOfBoundsException ex) { + break; + } + + // Make it a String. + currentLine = msgString.substring(lineStart, i); + currentLine = trimEndOfLine(currentLine); + + if (currentLine.length() == 0) { + // Last header line, process the previous buffered header. + if (currentHeader != null) { + processHeader(currentHeader, message); + } + } + else { + if (isFirstLine) { + message = processFirstLine(currentLine); + } else { + char firstChar = currentLine.charAt(0); + if (firstChar == '\t' || firstChar == ' ') { + if (currentHeader == null) + throw new ParseException("Bad header continuation.", 0); + + // This is a continuation, append it to the previous line. + currentHeader += currentLine.substring(1); + } + else { + if (currentHeader != null) { + processHeader(currentHeader, message); + } + currentHeader = currentLine; + } + } + } + + if (msgString.charAt(i) == '\r' && msgString.length() > i+1 && msgString.charAt(i+1) == '\n') + i++; + + i++; + + isFirstLine = false; + } + while (currentLine.length() > 0); + + message.setSize(i); + + // Check for content legth header + if (readBody && message.getContentLength() != null ) { + if ( message.getContentLength().getContentLength() != 0) { + String body = msgString.substring(i); + message.setMessageContent(body,this.strict,computeContentLengthFromMessage,message.getContentLength().getContentLength()); + } else if (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 && !msgString.endsWith("\r\n\r\n") ){ + if ( strict ) { + throw new ParseException("Extraneous characters at the end of the message ",i); + } + } + + } + + return message; + } + + private String trimEndOfLine(String line) { + if (line == null) + return line; + + int i = line.length() - 1; + while (i >= 0 && line.charAt(i) <= 0x20) + i--; + + if (i == line.length() - 1) + return line; + + if (i == -1) + return ""; + + return line.substring(0, i+1); + } + + private SIPMessage processFirstLine(String firstLine) throws ParseException { + SIPMessage message; + if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) { + message = new SIPRequest(); + try { + RequestLine requestLine = new RequestLineParser(firstLine + "\n") + .parse(); + ((SIPRequest) message).setRequestLine(requestLine); + } catch (ParseException ex) { + if (this.parseExceptionListener != null) + this.parseExceptionListener.handleException(ex, message, + RequestLine.class, firstLine, rawStringMessage); + else + throw ex; + + } + } else { + message = new SIPResponse(); + try { + StatusLine sl = new StatusLineParser(firstLine + "\n").parse(); + ((SIPResponse) message).setStatusLine(sl); + } catch (ParseException ex) { + if (this.parseExceptionListener != null) { + this.parseExceptionListener.handleException(ex, message, + StatusLine.class, firstLine, rawStringMessage); + } else + throw ex; + + } + } + return message; + } + + private void processHeader(String header, SIPMessage message) throws ParseException { + if (header == null || header.length() == 0) + return; + + HeaderParser headerParser = null; + try { + headerParser = ParserFactory.createParser(header + "\n"); + } catch (ParseException ex) { + this.parseExceptionListener.handleException(ex, message, null, + header, rawStringMessage); + return; + } + + try { + SIPHeader sipHeader = headerParser.parse(); + message.attachHeader(sipHeader, false); + } catch (ParseException ex) { + if (this.parseExceptionListener != null) { + String headerName = Lexer.getHeaderName(header); + Class headerClass = NameMap.getClassFromName(headerName); + if (headerClass == null) { + headerClass = ExtensionHeaderImpl.class; + + } + this.parseExceptionListener.handleException(ex, message, + headerClass, header, rawStringMessage); + + } + } + } + + /** + * Parse an address (nameaddr or address spec) and return and address + * structure. + * + * @param address + * is a String containing the address to be parsed. + * @return a parsed address structure. + * @since v1.0 + * @exception ParseException + * when the address is badly formatted. + */ + public AddressImpl parseAddress(String address) throws ParseException { + AddressParser addressParser = new AddressParser(address); + return addressParser.address(true); + } + + /** + * Parse a host:port and return a parsed structure. + * + * @param hostport + * is a String containing the host:port to be parsed + * @return a parsed address structure. + * @since v1.0 + * @exception throws + * a ParseException when the address is badly formatted. + * + public HostPort parseHostPort(String hostport) throws ParseException { + Lexer lexer = new Lexer("charLexer", hostport); + return new HostNameParser(lexer).hostPort(); + + } + */ + + /** + * Parse a host name and return a parsed structure. + * + * @param host + * is a String containing the host name to be parsed + * @return a parsed address structure. + * @since v1.0 + * @exception ParseException + * a ParseException when the hostname is badly formatted. + */ + public Host parseHost(String host) throws ParseException { + Lexer lexer = new Lexer("charLexer", host); + return new HostNameParser(lexer).host(); + + } + + /** + * Parse a telephone number return a parsed structure. + * + * @param telephone_number + * is a String containing the telephone # to be parsed + * @return a parsed address structure. + * @since v1.0 + * @exception ParseException + * a ParseException when the address is badly formatted. + */ + public TelephoneNumber parseTelephoneNumber(String telephone_number) + throws ParseException { + // Bug fix contributed by Will Scullin + return new URLParser(telephone_number).parseTelephoneNumber(true); + + } + + /** + * Parse a SIP url from a string and return a URI structure for it. + * + * @param url + * a String containing the URI structure to be parsed. + * @return A parsed URI structure + * @exception ParseException + * if there was an error parsing the message. + */ + + public SipUri parseSIPUrl(String url) throws ParseException { + try { + return new URLParser(url).sipURL(true); + } catch (ClassCastException ex) { + throw new ParseException(url + " Not a SIP URL ", 0); + } + } + + /** + * Parse a uri from a string and return a URI structure for it. + * + * @param url + * a String containing the URI structure to be parsed. + * @return A parsed URI structure + * @exception ParseException + * if there was an error parsing the message. + */ + + public GenericURI parseUrl(String url) throws ParseException { + return new URLParser(url).parse(); + } + + /** + * Parse an individual SIP message header from a string. + * + * @param header + * String containing the SIP header. + * @return a SIPHeader structure. + * @exception ParseException + * if there was an error parsing the message. + */ + public SIPHeader parseSIPHeader(String header) throws ParseException { + int start = 0; + int end = header.length() - 1; + try { + // Squeeze out any leading control character. + while (header.charAt(start) <= 0x20) + start++; + + // Squeeze out any trailing control character. + while (header.charAt(end) <= 0x20) + end--; + } + catch (ArrayIndexOutOfBoundsException e) { + // Array contains only control char. + throw new ParseException("Empty header.", 0); + } + + StringBuffer buffer = new StringBuffer(end + 1); + int i = start; + int lineStart = start; + boolean endOfLine = false; + while (i <= end) { + char c = header.charAt(i); + if (c == '\r' || c == '\n') { + if (!endOfLine) { + buffer.append(header.substring(lineStart, i)); + endOfLine = true; + } + } + else { + if (endOfLine) { + endOfLine = false; + if (c == ' ' || c == '\t') { + buffer.append(' '); + lineStart = i + 1; + } + else { + lineStart = i; + } + } + } + + i++; + } + buffer.append(header.substring(lineStart, i)); + buffer.append('\n'); + + HeaderParser hp = ParserFactory.createParser(buffer.toString()); + if (hp == null) + throw new ParseException("could not create parser", 0); + return hp.parse(); + } + + /** + * Parse the SIP Request Line + * + * @param requestLine + * a String containing the request line to be parsed. + * @return a RequestLine structure that has the parsed RequestLine + * @exception ParseException + * if there was an error parsing the requestLine. + */ + + public RequestLine parseSIPRequestLine(String requestLine) + throws ParseException { + requestLine += "\n"; + return new RequestLineParser(requestLine).parse(); + } + + /** + * Parse the SIP Response message status line + * + * @param statusLine + * a String containing the Status line to be parsed. + * @return StatusLine class corresponding to message + * @exception ParseException + * if there was an error parsing + * @see StatusLine + */ + + public StatusLine parseSIPStatusLine(String statusLine) + throws ParseException { + statusLine += "\n"; + return new StatusLineParser(statusLine).parse(); + } + + public static void setComputeContentLengthFromMessage( + boolean computeContentLengthFromMessage) { + StringMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage; + } + + + + /** + * Test code. + */ + public static void main(String[] args) throws ParseException { + String messages[] = { + "SIP/2.0 200 OK\r\n" + + "To: \"The Little Blister\" <sip:LittleGuy@there.com>;tag=469bc066\r\n" + + "From: \"The Master Blaster\" <sip:BigGuy@here.com>;tag=11\r\n" + + "Via: SIP/2.0/UDP 139.10.134.246:5060;branch=z9hG4bK8b0a86f6_1030c7d18e0_17;received=139.10.134.246\r\n" + + "Call-ID: 1030c7d18ae_a97b0b_b@8b0a86f6\r\n" + + "CSeq: 1 SUBSCRIBE\r\n" + + "Contact: <sip:172.16.11.162:5070>\r\n" + + "Content-Length: 0\r\n\r\n", + + "SIP/2.0 180 Ringing\r\n" + + "Via: SIP/2.0/UDP 172.18.1.29:5060;branch=z9hG4bK43fc10fb4446d55fc5c8f969607991f4\r\n" + + "To: \"0440\" <sip:0440@212.209.220.131>;tag=2600\r\n" + + "From: \"Andreas\" <sip:andreas@e-horizon.se>;tag=8524\r\n" + + "Call-ID: f51a1851c5f570606140f14c8eb64fd3@172.18.1.29\r\n" + + "CSeq: 1 INVITE\r\n" + "Max-Forwards: 70\r\n" + + "Record-Route: <sip:212.209.220.131:5060>\r\n" + + "Content-Length: 0\r\n\r\n", + "REGISTER sip:nist.gov SIP/2.0\r\n" + + "Via: SIP/2.0/UDP 129.6.55.182:14826\r\n" + + "Max-Forwards: 70\r\n" + + "From: <sip:mranga@nist.gov>;tag=6fcd5c7ace8b4a45acf0f0cd539b168b;epid=0d4c418ddf\r\n" + + "To: <sip:mranga@nist.gov>\r\n" + + "Call-ID: c5679907eb954a8da9f9dceb282d7230@129.6.55.182\r\n" + + "CSeq: 1 REGISTER\r\n" + + "Contact: <sip:129.6.55.182:14826>;methods=\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER\"\r\n" + + "User-Agent: RTC/(Microsoft RTC)\r\n" + + "Event: registration\r\n" + + "Allow-Events: presence\r\n" + + "Content-Length: 0\r\n\r\n" + + "INVITE sip:littleguy@there.com:5060 SIP/2.0\r\n" + + "Via: SIP/2.0/UDP 65.243.118.100:5050\r\n" + + "From: M. Ranganathan <sip:M.Ranganathan@sipbakeoff.com>;tag=1234\r\n" + + "To: \"littleguy@there.com\" <sip:littleguy@there.com:5060> \r\n" + + "Call-ID: Q2AboBsaGn9!?x6@sipbakeoff.com \r\n" + + "CSeq: 1 INVITE \r\n" + + "Content-Length: 247\r\n\r\n" + + "v=0\r\n" + + "o=4855 13760799956958020 13760799956958020 IN IP4 129.6.55.78\r\n" + + "s=mysession session\r\n" + "p=+46 8 52018010\r\n" + + "c=IN IP4 129.6.55.78\r\n" + "t=0 0\r\n" + + "m=audio 6022 RTP/AVP 0 4 18\r\n" + + "a=rtpmap:0 PCMU/8000\r\n" + + "a=rtpmap:4 G723/8000\r\n" + + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n" }; + + class ParserThread implements Runnable { + String[] messages; + + public ParserThread(String[] messagesToParse) { + this.messages = messagesToParse; + } + + public void run() { + for (int i = 0; i < messages.length; i++) { + StringMsgParser smp = new StringMsgParser(); + try { + SIPMessage sipMessage = smp + .parseSIPMessage(messages[i]); + System.out.println(" i = " + i + " branchId = " + + sipMessage.getTopmostVia().getBranch()); + // System.out.println("encoded " + + // sipMessage.toString()); + } catch (ParseException ex) { + + } + + // System.out.println("dialog id = " + + // sipMessage.getDialogId(false)); + } + } + } + + for (int i = 0; i < 20; i++) { + new Thread(new ParserThread(messages)).start(); + } + + } + + public void setStrict(boolean strict) { + this.strict = strict; + + } + +} diff --git a/java/gov/nist/javax/sip/parser/SubjectParser.java b/java/gov/nist/javax/sip/parser/SubjectParser.java new file mode 100644 index 0000000..e2e898e --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SubjectParser.java @@ -0,0 +1,165 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for Subject header. + * + * @version 1.2 + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class SubjectParser extends HeaderParser { + + /** + * Creates a new instance of SubjectParser + * @param subject the header to parse + */ + public SubjectParser(String subject) { + super(subject); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected SubjectParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (Subject object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + Subject subject = new Subject(); + if (debug) + dbg_enter("SubjectParser.parse"); + + try { + headerName(TokenTypes.SUBJECT); + + this.lexer.SPorHT(); + + String s = this.lexer.getRest(); + subject.setSubject(s.trim()); + + } finally { + if (debug) + dbg_leave("SubjectParser.parse"); + } + + return subject; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String subject[] = { + "Subject: Where is the Moscone?\n", + "Subject: Need more boxes\n" + }; + + for (int i = 0; i < subject.length; i++ ) { + SubjectParser parser = + new SubjectParser(subject[i]); + Subject s= (Subject) parser.parse(); + System.out.println("encoded = " +s.encode()); + } + + } + */ +} +/* + * $Log: SubjectParser.java,v $ + * Revision 1.7 2009/07/17 18:58:05 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:17 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/SubscriptionStateParser.java b/java/gov/nist/javax/sip/parser/SubscriptionStateParser.java new file mode 100644 index 0000000..f50b156 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SubscriptionStateParser.java @@ -0,0 +1,222 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for SubscriptionState header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:05 $ + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + */ +public class SubscriptionStateParser extends HeaderParser { + + /** + * Creates a new instance of SubscriptionStateParser + * @param subscriptionState the header to parse + */ + public SubscriptionStateParser(String subscriptionState) { + super(subscriptionState); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected SubscriptionStateParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (SubscriptionState object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("SubscriptionStateParser.parse"); + + SubscriptionState subscriptionState = new SubscriptionState(); + try { + headerName(TokenTypes.SUBSCRIPTION_STATE); + + subscriptionState.setHeaderName(SIPHeaderNames.SUBSCRIPTION_STATE); + + // State: + lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + subscriptionState.setState(token.getTokenValue()); + + while (lexer.lookAhead(0) == ';') { + this.lexer.match(';'); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + String value = token.getTokenValue(); + if (value.equalsIgnoreCase("reason")) { + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + value = token.getTokenValue(); + subscriptionState.setReasonCode(value); + } else if (value.equalsIgnoreCase("expires")) { + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + value = token.getTokenValue(); + try { + int expires = Integer.parseInt(value); + subscriptionState.setExpires(expires); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + } else if (value.equalsIgnoreCase("retry-after")) { + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + value = token.getTokenValue(); + try { + int retryAfter = Integer.parseInt(value); + subscriptionState.setRetryAfter(retryAfter); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + } else { + this.lexer.match('='); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token secondToken = lexer.getNextToken(); + String secondValue = secondToken.getTokenValue(); + subscriptionState.setParameter(value, secondValue); + } + this.lexer.SPorHT(); + } + } finally { + if (debug) + dbg_leave("SubscriptionStateParser.parse"); + } + + return subscriptionState; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String subscriptionState[] = { + "Subscription-State: active \n", + "Subscription-State: terminated;reason=rejected \n", + "Subscription-State: pending;reason=probation;expires=36\n", + "Subscription-State: pending;retry-after=10;expires=36\n", + "Subscription-State: pending;generic=void\n" + }; + + for (int i = 0; i < subscriptionState.length; i++ ) { + SubscriptionStateParser parser = + new SubscriptionStateParser(subscriptionState[i]); + SubscriptionState ss= (SubscriptionState) parser.parse(); + System.out.println("encoded = " + ss.encode()); + } + } + */ +} +/* + * $Log: SubscriptionStateParser.java,v $ + * Revision 1.7 2009/07/17 18:58:05 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:25 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/SupportedParser.java b/java/gov/nist/javax/sip/parser/SupportedParser.java new file mode 100644 index 0000000..85100de --- /dev/null +++ b/java/gov/nist/javax/sip/parser/SupportedParser.java @@ -0,0 +1,192 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Supported header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:06 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + * + * @version 1.0 + */ +public class SupportedParser extends HeaderParser { + + /** + * Creates a new instance of SupportedParser + * @param supported the header to parse + */ + public SupportedParser(String supported) { + super(supported); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected SupportedParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (Supported object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + SupportedList supportedList = new SupportedList(); + if (debug) + dbg_enter("SupportedParser.parse"); + + try { + headerName(TokenTypes.SUPPORTED); + + while (lexer.lookAhead(0) != '\n') { + this.lexer.SPorHT(); + Supported supported = new Supported(); + supported.setHeaderName(SIPHeaderNames.SUPPORTED); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + supported.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + supportedList.add(supported); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + supported = new Supported(); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + supported.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + supportedList.add(supported); + } + + } + } finally { + if (debug) + dbg_leave("SupportedParser.parse"); + } + + return supportedList; + } + + /** Test program + public static void main(String args[]) throws ParseException { + String supported[] = { + "Supported: 100rel \n", + "Supported: foo1, foo2 ,foo3 , foo4 \n" + }; + + for (int i = 0; i < supported.length; i++ ) { + SupportedParser parser = + new SupportedParser(supported[i]); + SupportedList s= (SupportedList) parser.parse(); + System.out.println("encoded = " + s.encode()); + } + + } + */ +} +/* + * $Log: SupportedParser.java,v $ + * Revision 1.7 2009/07/17 18:58:06 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:02 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/TimeStampParser.java b/java/gov/nist/javax/sip/parser/TimeStampParser.java new file mode 100644 index 0000000..842128c --- /dev/null +++ b/java/gov/nist/javax/sip/parser/TimeStampParser.java @@ -0,0 +1,240 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for TimeStamp header. + * + * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/18 13:46:39 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class TimeStampParser extends HeaderParser { + + /** + * Creates a new instance of TimeStampParser + * @param timeStamp the header to parse + */ + public TimeStampParser(String timeStamp) { + super(timeStamp); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected TimeStampParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (TimeStamp object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("TimeStampParser.parse"); + TimeStamp timeStamp = new TimeStamp(); + try { + headerName(TokenTypes.TIMESTAMP); + + timeStamp.setHeaderName(SIPHeaderNames.TIMESTAMP); + + this.lexer.SPorHT(); + String firstNumber = this.lexer.number(); + + try { + + if (lexer.lookAhead(0) == '.') { + this.lexer.match('.'); + String secondNumber = this.lexer.number(); + + String s = firstNumber + "." + secondNumber; + float ts = Float.parseFloat(s); + timeStamp.setTimeStamp(ts); + } else { + long ts = Long.parseLong(firstNumber); + timeStamp.setTime(ts); + } + + + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + + this.lexer.SPorHT(); + if (lexer.lookAhead(0) != '\n') { + firstNumber = this.lexer.number(); + + try { + + if (lexer.lookAhead(0) == '.') { + this.lexer.match('.'); + String secondNumber = this.lexer.number(); + + String s = firstNumber + "." + secondNumber; + float ts = Float.parseFloat(s); + timeStamp.setDelay(ts); + } else { + int ts = Integer.parseInt(firstNumber); + timeStamp.setDelay(ts); + } + + + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + } + + } finally { + if (debug) + dbg_leave("TimeStampParser.parse"); + } + + return timeStamp; + } + + + + +} +/* + * $Log: TimeStampParser.java,v $ + * Revision 1.9 2009/10/18 13:46:39 deruelle_jean + * FindBugs Fixes (Category Performance Warnings) + * + * Issue number: + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.8 2009/07/17 18:58:06 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.7 2006/08/15 21:44:50 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * Incorporating the latest API changes from Phelim + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.6 2006/07/13 09:02:14 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.5 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.4 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.3 2006/05/25 23:46:23 mranga + * Added @author NIST to all API files. Moved a package around in the tck directory. + * + * Ranga. + * + * Revision 1.2 2006/05/18 10:08:43 mranga + * Fixes null pointer in comparison when host is not specified. Add methods to allow longs and ints as args in TimeStamp Header. + * + * Ranga. + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/ToParser.java b/java/gov/nist/javax/sip/parser/ToParser.java new file mode 100644 index 0000000..6956472 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ToParser.java @@ -0,0 +1,170 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import java.text.ParseException; +import gov.nist.javax.sip.address.*; +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; + +/** + * To Header parser. + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/10/22 10:27:38 $ + * + * @author Olivier Deruelle <br/> + * + * + */ +public class ToParser extends AddressParametersParser { + + /** + * Creates new ToParser + * @param to String to set + */ + public ToParser(String to) { + super(to); + } + + protected ToParser(Lexer lexer) { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + + headerName(TokenTypes.TO); + To to = new To(); + super.parse(to); + this.lexer.match('\n'); + return to; + } + + /** + + public static void main(String args[]) throws ParseException { + String to[] = { + "To: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\n", + "To: T. A. Watson <sip:watson@bell-telephone.com;param=something>\n", + "To: LittleGuy <sip:UserB@there.com;tag=foo>;tag=bar\n", + "To: sip:mranga@120.6.55.9\n", + "To: sip:mranga@129.6.55.9;tag=696928473514.129.6.55.9\n", + "To: sip:mranga@129.6.55.9; tag=696928473514.129.6.55.9\n", + "To: sip:mranga@129.6.55.9 ;tag=696928473514.129.6.55.9\n", + "To: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\n" + }; + + for (int i = 0; i < to.length; i++ ) { + System.out.println("toParse = " + to[i]); + ToParser tp = + new ToParser(to[i]); + To t = (To) tp.parse(); + System.out.println("encoded = " + t.encode()); + } + + } + **/ +} +/* + * $Log: ToParser.java,v $ + * Revision 1.11 2009/10/22 10:27:38 jbemmel + * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>' + * stops at ';', then parameters are assigned to the header as expected + * + * Revision 1.10 2009/07/17 18:58:06 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.9 2007/10/23 17:34:55 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: mranga + * + * Refactored header collections. + * + * Revision 1.8 2006/07/13 09:02:00 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.6 2004/04/22 22:51:18 mranga + * Submitted by: Thomas Froment + * Reviewed by: mranga + * + * Fixed corner cases. + * + * Revision 1.5 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/TokenNames.java b/java/gov/nist/javax/sip/parser/TokenNames.java new file mode 100644 index 0000000..938f231 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/TokenNames.java @@ -0,0 +1,176 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import javax.sip.message.Request; +import gov.nist.javax.sip.address.*; +import gov.nist.javax.sip.header.*; + +/** + * A grab bag of SIP Token names. + * + * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/27 20:35:02 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public interface TokenNames + extends + gov.nist.javax.sip.header.ParameterNames, + gov.nist.javax.sip.address.ParameterNames { + // And now dreaded short forms.... + public static final String INVITE = Request.INVITE; + public static final String ACK = Request.ACK; + public static final String BYE = Request.BYE; + public static final String SUBSCRIBE = Request.SUBSCRIBE; + public static final String NOTIFY = Request.NOTIFY; + public static final String OPTIONS = Request.OPTIONS; + public static final String REGISTER = Request.REGISTER; + public static final String MESSAGE = Request.MESSAGE; + public static final String PUBLISH = Request.PUBLISH; + + public static final String SIP = GenericURI.SIP; + public static final String SIPS = GenericURI.SIPS; + public static final String TEL = GenericURI.TEL; + public static final String GMT = SIPDate.GMT; + public static final String MON = SIPDate.MON; + public static final String TUE = SIPDate.TUE; + public static final String WED = SIPDate.WED; + public static final String THU = SIPDate.THU; + public static final String FRI = SIPDate.FRI; + public static final String SAT = SIPDate.SAT; + public static final String SUN = SIPDate.SUN; + public static final String JAN = SIPDate.JAN; + public static final String FEB = SIPDate.FEB; + public static final String MAR = SIPDate.MAR; + public static final String APR = SIPDate.APR; + public static final String MAY = SIPDate.MAY; + public static final String JUN = SIPDate.JUN; + public static final String JUL = SIPDate.JUL; + public static final String AUG = SIPDate.AUG; + public static final String SEP = SIPDate.SEP; + public static final String OCT = SIPDate.OCT; + public static final String NOV = SIPDate.NOV; + public static final String DEC = SIPDate.DEC; + public static final String K = "K"; + public static final String C = "C"; + public static final String E = "E"; + public static final String F = "F"; + public static final String I = "I"; + public static final String M = "M"; + public static final String L = "L"; + public static final String S = "S"; + public static final String T = "T"; + public static final String U = "U";// JvB: added + public static final String V = "V"; + public static final String R = "R"; + public static final String O = "O"; + public static final String X = "X"; //Jozef Saniga added +} +/* + * $Log: TokenNames.java,v $ + * Revision 1.10 2009/07/27 20:35:02 deruelle_jean + * Fix for the compact form of SessionExpires Header from RFC 4028 + * + * Issue number: + * Obtained from: Jozef Saniga + * Submitted by: Jean Deruelle + * Reviewed by: + * + * Revision 1.9 2009/07/17 18:58:06 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.8 2006/07/13 09:02:13 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.5 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.4 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.3 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * Revision 1.2 2005/10/08 23:13:56 jeroen + * added short form for Allow-Events + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.5 2005/04/27 14:12:05 mranga + * Submitted by: Mario Mantak + * Reviewed by: mranga + * + * Added a missing "short form" for event header. + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/TokenTypes.java b/java/gov/nist/javax/sip/parser/TokenTypes.java new file mode 100644 index 0000000..a711732 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/TokenTypes.java @@ -0,0 +1,343 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.core.*; + +/** + * @version 1.2 $Revision: 1.13 $ $Date: 2010/01/12 00:05:25 $ + */ +public interface TokenTypes { + + public static final int START = LexerCore.START; + // Everything under this is reserved + public static final int END = LexerCore.END; + // End markder. + + public static final int SIP = START + 3; + public static final int REGISTER = START + 4; + public static final int INVITE = START + 5; + public static final int ACK = START + 6; + public static final int BYE = START + 7; + public static final int OPTIONS = START + 8; + public static final int CANCEL = START + 9; + public static final int ERROR_INFO = START + 10; + public static final int IN_REPLY_TO = START + 11; + public static final int MIME_VERSION = START + 12; + public static final int ALERT_INFO = START + 13; + public static final int FROM = START + 14; + public static final int TO = START + 15; + public static final int VIA = START + 16; + public static final int USER_AGENT = START + 17; + public static final int SERVER = START + 18; + public static final int ACCEPT_ENCODING = START + 19; + public static final int ACCEPT = START + 20; + public static final int ALLOW = START + 21; + public static final int ROUTE = START + 22; + public static final int AUTHORIZATION = START + 23; + public static final int PROXY_AUTHORIZATION = START + 24; + public static final int RETRY_AFTER = START + 25; + public static final int PROXY_REQUIRE = START + 26; + public static final int CONTENT_LANGUAGE = START + 27; + public static final int UNSUPPORTED = START + 28; + public static final int SUPPORTED = START + 20; + public static final int WARNING = START + 30; + public static final int MAX_FORWARDS = START + 31; + public static final int DATE = START + 32; + public static final int PRIORITY = START + 33; + public static final int PROXY_AUTHENTICATE = START + 34; + public static final int CONTENT_ENCODING = START + 35; + public static final int CONTENT_LENGTH = START + 36; + public static final int SUBJECT = START + 37; + public static final int CONTENT_TYPE = START + 38; + public static final int CONTACT = START + 39; + public static final int CALL_ID = START + 40; + public static final int REQUIRE = START + 41; + public static final int EXPIRES = START + 42; + public static final int ENCRYPTION = START + 43; + public static final int RECORD_ROUTE = START + 44; + public static final int ORGANIZATION = START + 45; + public static final int CSEQ = START + 46; + public static final int ACCEPT_LANGUAGE = START + 47; + public static final int WWW_AUTHENTICATE = START + 48; + public static final int RESPONSE_KEY = START + 49; + public static final int HIDE = START + 50; + public static final int CALL_INFO = START + 51; + public static final int CONTENT_DISPOSITION = START + 52; + public static final int SUBSCRIBE = START + 53; + public static final int NOTIFY = START + 54; + public static final int TIMESTAMP = START + 55; + public static final int SUBSCRIPTION_STATE = START + 56; + public static final int TEL = START + 57; + public static final int REPLY_TO = START + 58; + public static final int REASON = START + 59; + public static final int RSEQ = START + 60; + public static final int RACK = START + 61; + public static final int MIN_EXPIRES = START + 62; + public static final int EVENT = START + 63; + public static final int AUTHENTICATION_INFO = START + 64; + public static final int ALLOW_EVENTS = START + 65; + public static final int REFER_TO = START + 66; + + // JvB: added to support RFC3903 + public static final int PUBLISH = START + 67; + public static final int SIP_ETAG = START + 68; + public static final int SIP_IF_MATCH = START + 69; + + + + + public static final int MESSAGE = START + 70; + + // IMS Headers + public static final int PATH = START + 71; + public static final int SERVICE_ROUTE = START + 72; + public static final int P_ASSERTED_IDENTITY = START + 73; + public static final int P_PREFERRED_IDENTITY = START + 74; + public static final int P_VISITED_NETWORK_ID = START + 75; + public static final int P_CHARGING_FUNCTION_ADDRESSES = START + 76; + public static final int P_VECTOR_CHARGING = START + 77; + + + + // issued by Miguel Freitas - IMS headers + public static final int PRIVACY = START + 78; + public static final int P_ACCESS_NETWORK_INFO = START + 79; + public static final int P_CALLED_PARTY_ID = START + 80; + public static final int P_ASSOCIATED_URI = START + 81; + public static final int P_MEDIA_AUTHORIZATION = START + 82; + public static final int P_MEDIA_AUTHORIZATION_TOKEN = START + 83; + + + // pmusgrave - additions + public static final int REFERREDBY_TO = START + 84; + + // pmusgrave RFC4028 + public static final int SESSIONEXPIRES_TO = START + 85; + public static final int MINSE_TO = START + 86; + + // pmusgrave RFC3891 + public static final int REPLACES_TO = START + 87; + + // pmusgrave sips bug fix + public static final int SIPS = START + 88; + + + // issued by Miguel Freitas - SIP Security Agreement (RFC3329) + public static final int SECURITY_SERVER = START + 89; + public static final int SECURITY_CLIENT = START + 90; + public static final int SECURITY_VERIFY = START + 91; + + // jean deruelle RFC3911 + public static final int JOIN_TO = START + 92; + + // aayush.bhatnagar: RFC 4457 support. + public static final int P_USER_DATABASE = START + 93; + //aayush.bhatnagar: RFC 5002 support. + public static final int P_PROFILE_KEY = START + 94; + //aayush.bhatnagar: RFC 5502 support. + public static final int P_SERVED_USER = START + 95; + //aayush.bhatnaagr: P-Preferred-Service Header: + public static final int P_PREFERRED_SERVICE = START + 96; + //aayush.bhatnagar: P-Asserted-Service Header: + public static final int P_ASSERTED_SERVICE = START + 97; + //mranga - References header + public static final int REFERENCES = START + 98; + + public static final int ALPHA = LexerCore.ALPHA; + public static final int DIGIT = LexerCore.DIGIT; + public static final int ID = LexerCore.ID; + public static final int WHITESPACE = LexerCore.WHITESPACE; + public static final int BACKSLASH = LexerCore.BACKSLASH; + public static final int QUOTE = LexerCore.QUOTE; + public static final int AT = LexerCore.AT; + public static final int SP = LexerCore.SP; + public static final int HT = LexerCore.HT; + public static final int COLON = LexerCore.COLON; + public static final int STAR = LexerCore.STAR; + public static final int DOLLAR = LexerCore.DOLLAR; + public static final int PLUS = LexerCore.PLUS; + public static final int POUND = LexerCore.POUND; + public static final int MINUS = LexerCore.MINUS; + public static final int DOUBLEQUOTE = LexerCore.DOUBLEQUOTE; + public static final int TILDE = LexerCore.TILDE; + public static final int BACK_QUOTE = LexerCore.BACK_QUOTE; + public static final int NULL = LexerCore.NULL; + public static final int EQUALS = (int) '='; + public static final int SEMICOLON = (int) ';'; + public static final int SLASH = (int) '/'; + public static final int L_SQUARE_BRACKET = (int) '['; + public static final int R_SQUARE_BRACKET = (int) ']'; + public static final int R_CURLY = (int) '}'; + public static final int L_CURLY = (int) '{'; + public static final int HAT = (int) '^'; + public static final int BAR = (int) '|'; + public static final int DOT = (int) '.'; + public static final int EXCLAMATION = (int) '!'; + public static final int LPAREN = (int) '('; + public static final int RPAREN = (int) ')'; + public static final int GREATER_THAN = (int) '>'; + public static final int LESS_THAN = (int) '<'; + public static final int PERCENT = (int) '%'; + public static final int QUESTION = (int) '?'; + public static final int AND = (int) '&'; + public static final int UNDERSCORE = (int) '_'; + +} +/* + * $Log: TokenTypes.java,v $ + * Revision 1.13 2010/01/12 00:05:25 mranga + * Add support for References header draft-worley-references-05 + * + * Revision 1.12 2009/07/17 18:58:06 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.11 2009/05/10 00:29:53 mranga + * + * Submitted by: Aayush Bhatnagar + * Reviewed by: + * IMS headers and parsers. + * + * Revision 1.10 2009/01/22 19:33:47 deruelle_jean + * Add support for JOIN (RFC 3911) + * Issue number: 186 + * Obtained from: + * Submitted by: Jean Deruelle + * Reviewed by: Ranga, The high priest and grand poobah of Jain-SIP + * + * Revision 1.9 2007/01/08 19:24:22 mranga + * Issue number: + * Obtained from: + * Submitted by: Miguel Freitas + * Reviewed by: mranga + * + * Miguel -- please implement a deep clone method for the IMS headers. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.8 2006/10/12 11:57:54 pmusgrave + * Issue number: 79, 80 + * Submitted by: pmusgrave@newheights.com + * Reviewed by: mranga + * + * Revision 1.7 2006/09/11 18:41:32 mranga + * Issue number: + * Obtained from: + * Submitted by: mranga + * Reviewed by: + * Tighter integration of IMS headers. + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.6 2006/07/13 09:01:55 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.4 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.3 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.2 2005/10/27 20:49:00 jeroen + * added support for RFC3903 PUBLISH + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/URLParser.java b/java/gov/nist/javax/sip/parser/URLParser.java new file mode 100644 index 0000000..9e87890 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/URLParser.java @@ -0,0 +1,833 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import gov.nist.core.HostNameParser; +import gov.nist.core.HostPort; +import gov.nist.core.NameValue; +import gov.nist.core.NameValueList; +import gov.nist.core.Token; +import gov.nist.javax.sip.address.GenericURI; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.address.TelURLImpl; +import gov.nist.javax.sip.address.TelephoneNumber; +import java.text.ParseException; + +/** + * Parser For SIP and Tel URLs. Other kinds of URL's are handled by the + * J2SE 1.4 URL class. + * @version 1.2 $Revision: 1.27 $ $Date: 2009/10/22 10:27:39 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class URLParser extends Parser { + + public URLParser(String url) { + this.lexer = new Lexer("sip_urlLexer", url); + } + + // public tag added - issued by Miguel Freitas + public URLParser(Lexer lexer) { + this.lexer = lexer; + this.lexer.selectLexer("sip_urlLexer"); + } + protected static boolean isMark(char next) { + switch (next) { + case '-': + case '_': + case '.': + case '!': + case '~': + case '*': + case '\'': + case '(': + case ')': + return true; + default: + return false; + } + } + + protected static boolean isUnreserved(char next) { + return Lexer.isAlphaDigit(next) || isMark(next); + } + + protected static boolean isReservedNoSlash(char next) { + switch (next) { + case ';': + case '?': + case ':': + case '@': + case '&': + case '+': + case '$': + case ',': + return true; + default: + return false; + } + } + + // Missing '=' bug in character set - discovered by interop testing + // at SIPIT 13 by Bob Johnson and Scott Holben. + // change . to ; by Bruno Konik + protected static boolean isUserUnreserved(char la) { + switch (la) { + case '&': + case '?': + case '+': + case '$': + case '#': + case '/': + case ',': + case ';': + case '=': + return true; + default: + return false; + } + } + + protected String unreserved() throws ParseException { + char next = lexer.lookAhead(0); + if (isUnreserved(next)) { + lexer.consume(1); + return String.valueOf(next); + } else + throw createParseException("unreserved"); + + } + + /** Name or value of a parameter. + */ + protected String paramNameOrValue() throws ParseException { + int startIdx = lexer.getPtr(); + while (lexer.hasMoreChars()) { + char next = lexer.lookAhead(0); + boolean isValidChar = false; + switch (next) { + case '[': + case ']':// JvB: fixed this one + case '/': + case ':': + case '&': + case '+': + case '$': + isValidChar = true; + } + if (isValidChar || isUnreserved(next)) { + lexer.consume(1); + } else if (isEscaped()) { + lexer.consume(3); + } else + break; + } + return lexer.getBuffer().substring(startIdx, lexer.getPtr()); + } + + private NameValue uriParam() throws ParseException { + if (debug) + dbg_enter("uriParam"); + try { + String pvalue = ""; + String pname = paramNameOrValue(); + char next = lexer.lookAhead(0); + boolean isFlagParam = true; + if (next == '=') { + lexer.consume(1); + pvalue = paramNameOrValue(); + isFlagParam = false; + } + if (pname.length() == 0 && + ( pvalue == null || + pvalue.length() == 0)) + return null; + else return new NameValue(pname, pvalue, isFlagParam); + } finally { + if (debug) + dbg_leave("uriParam"); + } + } + + protected static boolean isReserved(char next) { + switch (next) { + case ';': + case '/': + case '?': + case ':': + case '=': // Bug fix by Bruno Konik + case '@': + case '&': + case '+': + case '$': + case ',': + return true; + default: + return false; + } + } + + protected String reserved() throws ParseException { + char next = lexer.lookAhead(0); + if (isReserved(next)) { + lexer.consume(1); + return new StringBuffer().append(next).toString(); + } else + throw createParseException("reserved"); + } + + protected boolean isEscaped() { + try { + return lexer.lookAhead(0) == '%' && + Lexer.isHexDigit(lexer.lookAhead(1)) && + Lexer.isHexDigit(lexer.lookAhead(2)); + } catch (Exception ex) { + return false; + } + } + + protected String escaped() throws ParseException { + if (debug) + dbg_enter("escaped"); + try { + StringBuffer retval = new StringBuffer(); + char next = lexer.lookAhead(0); + char next1 = lexer.lookAhead(1); + char next2 = lexer.lookAhead(2); + if (next == '%' + && Lexer.isHexDigit(next1) + && Lexer.isHexDigit(next2)) { + lexer.consume(3); + retval.append(next); + retval.append(next1); + retval.append(next2); + } else + throw createParseException("escaped"); + return retval.toString(); + } finally { + if (debug) + dbg_leave("escaped"); + } + } + + protected String mark() throws ParseException { + if (debug) + dbg_enter("mark"); + try { + char next = lexer.lookAhead(0); + if (isMark(next)) { + lexer.consume(1); + return new String( new char[]{next} ); + } else + throw createParseException("mark"); + } finally { + if (debug) + dbg_leave("mark"); + } + } + + protected String uric() { + if (debug) + dbg_enter("uric"); + try { + try { + char la = lexer.lookAhead(0); + if (isUnreserved(la)) { + lexer.consume(1); + return Lexer.charAsString(la); + } else if (isReserved(la)) { + lexer.consume(1); + return Lexer.charAsString(la); + } else if (isEscaped()) { + String retval = lexer.charAsString(3); + lexer.consume(3); + return retval; + } else + return null; + } catch (Exception ex) { + return null; + } + } finally { + if (debug) + dbg_leave("uric"); + } + + } + + protected String uricNoSlash() { + if (debug) + dbg_enter("uricNoSlash"); + try { + try { + char la = lexer.lookAhead(0); + if (isEscaped()) { + String retval = lexer.charAsString(3); + lexer.consume(3); + return retval; + } else if (isUnreserved(la)) { + lexer.consume(1); + return Lexer.charAsString(la); + } else if (isReservedNoSlash(la)) { + lexer.consume(1); + return Lexer.charAsString(la); + } else + return null; + } catch (ParseException ex) { + return null; + } + } finally { + if (debug) + dbg_leave("uricNoSlash"); + } + } + + protected String uricString() throws ParseException { + StringBuffer retval = new StringBuffer(); + while (true) { + String next = uric(); + if (next == null) { + char la = lexer.lookAhead(0); + // JvB: allow IPv6 addresses in generic URI strings + // e.g. http://[::1] + if ( la == '[' ) { + HostNameParser hnp = new HostNameParser(this.getLexer()); + HostPort hp = hnp.hostPort( false ); + retval.append(hp.toString()); + continue; + } + break; + } + retval.append(next); + } + return retval.toString(); + } + + /** + * Parse and return a structure for a generic URL. + * Note that non SIP URLs are just stored as a string (not parsed). + * @return URI is a URL structure for a SIP url. + * @throws ParseException if there was a problem parsing. + */ + public GenericURI uriReference( boolean inBrackets ) throws ParseException { + if (debug) + dbg_enter("uriReference"); + GenericURI retval = null; + Token[] tokens = lexer.peekNextToken(2); + Token t1 = (Token) tokens[0]; + Token t2 = (Token) tokens[1]; + try { + + if (t1.getTokenType() == TokenTypes.SIP || + t1.getTokenType() == TokenTypes.SIPS) { + if (t2.getTokenType() == ':') + retval = sipURL( inBrackets ); + else + throw createParseException("Expecting \':\'"); + } else if (t1.getTokenType() == TokenTypes.TEL) { + if (t2.getTokenType() == ':') { + retval = telURL( inBrackets ); + } else + throw createParseException("Expecting \':\'"); + } else { + String urlString = uricString(); + try { + retval = new GenericURI(urlString); + } catch (ParseException ex) { + throw createParseException(ex.getMessage()); + } + } + } finally { + if (debug) + dbg_leave("uriReference"); + } + return retval; + } + + /** + * Parser for the base phone number. + */ + private String base_phone_number() throws ParseException { + StringBuffer s = new StringBuffer(); + + if (debug) + dbg_enter("base_phone_number"); + try { + int lc = 0; + while (lexer.hasMoreChars()) { + char w = lexer.lookAhead(0); + if (Lexer.isDigit(w) + || w == '-' + || w == '.' + || w == '(' + || w == ')') { + lexer.consume(1); + s.append(w); + lc++; + } else if (lc > 0) + break; + else + throw createParseException("unexpected " + w); + } + return s.toString(); + } finally { + if (debug) + dbg_leave("base_phone_number"); + } + + } + + /** + * Parser for the local phone #. + */ + private String local_number() throws ParseException { + StringBuffer s = new StringBuffer(); + if (debug) + dbg_enter("local_number"); + try { + int lc = 0; + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + if (la == '*' + || la == '#' + || la == '-' + || la == '.' + || la == '(' + || la == ')' + // JvB: allow 'A'..'F', should be uppercase + || Lexer.isHexDigit(la)) { + lexer.consume(1); + s.append(la); + lc++; + } else if (lc > 0) + break; + else + throw createParseException("unexepcted " + la); + } + return s.toString(); + } finally { + if (debug) + dbg_leave("local_number"); + } + + } + + /** + * Parser for telephone subscriber. + * + * @return the parsed telephone number. + */ + public final TelephoneNumber parseTelephoneNumber( boolean inBrackets ) + throws ParseException { + TelephoneNumber tn; + + if (debug) + dbg_enter("telephone_subscriber"); + lexer.selectLexer("charLexer"); + try { + char c = lexer.lookAhead(0); + if (c == '+') + tn = global_phone_number( inBrackets ); + else if ( + Lexer.isHexDigit(c)// see RFC3966 + || c == '#' + || c == '*' + || c == '-' + || c == '.' + || c == '(' + || c == ')' ) { + tn = local_phone_number( inBrackets ); + } else + throw createParseException("unexpected char " + c); + return tn; + } finally { + if (debug) + dbg_leave("telephone_subscriber"); + } + + } + + private final TelephoneNumber global_phone_number( boolean inBrackets ) throws ParseException { + if (debug) + dbg_enter("global_phone_number"); + try { + TelephoneNumber tn = new TelephoneNumber(); + tn.setGlobal(true); + NameValueList nv = null; + this.lexer.match(PLUS); + String b = base_phone_number(); + tn.setPhoneNumber(b); + if (lexer.hasMoreChars()) { + char tok = lexer.lookAhead(0); + if (tok == ';' && inBrackets) { + this.lexer.consume(1); + nv = tel_parameters(); + tn.setParameters(nv); + } + } + return tn; + } finally { + if (debug) + dbg_leave("global_phone_number"); + } + } + + private TelephoneNumber local_phone_number( boolean inBrackets ) throws ParseException { + if (debug) + dbg_enter("local_phone_number"); + TelephoneNumber tn = new TelephoneNumber(); + tn.setGlobal(false); + NameValueList nv = null; + String b = null; + try { + b = local_number(); + tn.setPhoneNumber(b); + if (lexer.hasMoreChars()) { + Token tok = this.lexer.peekNextToken(); + switch (tok.getTokenType()) { + case SEMICOLON: + { + if (inBrackets) { + this.lexer.consume(1); + nv = tel_parameters(); + tn.setParameters(nv); + } + break; + } + default : + { + break; + } + } + } + } finally { + if (debug) + dbg_leave("local_phone_number"); + } + return tn; + } + + private NameValueList tel_parameters() throws ParseException { + NameValueList nvList = new NameValueList(); + + // JvB: Need to handle 'phone-context' specially + // 'isub' (or 'ext') MUST appear first, but we accept any order here + NameValue nv; + while ( true ) { + String pname = paramNameOrValue(); + + // Handle 'phone-context' specially, it may start with '+' + if ( pname.equalsIgnoreCase("phone-context")) { + nv = phone_context(); + } else { + if (lexer.lookAhead(0) == '=') { + lexer.consume(1); + String value = paramNameOrValue(); + nv = new NameValue( pname, value, false ); + } else { + nv = new NameValue( pname, "", true );// flag param + } + } + nvList.set( nv ); + + if ( lexer.lookAhead(0) == ';' ) { + lexer.consume(1); + } else { + return nvList; + } + } + + } + + /** + * Parses the 'phone-context' parameter in tel: URLs + * @throws ParseException + */ + private NameValue phone_context() throws ParseException { + lexer.match('='); + + char la = lexer.lookAhead(0); + Object value; + if (la=='+') {// global-number-digits + lexer.consume(1);// skip '+' + value = "+" + base_phone_number(); + } else if ( Lexer.isAlphaDigit(la) ) { + Token t = lexer.match( Lexer.ID );// more broad than allowed + value = t.getTokenValue(); + } else { + throw new ParseException( "Invalid phone-context:" + la , -1 ); + } + return new NameValue( "phone-context", value, false ); + } + + /** + * Parse and return a structure for a Tel URL. + * @return a parsed tel url structure. + */ + public TelURLImpl telURL( boolean inBrackets ) throws ParseException { + lexer.match(TokenTypes.TEL); + lexer.match(':'); + TelephoneNumber tn = this.parseTelephoneNumber(inBrackets); + TelURLImpl telUrl = new TelURLImpl(); + telUrl.setTelephoneNumber(tn); + return telUrl; + + } + + /** + * Parse and return a structure for a SIP URL. + * @return a URL structure for a SIP url. + * @throws ParseException if there was a problem parsing. + */ + public SipUri sipURL( boolean inBrackets ) throws ParseException { + if (debug) + dbg_enter("sipURL"); + SipUri retval = new SipUri(); + // pmusgrave - handle sips case + Token nextToken = lexer.peekNextToken(); + int sipOrSips = TokenTypes.SIP; + String scheme = TokenNames.SIP; + if ( nextToken.getTokenType() == TokenTypes.SIPS) + { + sipOrSips = TokenTypes.SIPS; + scheme = TokenNames.SIPS; + } + + try { + lexer.match(sipOrSips); + lexer.match(':'); + retval.setScheme(scheme); + int startOfUser = lexer.markInputPosition(); + String userOrHost = user();// Note: user may contain ';', host may not... + String passOrPort = null; + + // name:password or host:port + if ( lexer.lookAhead() == ':' ) { + lexer.consume(1); + passOrPort = password(); + } + + // name@hostPort + if ( lexer.lookAhead() == '@' ) { + lexer.consume(1); + retval.setUser( userOrHost ); + if (passOrPort!=null) retval.setUserPassword( passOrPort ); + } else { + // then userOrHost was a host, backtrack just in case a ';' was eaten... + lexer.rewindInputPosition( startOfUser ); + } + + HostNameParser hnp = new HostNameParser(this.getLexer()); + HostPort hp = hnp.hostPort( false ); + retval.setHostPort(hp); + + lexer.selectLexer("charLexer"); + while (lexer.hasMoreChars()) { + // If the URI is not enclosed in brackets, parameters belong to header + if (lexer.lookAhead(0) != ';' || !inBrackets) + break; + lexer.consume(1); + NameValue parms = uriParam(); + if (parms != null) retval.setUriParameter(parms); + } + + if (lexer.hasMoreChars() && lexer.lookAhead(0) == '?') { + lexer.consume(1); + while (lexer.hasMoreChars()) { + NameValue parms = qheader(); + retval.setQHeader(parms); + if (lexer.hasMoreChars() && lexer.lookAhead(0) != '&') + break; + else + lexer.consume(1); + } + } + return retval; + } finally { + if (debug) + dbg_leave("sipURL"); + } + } + + public String peekScheme() throws ParseException { + Token[] tokens = lexer.peekNextToken(1); + if (tokens.length == 0) + return null; + String scheme = ((Token) tokens[0]).getTokenValue(); + return scheme; + } + + /** + * Get a name value for a given query header (ie one that comes + * after the ?). + */ + protected NameValue qheader() throws ParseException { + String name = lexer.getNextToken('='); + lexer.consume(1); + String value = hvalue(); + return new NameValue(name, value, false); + + } + + protected String hvalue() throws ParseException { + StringBuffer retval = new StringBuffer(); + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + // Look for a character that can terminate a URL. + boolean isValidChar = false; + switch (la) { + case '+': + case '?': + case ':': + case '[': + case ']': + case '/': + case '$': + case '_': + case '-': + case '"': + case '!': + case '~': + case '*': + case '.': + case '(': + case ')': + isValidChar = true; + } + if (isValidChar || Lexer.isAlphaDigit(la)) { + lexer.consume(1); + retval.append(la); + } else if (la == '%') { + retval.append(escaped()); + } else + break; + } + return retval.toString(); + } + + /** + * Scan forward until you hit a terminating character for a URL. + * We do not handle non sip urls in this implementation. + * @return the string that takes us to the end of this URL (i.e. to + * the next delimiter). + */ + protected String urlString() throws ParseException { + StringBuffer retval = new StringBuffer(); + lexer.selectLexer("charLexer"); + + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + // Look for a character that can terminate a URL. + if (la == ' ' + || la == '\t' + || la == '\n' + || la == '>' + || la == '<') + break; + lexer.consume(0); + retval.append(la); + } + return retval.toString(); + } + + protected String user() throws ParseException { + if (debug) + dbg_enter("user"); + try { + int startIdx = lexer.getPtr(); + while (lexer.hasMoreChars()) { + char la = lexer.lookAhead(0); + if (isUnreserved(la) || isUserUnreserved(la)) { + lexer.consume(1); + } else if (isEscaped()) { + lexer.consume(3); + } else + break; + } + return lexer.getBuffer().substring(startIdx, lexer.getPtr()); + } finally { + if (debug) + dbg_leave("user"); + } + + } + + protected String password() throws ParseException { + int startIdx = lexer.getPtr(); + while (true) { + char la = lexer.lookAhead(0); + boolean isValidChar = false; + switch (la) { + case '&': + case '=': + case '+': + case '$': + case ',': + isValidChar = true; + } + if (isValidChar || isUnreserved(la)) { + lexer.consume(1); + } else if (isEscaped()) { + lexer.consume(3); // bug reported by + // Jeff Haynie + } else + break; + + } + return lexer.getBuffer().substring(startIdx, lexer.getPtr()); + } + + /** + * Default parse method. This method just calls uriReference. + */ + public GenericURI parse() throws ParseException { + return uriReference( true ); + } + + // quick test routine for debugging type assignment + public static void main(String[] args) throws ParseException + { + // quick test for sips parsing + String[] test = { "sip:alice@example.com", + "sips:alice@examples.com" , + "sip:3Zqkv5dajqaaas0tCjCxT0xH2ZEuEMsFl0xoasip%3A%2B3519116786244%40siplab.domain.com@213.0.115.163:7070"}; + + for ( int i = 0; i < test.length; i++) + { + URLParser p = new URLParser(test[i]); + + GenericURI uri = p.parse(); + System.out.println("uri type returned " + uri.getClass().getName()); + System.out.println(test[i] + " is SipUri? " + uri.isSipURI() + + ">" + uri.encode()); + } + } + + /** + + **/ +} + diff --git a/java/gov/nist/javax/sip/parser/UnsupportedParser.java b/java/gov/nist/javax/sip/parser/UnsupportedParser.java new file mode 100644 index 0000000..051ebfd --- /dev/null +++ b/java/gov/nist/javax/sip/parser/UnsupportedParser.java @@ -0,0 +1,190 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for Unsupported header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:07 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class UnsupportedParser extends HeaderParser { + + /** + * Creates a new instance of UnsupportedParser + * @param unsupported - Unsupported header to parse + */ + public UnsupportedParser(String unsupported) { + super(unsupported); + } + + /** + * Constructor + * @param lexer - the lexer to use to parse the header + */ + protected UnsupportedParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (Unsupported object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + UnsupportedList unsupportedList = new UnsupportedList(); + if (debug) + dbg_enter("UnsupportedParser.parse"); + + try { + headerName(TokenTypes.UNSUPPORTED); + + while (lexer.lookAhead(0) != '\n') { + this.lexer.SPorHT(); + Unsupported unsupported = new Unsupported(); + unsupported.setHeaderName(SIPHeaderNames.UNSUPPORTED); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + unsupported.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + unsupportedList.add(unsupported); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + unsupported = new Unsupported(); + + // Parsing the option tag + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + unsupported.setOptionTag(token.getTokenValue()); + this.lexer.SPorHT(); + + unsupportedList.add(unsupported); + } + + } + } finally { + if (debug) + dbg_leave("UnsupportedParser.parse"); + } + + return unsupportedList; + } + + /** + public static void main(String args[]) throws ParseException { + String unsupported[] = { + "Unsupported: foo \n", + "Unsupported: foo1, foo2 ,foo3 , foo4\n" + }; + + for (int i = 0; i < unsupported.length; i++ ) { + UnsupportedParser parser = + new UnsupportedParser(unsupported[i]); + UnsupportedList u= (UnsupportedList) parser.parse(); + System.out.println("encoded = " + u.encode()); + } + + } + */ +} +/* + * $Log: UnsupportedParser.java,v $ + * Revision 1.7 2009/07/17 18:58:07 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:01:54 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/UserAgentParser.java b/java/gov/nist/javax/sip/parser/UserAgentParser.java new file mode 100644 index 0000000..e96ff93 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/UserAgentParser.java @@ -0,0 +1,146 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.core.Token; +import gov.nist.javax.sip.header.*; +import java.text.ParseException; + +/** + * Parser for UserAgent header. + * + * @version 1.2 $Revision: 1.15 $ $Date: 2009/07/17 18:58:07 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class UserAgentParser extends HeaderParser { + + /** + * Constructor + * + * @param userAgent - + * UserAgent header to parse + */ + public UserAgentParser(String userAgent) { + super(userAgent); + } + + /** + * Constructor + * + * @param lexer - + * the lexer to use. + */ + protected UserAgentParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the message. Note that we have losened up on the parsing quite a bit because + * user agents tend to be very bad about specifying the user agent according to RFC. + * + * @return SIPHeader (UserAgent object) + * @throws SIPParseException + * if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("UserAgentParser.parse"); + UserAgent userAgent = new UserAgent(); + try { + headerName(TokenTypes.USER_AGENT); + if (this.lexer.lookAhead(0) == '\n') + throw createParseException("empty header"); + + /* + * BNF User-Agent = "User-Agent" HCOLON server-val *(LWS server-val) + * server-val = product / comment product = token [SLASH + * product-version] product-version = token + */ + while (this.lexer.lookAhead(0) != '\n' + && this.lexer.lookAhead(0) != '\0') { + + if (this.lexer.lookAhead(0) == '(') { + String comment = this.lexer.comment(); + userAgent.addProductToken('(' + comment + ')'); + } else { + // product = token [SLASHproduct-version] + // product-version = token + // The RFC Does NOT allow this space but we are generous in what we accept + + this.getLexer().SPorHT(); + + + String product = this.lexer.byteStringNoSlash(); + if ( product == null ) throw createParseException("Expected product string"); + + StringBuffer productSb = new StringBuffer(product); + // do we possibily have the optional product-version? + if (this.lexer.peekNextToken().getTokenType() == TokenTypes.SLASH) { + // yes + this.lexer.match(TokenTypes.SLASH); + // product-version + // The RFC Does NOT allow this space but we are generous in what we accept + this.getLexer().SPorHT(); + + String productVersion = this.lexer.byteStringNoSlash(); + + if ( productVersion == null ) throw createParseException("Expected product version"); + + productSb.append("/"); + + productSb.append(productVersion); + } + + userAgent.addProductToken(productSb.toString()); + } + // LWS + this.lexer.SPorHT(); + } + } finally { + if (debug) + dbg_leave("UserAgentParser.parse"); + } + + return userAgent; + } + + + public static void main(String args[]) throws ParseException { String + userAgent[] = { "User-Agent: Softphone/Beta1.5 \n", "User-Agent:Nist/Beta1 (beta version) \n", "User-Agent: Nist UA (beta version)\n", + "User-Agent: Nist1.0/Beta2 Ubi/vers.1.0 (very cool) \n" , + "User-Agent: SJphone/1.60.299a/L (SJ Labs)\n", + "User-Agent: sipXecs/3.5.11 sipXecs/sipxbridge (Linux)\n"}; + + for (int i = 0; i < userAgent.length; i++ ) { UserAgentParser parser = + new UserAgentParser(userAgent[i]); UserAgent ua= (UserAgent) + parser.parse(); System.out.println("encoded = " + ua.encode()); } + } + +} diff --git a/java/gov/nist/javax/sip/parser/ViaParser.java b/java/gov/nist/javax/sip/parser/ViaParser.java new file mode 100644 index 0000000..bc2d0f9 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ViaParser.java @@ -0,0 +1,258 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; + +/** + * Parser for via headers. + * + * @version 1.2 $Revision: 1.12 $ $Date: 2009/07/17 18:58:07 $ + * @since 1.1 + * + * @author Olivier Deruelle + * @author M. Ranganathan + */ +public class ViaParser extends HeaderParser { + + public ViaParser(String via) { + super(via); + } + + public ViaParser(Lexer lexer) { + super(lexer); + } + + /** + * a parser for the essential part of the via header. + */ + private void parseVia(Via v) throws ParseException { + // The protocol + lexer.match(TokenTypes.ID); + Token protocolName = lexer.getNextToken(); + + this.lexer.SPorHT(); + // consume the "/" + lexer.match('/'); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + this.lexer.SPorHT(); + Token protocolVersion = lexer.getNextToken(); + + this.lexer.SPorHT(); + + // We consume the "/" + lexer.match('/'); + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + this.lexer.SPorHT(); + + Token transport = lexer.getNextToken(); + this.lexer.SPorHT(); + + Protocol protocol = new Protocol(); + protocol.setProtocolName(protocolName.getTokenValue()); + protocol.setProtocolVersion(protocolVersion.getTokenValue()); + protocol.setTransport(transport.getTokenValue()); + v.setSentProtocol(protocol); + + // sent-By + HostNameParser hnp = new HostNameParser(this.getLexer()); + HostPort hostPort = hnp.hostPort( true ); + v.setSentBy(hostPort); + + // Ignore blanks + this.lexer.SPorHT(); + + // parameters + while (lexer.lookAhead(0) == ';') { + this.lexer.consume(1); + this.lexer.SPorHT(); + NameValue nameValue = this.nameValue(); + String name = nameValue.getName(); + if (name.equals(Via.BRANCH)) { + String branchId = (String) nameValue.getValueAsObject(); + if (branchId == null) + throw new ParseException("null branch Id", lexer.getPtr()); + + } + v.setParameter(nameValue); + this.lexer.SPorHT(); + } + + // + // JvB Note: RFC3261 does not allow a comment in Via headers anymore + // + if (lexer.lookAhead(0) == '(') { + this.lexer.selectLexer("charLexer"); + lexer.consume(1); + StringBuffer comment = new StringBuffer(); + while (true) { + char ch = lexer.lookAhead(0); + if (ch == ')') { + lexer.consume(1); + break; + } else if (ch == '\\') { + // Escaped character + Token tok = lexer.getNextToken(); + comment.append(tok.getTokenValue()); + lexer.consume(1); + tok = lexer.getNextToken(); + comment.append(tok.getTokenValue()); + lexer.consume(1); + } else if (ch == '\n') { + break; + } else { + comment.append(ch); + lexer.consume(1); + } + } + v.setComment(comment.toString()); + } + + } + + /** + * Overrides the superclass nameValue parser because we have to tolerate + * IPV6 addresses in the received parameter. + */ + protected NameValue nameValue() throws ParseException { + if (debug) + dbg_enter("nameValue"); + try { + + lexer.match(LexerCore.ID); + Token name = lexer.getNextToken(); + // eat white space. + lexer.SPorHT(); + try { + + boolean quoted = false; + + char la = lexer.lookAhead(0); + + if (la == '=') { + lexer.consume(1); + lexer.SPorHT(); + String str = null; + if (name.getTokenValue().compareToIgnoreCase(Via.RECEIVED) == 0) { + // Allow for IPV6 Addresses. + // these could have : in them! + str = lexer.byteStringNoSemicolon(); + } else { + if (lexer.lookAhead(0) == '\"') { + str = lexer.quotedString(); + quoted = true; + } else { + lexer.match(LexerCore.ID); + Token value = lexer.getNextToken(); + str = value.getTokenValue(); + } + } + NameValue nv = new NameValue(name.getTokenValue() + .toLowerCase(), str); + if (quoted) + nv.setQuotedValue(); + return nv; + } else { + return new NameValue(name.getTokenValue().toLowerCase(), + null); + } + } catch (ParseException ex) { + return new NameValue(name.getTokenValue(), null); + } + + } finally { + if (debug) + dbg_leave("nameValue"); + } + + } + + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + ViaList viaList = new ViaList(); + // The first via header. + this.lexer.match(TokenTypes.VIA); + this.lexer.SPorHT(); // ignore blanks + this.lexer.match(':'); // expect a colon. + this.lexer.SPorHT(); // ingore blanks. + + while (true) { + Via v = new Via(); + parseVia(v); + viaList.add(v); + this.lexer.SPorHT(); // eat whitespace. + if (this.lexer.lookAhead(0) == ',') { + this.lexer.consume(1); // Consume the comma + this.lexer.SPorHT(); // Ignore space after. + } + if (this.lexer.lookAhead(0) == '\n') + break; + } + this.lexer.match('\n'); + return viaList; + } finally { + if (debug) + dbg_leave("parse"); + } + + } + + /** + * + * public static void main(String args[]) throws ParseException { String + * via[] = { "Via: SIP/2.0/UDP 135.180.130.133;branch=-12345\n", "Via: + * SIP/2.0/UDP 166.34.120.100;branch=0000045d-00000001"+ ",SIP/2.0/UDP + * 166.35.224.216:5000\n", "Via: SIP/2.0/UDP sip33.example.com,"+ " + * SIP/2.0/UDP sip32.example.com (oli),"+ "SIP/2.0/UDP sip31.example.com\n", + * "Via: SIP/2.0/UDP host.example.com;received=::133;"+ " + * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via: + * SIP/2.0/UDP host.example.com;received=135.180.130.133;"+ " + * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via: + * SIP/2.0/UDP company.com:5604 ( Hello )"+ ", SIP / 2.0 / UDP + * 135.180.130.133\n", "Via: SIP/2.0/UDP + * 129.6.55.9:7060;received=stinkbug.antd.nist.gov\n", + * + * "Via: SIP/2.0/UDP ss2.wcom.com:5060;branch=721e418c4.1"+ ", SIP/2.0/UDP + * ss1.wcom.com:5060;branch=2d4790.1"+ " , SIP/2.0/UDP here.com:5060( Hello + * the big world) \n" ,"Via: SIP/2.0/UDP + * ss1.wcom.com:5060;branch=2d4790.1\n", "Via: SIP/2.0/UDP + * first.example.com:4000;ttl=16"+ ";maddr=224.2.0.1 ;branch=a7c6a8dlze.1 + * (Acme server)\n" }; + * + * for (int i = 0; i < via.length; i++ ) { ViaParser vp = new + * ViaParser(via[i]); System.out.println("toParse = " + via[i]); ViaList vl = + * (ViaList) vp.parse(); System.out.println("encoded = " + vl.encode()); } + * } + * + */ + +} diff --git a/java/gov/nist/javax/sip/parser/WWWAuthenticateParser.java b/java/gov/nist/javax/sip/parser/WWWAuthenticateParser.java new file mode 100644 index 0000000..9fc27ec --- /dev/null +++ b/java/gov/nist/javax/sip/parser/WWWAuthenticateParser.java @@ -0,0 +1,140 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; +import java.text.ParseException; +import gov.nist.javax.sip.header.*; + +/** + * Parser for WWW authenitcate header. + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:07 $ + * + * @author Olivier Deruelle <br/> + * @author M. Ranganathan <br/> + * + * + */ +public class WWWAuthenticateParser extends ChallengeParser { + + /** + * Constructor + * @param wwwAuthenticate - message to parse + */ + public WWWAuthenticateParser(String wwwAuthenticate) { + super(wwwAuthenticate); + } + + /** + * Cosntructor + * @param lexer - lexer to use. + */ + protected WWWAuthenticateParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (WWWAuthenticate object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.WWW_AUTHENTICATE); + WWWAuthenticate wwwAuthenticate = new WWWAuthenticate(); + super.parse(wwwAuthenticate); + return wwwAuthenticate; + } finally { + if (debug) + dbg_leave("parse"); + } + } +} +/* + * $Log: WWWAuthenticateParser.java,v $ + * Revision 1.7 2009/07/17 18:58:07 emcho + * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project. + * + * Revision 1.6 2006/07/13 09:02:15 mranga + * Issue number: + * Obtained from: + * Submitted by: jeroen van bemmel + * Reviewed by: mranga + * Moved some changes from jain-sip-1.2 to java.net + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + * Revision 1.3 2006/06/19 06:47:27 mranga + * javadoc fixups + * + * Revision 1.2 2006/06/16 15:26:28 mranga + * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak + * + * Revision 1.1.1.1 2005/10/04 17:12:36 mranga + * + * Import + * + * + * Revision 1.4 2004/01/22 13:26:32 sverker + * Issue number: + * Obtained from: + * Submitted by: sverker + * Reviewed by: mranga + * + * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags. + * + * CVS: ---------------------------------------------------------------------- + * CVS: Issue number: + * CVS: If this change addresses one or more issues, + * CVS: then enter the issue number(s) here. + * CVS: Obtained from: + * CVS: If this change has been taken from another system, + * CVS: then name the system in this line, otherwise delete it. + * CVS: Submitted by: + * CVS: If this code has been contributed to the project by someone else; i.e., + * CVS: they sent us a patch or a set of diffs, then include their name/email + * CVS: address here. If this is your work then delete this line. + * CVS: Reviewed by: + * CVS: If we are doing pre-commit code reviews and someone else has + * CVS: reviewed your changes, include their name(s) here. + * CVS: If you have not had it reviewed then delete this line. + * + */ diff --git a/java/gov/nist/javax/sip/parser/WarningParser.java b/java/gov/nist/javax/sip/parser/WarningParser.java new file mode 100644 index 0000000..0fd33c3 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/WarningParser.java @@ -0,0 +1,192 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.parser; + +import gov.nist.javax.sip.header.*; +import gov.nist.core.*; +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for Warning header. + * + * @version 1.2 + * + * @author Olivier Deruelle + * @author M. Ranganathan + * + * + * + * @version 1.0 + */ +public class WarningParser extends HeaderParser { + + /** + * Constructor + * + * @param warning - + * Warning header to parse + */ + public WarningParser(String warning) { + super(warning); + } + + /** + * Cosntructor + * + * @param lexer - + * the lexer to use. + */ + protected WarningParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * + * @return SIPHeader (WarningList object) + * @throws SIPParseException + * if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + WarningList warningList = new WarningList(); + if (debug) + dbg_enter("WarningParser.parse"); + + try { + headerName(TokenTypes.WARNING); + + while (lexer.lookAhead(0) != '\n') { + Warning warning = new Warning(); + warning.setHeaderName(SIPHeaderNames.WARNING); + + // Parsing the 3digits code + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + try { + int code = Integer.parseInt(token.getTokenValue()); + warning.setCode(code); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + + // Parsing the agent + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + // Bug reported by zvali@dev.java.net + if (lexer.lookAhead(0) == ':') { + this.lexer.match(':'); + this.lexer.match(TokenTypes.ID); + Token token2 = lexer.getNextToken(); + warning.setAgent(token.getTokenValue() + ":" + + token2.getTokenValue()); + } else { + warning.setAgent(token.getTokenValue()); + } + + this.lexer.SPorHT(); + + // Parsing the text + String text = this.lexer.quotedString(); + warning.setText(text); + this.lexer.SPorHT(); + + warningList.add(warning); + + while (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + + warning = new Warning(); + + // Parsing the 3digits code + this.lexer.match(TokenTypes.ID); + Token tok = lexer.getNextToken(); + try { + int code = Integer.parseInt(tok.getTokenValue()); + warning.setCode(code); + } catch (NumberFormatException ex) { + throw createParseException(ex.getMessage()); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + + // Parsing the agent + this.lexer.match(TokenTypes.ID); + tok = lexer.getNextToken(); + + // Bug reported by zvali@dev.java.net + + if (lexer.lookAhead(0) == ':') { + this.lexer.match(':'); + this.lexer.match(TokenTypes.ID); + Token token2 = lexer.getNextToken(); + warning.setAgent(tok.getTokenValue() + ":" + + token2.getTokenValue()); + } else { + warning.setAgent(tok.getTokenValue()); + } + + this.lexer.SPorHT(); + + // Parsing the text + text = this.lexer.quotedString(); + warning.setText(text); + this.lexer.SPorHT(); + + warningList.add(warning); + } + + } + } finally { + if (debug) + dbg_leave("WarningParser.parse"); + } + + return warningList; + } + + /** + * public static void main(String args[]) throws ParseException { String + * warning[] = { "Warning: 307 isi.edu \"Session parameter 'foo' not + * understood\"\n", "Warning: 301 isi.edu \"Incompatible network address + * type 'E.164'\"\n", "Warning: 312 ii.edu \"Soda\", "+ " 351 i.edu \"I + * network address 'E.164'\" , 323 ii.edu \"Sodwea\"\n", "Warning: 392 + * 192.168.89.71:5060 \"Noisy feedback tells: pid=936 + * req_src_ip=192.168.89.20 in_uri=sip:xxx@yyyy.org:5061 + * out_uri=sip:xxx@yyyy.org:5061 via_cnt==1\"\n" }; + * + * for (int i = 0; i < warning.length; i++ ) { WarningParser parser = new + * WarningParser(warning[i]); WarningList warningList= (WarningList) + * parser.parse(); System.out.println("encoded = " + warningList.encode()); } + * } + */ + +} diff --git a/java/gov/nist/javax/sip/parser/extensions/JoinParser.java b/java/gov/nist/javax/sip/parser/extensions/JoinParser.java new file mode 100644 index 0000000..12c5574 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/JoinParser.java @@ -0,0 +1,78 @@ +package gov.nist.javax.sip.parser.extensions; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.parser.*; + +import java.text.ParseException; + +// Parser for Join Header (RFC3911) +// Extension by jean deruelle +// +// Join = "Join" HCOLON callid *(SEMI join-param) +// join-param = to-tag / from-tag / generic-param +// to-tag = "to-tag" EQUAL token +// from-tag = "from-tag" EQUAL token +// +// + +public class JoinParser extends ParametersParser { + + /** + * Creates new CallIDParser + * @param callID message to parse + */ + public JoinParser(String callID) { + super(callID); + } + + /** + * Constructor + * @param lexer Lexer to set + */ + protected JoinParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (CallID object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.JOIN_TO); + + Join join = new Join(); + this.lexer.SPorHT(); + String callId = lexer.byteStringNoSemicolon(); + this.lexer.SPorHT(); + super.parse(join); + join.setCallId(callId); + return join; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Join: 12345th5z8z\n", + "Join: 12345th5z8z;to-tag=tozght6-45;from-tag=fromzght789-337-2\n", + }; + + for (int i = 0; i < to.length; i++) { + JoinParser tp = new JoinParser(to[i]); + Join t = (Join) tp.parse(); + System.out.println("Parsing => " + to[i]); + System.out.print("encoded = " + t.encode() + "==> "); + System.out.println("callId " + t.getCallId() + " from-tag=" + t.getFromTag() + + " to-tag=" + t.getToTag()) ; + + } + } + +} diff --git a/java/gov/nist/javax/sip/parser/extensions/MinSEParser.java b/java/gov/nist/javax/sip/parser/extensions/MinSEParser.java new file mode 100644 index 0000000..3bd4833 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/MinSEParser.java @@ -0,0 +1,87 @@ +package gov.nist.javax.sip.parser.extensions; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.parser.*; + +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for SIP MinSE Parser. + * + * Min-SE = "Min-SE" HCOLON delta-seconds *(SEMI generic-param) + * + * @author P. Musgrave <pmusgrave@newheights.com> + * + * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a> + */ +public class MinSEParser extends ParametersParser { + + /** + * protected constructor. + * @param text is the text of the header to parse + */ + public MinSEParser(String text) { + super(text); + } + + /** + * constructor. + * @param lexer is the lexer passed in from the enclosing parser. + */ + protected MinSEParser(Lexer lexer) { + super(lexer); + } + + /** + * Parse the header. + */ + public SIPHeader parse() throws ParseException { + MinSE minse = new MinSE(); + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.MINSE_TO); + + String nextId = lexer.getNextId(); + try { + int delta = Integer.parseInt(nextId); + minse.setExpires(delta); + } catch (NumberFormatException ex) { + throw createParseException("bad integer format"); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + this.lexer.SPorHT(); + super.parse(minse); + return minse; + + } finally { + if (debug) + dbg_leave("parse"); + } + + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Min-SE: 30\n", + "Min-SE: 45;some-param=somevalue\n", + }; + + for (int i = 0; i < to.length; i++) { + MinSEParser tp = new MinSEParser(to[i]); + MinSE t = (MinSE) tp.parse(); + System.out.println("encoded = " + t.encode()); + System.out.println("\ntime=" + t.getExpires() ); + if ( t.getParameter("some-param") != null) + System.out.println("some-param=" + t.getParameter("some-param") ); + + } + } + + + + +} diff --git a/java/gov/nist/javax/sip/parser/extensions/ReferencesParser.java b/java/gov/nist/javax/sip/parser/extensions/ReferencesParser.java new file mode 100644 index 0000000..1d6e8cf --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/ReferencesParser.java @@ -0,0 +1,59 @@ +package gov.nist.javax.sip.parser.extensions; + +import gov.nist.core.Token; +import gov.nist.javax.sip.header.Reason; +import gov.nist.javax.sip.header.ReasonList; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.extensions.References; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + +public class ReferencesParser extends ParametersParser { + /** + * Creates a new instance of ReferencesParser + * @param references the header to parse + */ + public ReferencesParser(String references) { + super(references); + } + + /** + * Constructor + * @param lexer the lexer to use to parse the header + */ + protected ReferencesParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (ReasonParserList object) + * @throws SIPParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("ReasonParser.parse"); + + try { + headerName(TokenTypes.REFERENCES); + References references= new References(); + this.lexer.SPorHT(); + + String callId = lexer.byteStringNoSemicolon(); + + references.setCallId(callId); + super.parse(references); + return references; + } finally { + if (debug) + dbg_leave("ReferencesParser.parse"); + } + + + } + +} diff --git a/java/gov/nist/javax/sip/parser/extensions/ReferredByParser.java b/java/gov/nist/javax/sip/parser/extensions/ReferredByParser.java new file mode 100644 index 0000000..e377741 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/ReferredByParser.java @@ -0,0 +1,63 @@ +package gov.nist.javax.sip.parser.extensions; + + +import java.text.ParseException; +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.parser.*; + + +/** + * ReferredBy Header parser. + * + * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a> + * + * Based on JAIN ReferToParser + * + */ +public class ReferredByParser extends AddressParametersParser { + + /** + * Creates new ToParser + * @param referBy String to set + */ + public ReferredByParser(String referBy) { + super(referBy); + } + + protected ReferredByParser(Lexer lexer) { + super(lexer); + } + public SIPHeader parse() throws ParseException { + + headerName(TokenTypes.REFERREDBY_TO); + ReferredBy referBy = new ReferredBy(); + super.parse(referBy); + this.lexer.match('\n'); + return referBy; + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Referred-By: <sip:dave@denver.example.org?" + + "Replaces=12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994>\n", + "Referred-By: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\n", + "Referred-By: T. A. Watson <sip:watson@bell-telephone.com>\n", + "Referred-By: LittleGuy <sip:UserB@there.com>\n", + "Referred-By: sip:mranga@120.6.55.9\n", + "Referred-By: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\n" }; + + for (int i = 0; i < to.length; i++) { + ReferredByParser tp = new ReferredByParser(to[i]); + ReferredBy t = (ReferredBy) tp.parse(); + System.out.println("encoded = " + t.encode()); + + } + } +} +/* + * $Log: + * + */ + + diff --git a/java/gov/nist/javax/sip/parser/extensions/ReplacesParser.java b/java/gov/nist/javax/sip/parser/extensions/ReplacesParser.java new file mode 100644 index 0000000..55c77d2 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/ReplacesParser.java @@ -0,0 +1,80 @@ +package gov.nist.javax.sip.parser.extensions; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.parser.*; + +import java.text.ParseException; + +// Parser for Replaces Header (RFC3891) +// Extension by pmusgrave +// +// Replaces = "Replaces" HCOLON callid *(SEMI replaces-param) +// replaces-param = to-tag / from-tag / early-flag / generic-param +// to-tag = "to-tag" EQUAL token +// from-tag = "from-tag" EQUAL token +// early-flag = "early-only" +// +// TODO Should run a test case on early-only +// + +public class ReplacesParser extends ParametersParser { + + /** + * Creates new CallIDParser + * @param callID message to parse + */ + public ReplacesParser(String callID) { + super(callID); + } + + /** + * Constructor + * @param lexer Lexer to set + */ + protected ReplacesParser(Lexer lexer) { + super(lexer); + } + + /** + * parse the String message + * @return SIPHeader (CallID object) + * @throws ParseException if the message does not respect the spec. + */ + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.REPLACES_TO); + + Replaces replaces = new Replaces(); + this.lexer.SPorHT(); + String callId = lexer.byteStringNoSemicolon(); + this.lexer.SPorHT(); + super.parse(replaces); + replaces.setCallId(callId); + return replaces; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Replaces: 12345th5z8z\n", + "Replaces: 12345th5z8z;to-tag=tozght6-45;from-tag=fromzght789-337-2\n", + }; + + for (int i = 0; i < to.length; i++) { + ReplacesParser tp = new ReplacesParser(to[i]); + Replaces t = (Replaces) tp.parse(); + System.out.println("Parsing => " + to[i]); + System.out.print("encoded = " + t.encode() + "==> "); + System.out.println("callId " + t.getCallId() + " from-tag=" + t.getFromTag() + + " to-tag=" + t.getToTag()) ; + + } + } + +} diff --git a/java/gov/nist/javax/sip/parser/extensions/SessionExpiresParser.java b/java/gov/nist/javax/sip/parser/extensions/SessionExpiresParser.java new file mode 100644 index 0000000..e84b978 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/extensions/SessionExpiresParser.java @@ -0,0 +1,84 @@ +package gov.nist.javax.sip.parser.extensions; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.header.extensions.*; +import gov.nist.javax.sip.parser.*; + +import java.text.ParseException; +import javax.sip.*; + +/** + * Parser for SIP Session Expires Header. + * + * + */ +public class SessionExpiresParser extends ParametersParser { + + /** + * protected constructor. + * @param text is the text of the header to parse + */ + public SessionExpiresParser(String text) { + super(text); + } + + /** + * constructor. + * @param lexer is the lexer passed in from the enclosing parser. + */ + protected SessionExpiresParser(Lexer lexer) { + super(lexer); + } + + /** + * Parse the header. + */ + public SIPHeader parse() throws ParseException { + SessionExpires se = new SessionExpires(); + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.SESSIONEXPIRES_TO); + + String nextId = lexer.getNextId(); + + try { + int delta = Integer.parseInt(nextId); + se.setExpires(delta); + } catch (NumberFormatException ex) { + throw createParseException("bad integer format"); + } catch (InvalidArgumentException ex) { + throw createParseException(ex.getMessage()); + } + // May have parameters... + this.lexer.SPorHT(); + super.parse(se); + return se; + + } finally { + if (debug) + dbg_leave("parse"); + } + + } + + public static void main(String args[]) throws ParseException { + String to[] = + { "Session-Expires: 30\n", + "Session-Expires: 45;refresher=uac\n", + }; + + for (int i = 0; i < to.length; i++) { + SessionExpiresParser tp = new SessionExpiresParser(to[i]); + SessionExpires t = (SessionExpires) tp.parse(); + System.out.println("encoded = " + t.encode()); + System.out.println("\ntime=" + t.getExpires() ); + if ( t.getParameter("refresher") != null) + System.out.println("refresher=" + t.getParameter("refresher") ); + + } + } + + +} + diff --git a/java/gov/nist/javax/sip/parser/ims/AddressHeaderParser.java b/java/gov/nist/javax/sip/parser/ims/AddressHeaderParser.java new file mode 100644 index 0000000..3a589e6 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/AddressHeaderParser.java @@ -0,0 +1,72 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.parser.AddressParser; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.AddressHeaderIms; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +abstract class AddressHeaderParser extends HeaderParser { + + + protected AddressHeaderParser(Lexer lexer) { + super(lexer); + } + + protected AddressHeaderParser(String buffer) { + super(buffer); + } + + protected void parse(AddressHeaderIms addressHeader) + throws ParseException { + dbg_enter("AddressHeaderParser.parse"); + try { + AddressParser addressParser = new AddressParser(this.getLexer()); + AddressImpl addr = addressParser.address(true); + addressHeader.setAddress(addr); + + + } catch (ParseException ex) { + throw ex; + } finally { + dbg_leave("AddressParametersParser.parse"); + } + } + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PAccessNetworkInfoParser.java b/java/gov/nist/javax/sip/parser/ims/PAccessNetworkInfoParser.java new file mode 100644 index 0000000..7c1c6d9 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PAccessNetworkInfoParser.java @@ -0,0 +1,126 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + +package gov.nist.javax.sip.parser.ims; + + +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.PAccessNetworkInfo; +import gov.nist.javax.sip.header.ims.SIPHeaderNamesIms; +import gov.nist.core.Token; +import gov.nist.core.NameValue; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + + +/** + * P-Access-Network-Info header parser. + * + * <p>RFC 3455 - Private Header (P-Header) Extensions to the Session Initiation + * Protocol (SIP) for the 3rd-Generation Partnership Project (3GPP) </p> + * + * <p>Sintax (RFC 3455):</p> + * <pre> + * P-Access-Network-Info = "P-Access-Network-Info" HCOLON access-net-spec + * access-net-spec = access-type *(SEMI access-info) + * access-type = "IEEE-802.11a" / "IEEE-802.11b" / + * "3GPP-GERAN" / "3GPP-UTRAN-FDD" / + * "3GPP-UTRAN-TDD" / "3GPP-CDMA2000" / token + * access-info = cgi-3gpp / utran-cell-id-3gpp / extension-access-info + * extension-access-info = gen-value + * cgi-3gpp = "cgi-3gpp" EQUAL (token / quoted-string) + * utran-cell-id-3gpp = "utran-cell-id-3gpp" EQUAL (token / quoted-string) + * </pre> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public class PAccessNetworkInfoParser + extends HeaderParser + implements TokenTypes +{ + + public PAccessNetworkInfoParser(String accessNetwork) { + + super(accessNetwork); + + } + + + protected PAccessNetworkInfoParser(Lexer lexer) { + super(lexer); + + } + + + public SIPHeader parse() throws ParseException + { + + if (debug) + dbg_enter("AccessNetworkInfoParser.parse"); + try { + headerName(TokenTypes.P_ACCESS_NETWORK_INFO); + PAccessNetworkInfo accessNetworkInfo = new PAccessNetworkInfo(); + accessNetworkInfo.setHeaderName(SIPHeaderNamesIms.P_ACCESS_NETWORK_INFO); + + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + accessNetworkInfo.setAccessType(token.getTokenValue()); + + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ';') { + this.lexer.match(';'); + this.lexer.SPorHT(); + + NameValue nv = super.nameValue('='); + accessNetworkInfo.setParameter(nv); + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + + return accessNetworkInfo; + } finally { + if (debug) + dbg_leave("AccessNetworkInfoParser.parse"); + } + + } + + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PAssertedIdentityParser.java b/java/gov/nist/javax/sip/parser/ims/PAssertedIdentityParser.java new file mode 100644 index 0000000..b012d06 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PAssertedIdentityParser.java @@ -0,0 +1,108 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PAssertedIdentity; +import gov.nist.javax.sip.header.ims.PAssertedIdentityList; +import gov.nist.javax.sip.header.ims.SIPHeaderNamesIms; + +import gov.nist.javax.sip.parser.AddressParametersParser; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public class PAssertedIdentityParser + extends AddressParametersParser + implements TokenTypes{ + + /** + * Constructor + * @param assertedIdentity - message to parse to set + */ + public PAssertedIdentityParser(String assertedIdentity) { + super(assertedIdentity); + + } + + protected PAssertedIdentityParser(Lexer lexer) { + super(lexer); + + } + + + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("AssertedIdentityParser.parse"); + + PAssertedIdentityList assertedIdList = new PAssertedIdentityList(); + + try { + + headerName(TokenTypes.P_ASSERTED_IDENTITY); + + PAssertedIdentity pai = new PAssertedIdentity(); + pai.setHeaderName(SIPHeaderNamesIms.P_ASSERTED_IDENTITY); + + super.parse(pai); + assertedIdList.add(pai); + + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ',') + { + this.lexer.match(','); + this.lexer.SPorHT(); + + pai = new PAssertedIdentity(); + super.parse(pai); + assertedIdList.add(pai); + + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return assertedIdList; + + } + + finally { + if (debug) + dbg_leave("AssertedIdentityParser.parse"); + } + } +} diff --git a/java/gov/nist/javax/sip/parser/ims/PAssertedServiceParser.java b/java/gov/nist/javax/sip/parser/ims/PAssertedServiceParser.java new file mode 100644 index 0000000..d93330f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PAssertedServiceParser.java @@ -0,0 +1,116 @@ +package gov.nist.javax.sip.parser.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PAssertedService; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * Parse this: + * P-Asserted-Service: urn:urn-7:3gpp-service.exampletelephony.version1 + * + */ +public class PAssertedServiceParser extends HeaderParser implements TokenTypes{ + + protected PAssertedServiceParser(Lexer lexer) { + super(lexer); + } + + public PAssertedServiceParser(String pas) + { + super(pas); + } + + public SIPHeader parse() throws ParseException { + if(debug) + dbg_enter("PAssertedServiceParser.parse"); + try + { + this.lexer.match(TokenTypes.P_ASSERTED_SERVICE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PAssertedService pps = new PAssertedService(); + String urn = this.lexer.getBuffer(); + if(urn.contains(ParameterNamesIms.SERVICE_ID)){ + + if(urn.contains(ParameterNamesIms.SERVICE_ID_LABEL)) + { + String serviceID = urn.split(ParameterNamesIms.SERVICE_ID_LABEL+".")[1]; + + if(serviceID.trim().equals("")) + try { + throw new InvalidArgumentException("URN should atleast have one sub-service"); + } catch (InvalidArgumentException e) { + + e.printStackTrace(); + } + else + pps.setSubserviceIdentifiers(urn.split(ParameterNamesIms.SERVICE_ID_LABEL)[1]); + } + else if(urn.contains(ParameterNamesIms.APPLICATION_ID_LABEL)) + { + String appID = urn.split(ParameterNamesIms.APPLICATION_ID_LABEL+".")[1]; + if(appID.trim().equals("")) + try { + throw new InvalidArgumentException("URN should atleast have one sub-application"); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + else + pps.setApplicationIdentifiers(urn.split(ParameterNamesIms.APPLICATION_ID_LABEL)[1]); + } + else + { + try { + throw new InvalidArgumentException("URN is not well formed"); + + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + } + } + + super.parse(); + return pps; + } + finally{ + if(debug) + dbg_enter("PAssertedServiceParser.parse"); + } + + } +} diff --git a/java/gov/nist/javax/sip/parser/ims/PAssociatedURIParser.java b/java/gov/nist/javax/sip/parser/ims/PAssociatedURIParser.java new file mode 100644 index 0000000..73e822e --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PAssociatedURIParser.java @@ -0,0 +1,148 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/**************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) * + ****************************************************************************/ + +package gov.nist.javax.sip.parser.ims; + +import java.text.ParseException; + +import gov.nist.core.Token; +import gov.nist.javax.sip.address.GenericURI; +import gov.nist.javax.sip.header.ims.PAssociatedURI; +import gov.nist.javax.sip.header.ims.PAssociatedURIList; +import gov.nist.javax.sip.header.ims.SIPHeaderNamesIms; + +import gov.nist.javax.sip.header.Allow; +import gov.nist.javax.sip.header.ErrorInfo; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.SIPHeaderNames; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import gov.nist.javax.sip.parser.AddressParametersParser; +import gov.nist.javax.sip.parser.URLParser; + +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.HeaderParser; + + +/** + * P-Associated-URI header parser + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public class PAssociatedURIParser + extends AddressParametersParser +{ + + + /** + * Constructor + * @param associatedURI content to set + */ + public PAssociatedURIParser(String associatedURI) + { + super(associatedURI); + } + + protected PAssociatedURIParser(Lexer lexer) + { + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + if (debug) + dbg_enter("PAssociatedURIParser.parse"); + + PAssociatedURIList associatedURIList = new PAssociatedURIList(); + + try { + + headerName(TokenTypes.P_ASSOCIATED_URI); + + PAssociatedURI associatedURI = new PAssociatedURI(); + associatedURI.setHeaderName(SIPHeaderNamesIms.P_ASSOCIATED_URI); + + super.parse(associatedURI); + associatedURIList.add(associatedURI); + + this.lexer.SPorHT(); + while (lexer.lookAhead(0) == ',') + { + this.lexer.match(','); + this.lexer.SPorHT(); + + associatedURI = new PAssociatedURI(); + super.parse(associatedURI); + associatedURIList.add(associatedURI); + + this.lexer.SPorHT(); + } + this.lexer.SPorHT(); + this.lexer.match('\n'); + + return associatedURIList; + + + + + } finally { + if (debug) + dbg_leave("PAssociatedURIParser.parse"); + } + + } + + + + + + /** Test program + public static void main(String args[]) throws ParseException + { + String rou[] = { + + "P-Associated-URI: <sip:123qwe@ptinovacao.pt>\n", + + "P-Associated-URI: <sip:testes1@ptinovacao.pt>, " + + "<sip:testes2@ptinovacao.pt> \n" + }; + + for (int i = 0; i < rou.length; i++ ) { + PAssociatedURIParser rp = + new PAssociatedURIParser(rou[i]); + PAssociatedURIList list = (PAssociatedURIList) rp.parse(); + System.out.println("encoded = " +list.encode()); + } + } + + */ + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PCalledPartyIDParser.java b/java/gov/nist/javax/sip/parser/ims/PCalledPartyIDParser.java new file mode 100644 index 0000000..4a94bde --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PCalledPartyIDParser.java @@ -0,0 +1,111 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/**************************************************************************** + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) * + ****************************************************************************/ + +package gov.nist.javax.sip.parser.ims; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.PCalledPartyID; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import gov.nist.javax.sip.parser.AddressParametersParser; + +/** + * P-Called-Party-ID header parser + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public class PCalledPartyIDParser + extends AddressParametersParser +{ + + + /** + * Constructor + * @param calledPartyID content to set + */ + public PCalledPartyIDParser(String calledPartyID) + { + super(calledPartyID); + } + + protected PCalledPartyIDParser(Lexer lexer) + { + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + + if (debug) + dbg_enter("PCalledPartyIDParser.parse"); + + try { + this.lexer.match(TokenTypes.P_CALLED_PARTY_ID); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PCalledPartyID calledPartyID = new PCalledPartyID(); + super.parse(calledPartyID); + + return calledPartyID; + + } finally { + if (debug) + dbg_leave("PCalledPartyIDParser.parse"); + } + + } + + + + + /** Test program + public static void main(String args[]) throws ParseException + { + String rou[] = { + "P-Associated-URI: <sip:testes1@ptinovacao.pt>, " + + "<sip:testes2@ptinovacao.pt> \n" + }; + + for (int i = 0; i < rou.length; i++ ) { + RecordRouteParser rp = + new RecordRouteParser(rou[i]); + RecordRouteList recordRouteList = (RecordRouteList) rp.parse(); + System.out.println("encoded = " +recordRouteList.encode()); + } + } + */ + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PChargingFunctionAddressesParser.java b/java/gov/nist/javax/sip/parser/ims/PChargingFunctionAddressesParser.java new file mode 100644 index 0000000..53c274f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PChargingFunctionAddressesParser.java @@ -0,0 +1,178 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.core.NameValue; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PChargingFunctionAddresses; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + + +/** + * P-Charging-Function-Addresses header parser. + * + * <p>Sintax (RFC 3455):</p> + * <pre> + * P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON + * charge-addr-params + * * (SEMI charge-addr-params) + * charge-addr-params = ccf / ecf / generic-param + * ccf = "ccf" EQUAL gen-value + * ecf = "ecf" EQUAL gen-value + * gen-value = token / host / quoted-string + * host = hostname / IPv4address / IPv6reference + * hostname = *( domainlabel "." ) toplabel [ "." ] + * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum + * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum + * ipv6reference = "[" IPv6address "]" + * + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + * @author aayush.bhatnagar: proposed change to allow duplicate ecf and ccf header parameters. + */ + +public class PChargingFunctionAddressesParser + extends ParametersParser + implements TokenTypes { + + + public PChargingFunctionAddressesParser(String charging) { + + super(charging); + + + } + + + protected PChargingFunctionAddressesParser(Lexer lexer) { + super(lexer); + + } + + + + public SIPHeader parse() throws ParseException { + + + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.P_CHARGING_FUNCTION_ADDRESSES); + PChargingFunctionAddresses chargingFunctionAddresses = new PChargingFunctionAddresses(); + + try { + while (lexer.lookAhead(0) != '\n') { + + this.parseParameter(chargingFunctionAddresses); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == '\n' || la == '\0') + break; + + this.lexer.match(';'); + this.lexer.SPorHT(); + } + } catch (ParseException ex) { + throw ex; + } + + + super.parse(chargingFunctionAddresses); + return chargingFunctionAddresses; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + protected void parseParameter(PChargingFunctionAddresses chargingFunctionAddresses) throws ParseException { + + if (debug) + dbg_enter("parseParameter"); + try { + + NameValue nv = this.nameValue('='); + + //chargingFunctionAddresses.setParameter(nv); + chargingFunctionAddresses.setMultiParameter(nv); + + } finally { + if (debug) + dbg_leave("parseParameter"); + } + + + + } + + + + + + + /** Test program */ + + public static void main(String args[]) throws ParseException { + String r[] = { + "P-Charging-Function-Addresses: ccf=\"test str\"; ecf=token\n", + "P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2; ecf=192.1.1.3; ecf=192.1.1.4\n", + "P-Charging-Function-Addresses: ccf=[5555::b99:c88:d77:e66]; ccf=[5555::a55:b44:c33:d22]; " + + "ecf=[5555::1ff:2ee:3dd:4cc]; ecf=[5555::6aa:7bb:8cc:9dd]\n" + + }; + + + for (int i = 0; i < r.length; i++ ) + { + + PChargingFunctionAddressesParser parser = + new PChargingFunctionAddressesParser(r[i]); + + System.out.println("original = " + r[i]); + + PChargingFunctionAddresses chargAddr= (PChargingFunctionAddresses) parser.parse(); + System.out.println("encoded = " + chargAddr.encode()); + } + + + } + + + + + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PChargingVectorParser.java b/java/gov/nist/javax/sip/parser/ims/PChargingVectorParser.java new file mode 100644 index 0000000..12cec51 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PChargingVectorParser.java @@ -0,0 +1,118 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.core.NameValue; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PChargingVector; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + +/** + * P-Charging-Vector header parser. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public class PChargingVectorParser +extends ParametersParser implements TokenTypes { + + public PChargingVectorParser(String chargingVector) { + + super(chargingVector); + + } + + protected PChargingVectorParser(Lexer lexer) { + + super(lexer); + + } + + + + public SIPHeader parse() throws ParseException { + + + if (debug) + dbg_enter("parse"); + try { + headerName(TokenTypes.P_VECTOR_CHARGING); + PChargingVector chargingVector = new PChargingVector(); + + try { + while (lexer.lookAhead(0) != '\n') { + this.parseParameter(chargingVector); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == '\n' || la == '\0') + break; + this.lexer.match(';'); + this.lexer.SPorHT(); + } + + } catch (ParseException ex) { + throw ex; + } + + + super.parse(chargingVector); + if ( chargingVector.getParameter(ParameterNamesIms.ICID_VALUE) == null ) + throw new ParseException("Missing a required Parameter : " + ParameterNamesIms.ICID_VALUE, 0); + return chargingVector; + } finally { + if (debug) + dbg_leave("parse"); + } + } + + protected void parseParameter(PChargingVector chargingVector) throws ParseException { + + if (debug) + dbg_enter("parseParameter"); + try { + NameValue nv = this.nameValue('='); + chargingVector.setParameter(nv); + } finally { + if (debug) + dbg_leave("parseParameter"); + } + + + + } + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PMediaAuthorizationParser.java b/java/gov/nist/javax/sip/parser/ims/PMediaAuthorizationParser.java new file mode 100644 index 0000000..cb42009 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PMediaAuthorizationParser.java @@ -0,0 +1,145 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + +package gov.nist.javax.sip.parser.ims; + +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; + +import gov.nist.javax.sip.header.ims.PMediaAuthorizationList; +import gov.nist.javax.sip.header.ims.PMediaAuthorization; +import gov.nist.javax.sip.header.ims.SIPHeaderNamesIms; +import gov.nist.core.Token; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + + +/** + * P-Media-Authorization header parser. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +public class PMediaAuthorizationParser + extends HeaderParser + implements TokenTypes +{ + + public PMediaAuthorizationParser(String mediaAuthorization) + { + super(mediaAuthorization); + + } + + public PMediaAuthorizationParser(Lexer lexer) + { + super(lexer); + + } + + + + + + public SIPHeader parse() throws ParseException + { + PMediaAuthorizationList mediaAuthorizationList = new PMediaAuthorizationList(); + + if (debug) + dbg_enter("MediaAuthorizationParser.parse"); + + + try + { + headerName(TokenTypes.P_MEDIA_AUTHORIZATION); + + PMediaAuthorization mediaAuthorization = new PMediaAuthorization(); + mediaAuthorization.setHeaderName(SIPHeaderNamesIms.P_MEDIA_AUTHORIZATION); + + while (lexer.lookAhead(0) != '\n') + { + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + try { + mediaAuthorization.setMediaAuthorizationToken(token.getTokenValue()); + } catch (InvalidArgumentException e) { + throw createParseException(e.getMessage()); + } + mediaAuthorizationList.add(mediaAuthorization); + + this.lexer.SPorHT(); + if (lexer.lookAhead(0) == ',') + { + this.lexer.match(','); + mediaAuthorization = new PMediaAuthorization(); + } + this.lexer.SPorHT(); + } + + return mediaAuthorizationList; + + } + finally + { + if (debug) + dbg_leave("MediaAuthorizationParser.parse"); + } + + } + + + + + /* + * test + * + public static void main(String args[]) throws ParseException + { + String pHeader[] = { + "P-Media-Authorization: 0123456789 \n", + "P-Media-Authorization: 0123456789, ABCDEF\n" + }; + + for (int i = 0; i < pHeader.length; i++ ) + { + PMediaAuthorizationParser mParser = + new PMediaAuthorizationParser(pHeader[i]); + + PMediaAuthorizationList mList= (PMediaAuthorizationList) mParser.parse(); + System.out.println("encoded = " + mList.encode()); + } + } + */ + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PPreferredIdentityParser.java b/java/gov/nist/javax/sip/parser/ims/PPreferredIdentityParser.java new file mode 100644 index 0000000..a369d6c --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PPreferredIdentityParser.java @@ -0,0 +1,85 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import java.text.ParseException; + +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PPreferredIdentity; + +import gov.nist.javax.sip.parser.AddressParametersParser; + +/** + * P-Preferred-Identity header parser. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public class PPreferredIdentityParser + //extends AddressHeaderParser + extends AddressParametersParser + implements TokenTypes { + + public PPreferredIdentityParser(String preferredIdentity) { + super(preferredIdentity); + + } + + + protected PPreferredIdentityParser(Lexer lexer) { + super(lexer); + + } + + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("PreferredIdentityParser.parse"); + + try { + this.lexer.match(TokenTypes.P_PREFERRED_IDENTITY); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PPreferredIdentity p = new PPreferredIdentity(); + super.parse( p ); + return p; + } finally { + if (debug) + dbg_leave("PreferredIdentityParser.parse"); + } + + + } + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PPreferredServiceParser.java b/java/gov/nist/javax/sip/parser/ims/PPreferredServiceParser.java new file mode 100644 index 0000000..c7efb28 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PPreferredServiceParser.java @@ -0,0 +1,154 @@ +package gov.nist.javax.sip.parser.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; + +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PPreferredService; +import gov.nist.javax.sip.header.ims.ParameterNamesIms; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * Parse this: + * P-Preferred-Service: urn:urn-7:3gpp-service.exampletelephony.version1 + * + */ +public class PPreferredServiceParser extends HeaderParser implements TokenTypes{ + + protected PPreferredServiceParser(Lexer lexer) { + super(lexer); + } + + public PPreferredServiceParser(String pps) + { + super(pps); + } + + /** + * "The URN consists of a hierarchical service identifier or application + * identifier, with a sequence of labels separated by periods.The left-most label is + * the most significant one and is called 'top-level service + * identifier', while names to the right are called 'sub-services' or + * 'sub-applications'. + * + * For any given service identifier, labels can be removed right-to-left and + * the resulting URN is still valid, referring a more generic + * service, with the exception of the top-level service identifier + * and possibly the first sub-service or sub-application identifier. + * + * Labels cannot be removed beyond a defined basic service, for + * example, the label w.x may define a service, but the label w may + * only define an assignment authority for assigning subsequent + * values and not define a service in its own right. In other words, + * if a service identifier 'w.x.y.z' exists, the URNs 'w.x' and + * 'w.x.y' are also valid service identifiers, but w may not be a + * valid service identifier if it merely defines who is responsible" + * + * TODO: PLEASE VALIDATE MY UNDERSTANDING OF THE ABOVE TEXT :) + * @ranga: Please validate my understanding of the above text in the draft :) + * This last para is a little ambiguous.I will only check that atleast + * 1 sub-service or 1 sub-application is present in the URN declaration. + * If not, I throw an exception. I thought of not throwing an exception + * and returning whatever was encoded..but the resultant encoding wont + * make sense. It would be something like--> + * urn:urn-7:3gpp-service OR urn:urn-7:3gpp-application alone with no sub-services + * or sub-applications. This is bound to cause an error at the recepient later. + * + * Sub-service and Application identifiers are not maintained by IANA and + * are organization/application dependent (Section 8.2). So we cannot gurantee what lies + * beyond the first sub-service or sub-application identifier. It should be the responsibility + * of the application to make sense of the entire URN holistically. We can only check for the + * standardized part as per the ABNF. + */ + public SIPHeader parse() throws ParseException { + if(debug) + dbg_enter("PPreferredServiceParser.parse"); + try + { + + this.lexer.match(TokenTypes.P_PREFERRED_SERVICE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PPreferredService pps = new PPreferredService(); + String urn = this.lexer.getBuffer(); + if(urn.contains(ParameterNamesIms.SERVICE_ID)){ + + if(urn.contains(ParameterNamesIms.SERVICE_ID_LABEL)) + { + String serviceID = urn.split(ParameterNamesIms.SERVICE_ID_LABEL+".")[1]; + + if(serviceID.trim().equals("")) + try { + throw new InvalidArgumentException("URN should atleast have one sub-service"); + } catch (InvalidArgumentException e) { + + e.printStackTrace(); + } + else + pps.setSubserviceIdentifiers(serviceID); + } + else if(urn.contains(ParameterNamesIms.APPLICATION_ID_LABEL)) + { + String appID = urn.split(ParameterNamesIms.APPLICATION_ID_LABEL)[1]; + if(appID.trim().equals("")) + try { + throw new InvalidArgumentException("URN should atleast have one sub-application"); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + else + pps.setApplicationIdentifiers(appID); + } + else + { + try { + throw new InvalidArgumentException("URN is not well formed"); + + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } + } + } + + super.parse(); + return pps; + } + finally{ + if(debug) + dbg_enter("PPreferredServiceParser.parse"); + } + + } +} diff --git a/java/gov/nist/javax/sip/parser/ims/PProfileKeyParser.java b/java/gov/nist/javax/sip/parser/ims/PProfileKeyParser.java new file mode 100644 index 0000000..718fd97 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PProfileKeyParser.java @@ -0,0 +1,73 @@ +package gov.nist.javax.sip.parser.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +import java.text.ParseException; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PProfileKey; +import gov.nist.javax.sip.parser.AddressParametersParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + */ +public class PProfileKeyParser extends AddressParametersParser implements TokenTypes{ + + protected PProfileKeyParser(Lexer lexer) { + super(lexer); + + } + + public PProfileKeyParser(String profilekey){ + super(profilekey); + } + + public SIPHeader parse() throws ParseException { + if (debug) + dbg_enter("PProfileKey.parse"); + try { + + this.lexer.match(TokenTypes.P_PROFILE_KEY); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PProfileKey p = new PProfileKey(); + super.parse(p); + return p; + + } finally { + if (debug) + dbg_leave("PProfileKey.parse"); + } + + + } + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PServedUserParser.java b/java/gov/nist/javax/sip/parser/ims/PServedUserParser.java new file mode 100644 index 0000000..65e7941 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PServedUserParser.java @@ -0,0 +1,78 @@ +package gov.nist.javax.sip.parser.ims; + +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +import java.text.ParseException; +import gov.nist.javax.sip.address.AddressFactoryImpl; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PServedUser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +/** + * + * @author aayush.bhatnagar + * + */ +public class PServedUserParser extends ParametersParser implements TokenTypes{ + + protected PServedUserParser(Lexer lexer) { + super(lexer); + } + + public PServedUserParser(String servedUser){ + super(servedUser); + } + + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("PServedUser.parse"); + + try{ + + this.lexer.match(TokenTypes.P_SERVED_USER); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + PServedUser servedUser = new PServedUser(); + this.lexer.SPorHT(); + String servedUsername = lexer.byteStringNoSemicolon(); + servedUser.setAddress(new AddressFactoryImpl().createAddress(servedUsername)); + super.parse(servedUser); + + return servedUser; + + } + finally { + if (debug) + dbg_leave("PServedUser.parse"); + } + } + + } diff --git a/java/gov/nist/javax/sip/parser/ims/PUserDatabaseParser.java b/java/gov/nist/javax/sip/parser/ims/PUserDatabaseParser.java new file mode 100644 index 0000000..c89aec7 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PUserDatabaseParser.java @@ -0,0 +1,111 @@ +package gov.nist.javax.sip.parser.ims; +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ + +import java.text.ParseException; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PUserDatabase; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +/** + * + * @author aayush.bhatnagar + * Rancore Technologies Pvt Ltd, Mumbai India. + * + * This is the parser for the P-user-database header. + * The syntax for the P-user-database header as per + * RFC 4457 is given below: + * + * P-User-Database = "P-User-Database" HCOLON database + * *( SEMI generic-param ) + * database = LAQUOT DiameterURI RAQUOT + * + * Eg: P-User-Database: <aaa://host.example.com;transport=tcp> + * + */ +public class PUserDatabaseParser extends ParametersParser implements TokenTypes{ + + /** + * + * @param databaseName + */ + public PUserDatabaseParser(String databaseName) + { + super(databaseName); + } + + /** + * + * @param lexer + */ + public PUserDatabaseParser(Lexer lexer) + { + super(lexer); + } + + public SIPHeader parse() throws ParseException { + + if (debug) + dbg_enter("PUserDatabase.parse"); + + try{ + this.lexer.match(TokenTypes.P_USER_DATABASE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + PUserDatabase userDatabase = new PUserDatabase(); + this.parseheader(userDatabase); + + return userDatabase; + } + finally{ + if(debug) + dbg_leave("PUserDatabase.parse"); + } + } + + private void parseheader(PUserDatabase userDatabase) throws ParseException + { + StringBuffer dbname = new StringBuffer(); + this.lexer.match(LESS_THAN); + + while(this.lexer.hasMoreChars()) + { + char next = this.lexer.getNextChar(); + if (next!='>'&&next!='\n') + { + dbname.append(next); + } + + } + userDatabase.setDatabaseName(dbname.toString()); + super.parse(userDatabase); + +} +} diff --git a/java/gov/nist/javax/sip/parser/ims/PVisitedNetworkIDParser.java b/java/gov/nist/javax/sip/parser/ims/PVisitedNetworkIDParser.java new file mode 100644 index 0000000..c2f910f --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PVisitedNetworkIDParser.java @@ -0,0 +1,175 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.core.Token; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.PVisitedNetworkID; +import gov.nist.javax.sip.header.ims.PVisitedNetworkIDList; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.ParametersParser; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + +/** + * P-Visited-Network-ID header parser. + * + * <pre> + * P-Visited-Network-ID = "P-Visited-Network-ID" HCOLON + * vnetwork-spec + * *(COMMA vnetwork-spec) + * vnetwork-spec = (token / quoted-string) + * *(SEMI vnetwork-param) + * vnetwork-param = generic-param + * </pre> + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +/* + + */ + +public class PVisitedNetworkIDParser extends ParametersParser implements TokenTypes { + + /** + * Constructor + */ + public PVisitedNetworkIDParser(String networkID) { + super(networkID); + + } + + protected PVisitedNetworkIDParser(Lexer lexer) { + super(lexer); + + } + + + + + public SIPHeader parse() throws ParseException { + + PVisitedNetworkIDList visitedNetworkIDList = new PVisitedNetworkIDList(); + + if (debug) + dbg_enter("VisitedNetworkIDParser.parse"); + + try { + this.lexer.match(TokenTypes.P_VISITED_NETWORK_ID); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + + while (true) { + + PVisitedNetworkID visitedNetworkID = new PVisitedNetworkID(); + + if (this.lexer.lookAhead(0) == '\"') + parseQuotedString(visitedNetworkID); + else + parseToken(visitedNetworkID); + + visitedNetworkIDList.add(visitedNetworkID); + + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (la == '\n') + break; + else + throw createParseException("unexpected char = " + la); + } + return visitedNetworkIDList; + } finally { + if (debug) + dbg_leave("VisitedNetworkIDParser.parse"); + } + + } + + protected void parseQuotedString(PVisitedNetworkID visitedNetworkID) throws ParseException { + + if (debug) + dbg_enter("parseQuotedString"); + + try { + + StringBuffer retval = new StringBuffer(); + + if (this.lexer.lookAhead(0) != '\"') + throw createParseException("unexpected char"); + this.lexer.consume(1); + + while (true) { + char next = this.lexer.getNextChar(); + if (next == '\"') { + // Got to the terminating quote. + break; + } else if (next == '\0') { + throw new ParseException("unexpected EOL", 1); + } else if (next == '\\') { + retval.append(next); + next = this.lexer.getNextChar(); + retval.append(next); + } else { + retval.append(next); + } + } + + visitedNetworkID.setVisitedNetworkID(retval.toString()); + super.parse(visitedNetworkID); + + + + }finally { + if (debug) + dbg_leave("parseQuotedString.parse"); + } + + } + + protected void parseToken(PVisitedNetworkID visitedNetworkID) throws ParseException + { + // issued by Miguel Freitas + + lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + //String value = token.getTokenValue(); + visitedNetworkID.setVisitedNetworkID(token); + super.parse(visitedNetworkID); + + } + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PathParser.java b/java/gov/nist/javax/sip/parser/ims/PathParser.java new file mode 100644 index 0000000..94f972a --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PathParser.java @@ -0,0 +1,106 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVACAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.ims.Path; +import gov.nist.javax.sip.header.ims.PathList; +import gov.nist.javax.sip.parser.AddressParametersParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + +/** + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + + +public class PathParser extends AddressParametersParser implements TokenTypes { + + /** + * Constructor + */ + public PathParser(String path) { + super(path); + + } + + protected PathParser(Lexer lexer) { + super(lexer); + + } + + + + + /** + * parse the String message and generate the RecordRoute List Object + * @return SIPHeader the RecordRoute List object + * @throws ParseException if errors occur during the parsing + */ + + public SIPHeader parse() throws ParseException { + + PathList pathList = new PathList(); + + if (debug) + dbg_enter("PathParser.parse"); + + try { + this.lexer.match(TokenTypes.PATH); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + while (true) { + Path path = new Path(); + super.parse(path); + pathList.add(path); + this.lexer.SPorHT(); + char la = lexer.lookAhead(0); + if (la == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (la == '\n') + break; + else + throw createParseException("unexpected char"); + } + return pathList; + } finally { + if (debug) + dbg_leave("PathParser.parse"); + } + + } + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/PrivacyParser.java b/java/gov/nist/javax/sip/parser/ims/PrivacyParser.java new file mode 100644 index 0000000..faa0458 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/PrivacyParser.java @@ -0,0 +1,144 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * Privacy header parser. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + +/* + * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value) + * priv-value = "header" / "session" / "user" / "none" / "critical" / token + */ + +import gov.nist.core.*; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import gov.nist.javax.sip.parser.HeaderParser; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.Privacy; +import gov.nist.javax.sip.header.ims.PrivacyList; +import gov.nist.javax.sip.header.ims.SIPHeaderNamesIms; + + + +public class PrivacyParser + extends HeaderParser + implements TokenTypes +{ + + + public PrivacyParser(String privacyType) { + + super(privacyType); + } + + protected PrivacyParser(Lexer lexer) { + + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + if (debug) + dbg_enter("PrivacyParser.parse"); + + PrivacyList privacyList = new PrivacyList(); + + try + { + this.headerName(TokenTypes.PRIVACY); + + while (lexer.lookAhead(0) != '\n') { + this.lexer.SPorHT(); + + Privacy privacy = new Privacy(); + privacy.setHeaderName(SIPHeaderNamesIms.PRIVACY); + + this.lexer.match(TokenTypes.ID); + Token token = lexer.getNextToken(); + privacy.setPrivacy(token.getTokenValue()); + this.lexer.SPorHT(); + privacyList.add(privacy); + + // Parsing others option-tags + while (lexer.lookAhead(0) == ';') + { + this.lexer.match(';'); + this.lexer.SPorHT(); + privacy = new Privacy(); + this.lexer.match(TokenTypes.ID); + token = lexer.getNextToken(); + privacy.setPrivacy(token.getTokenValue()); + this.lexer.SPorHT(); + + privacyList.add(privacy); + } + } + + return privacyList; + + } + finally { + if (debug) + dbg_leave("PrivacyParser.parse"); + } + + } + + + /** Test program */ + public static void main(String args[]) throws ParseException + { + String rou[] = { + + "Privacy: none\n", + "Privacy: none;id;user\n" + }; + + for (int i = 0; i < rou.length; i++ ) { + PrivacyParser rp = + new PrivacyParser(rou[i]); + PrivacyList list = (PrivacyList) rp.parse(); + System.out.println("encoded = " +list.encode()); + } + } + + + +} + diff --git a/java/gov/nist/javax/sip/parser/ims/SecurityAgreeParser.java b/java/gov/nist/javax/sip/parser/ims/SecurityAgreeParser.java new file mode 100644 index 0000000..44ca2e9 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/SecurityAgreeParser.java @@ -0,0 +1,167 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * Security Agreement for SIP. + * <p>headers: Security-Client, Security-Server and Security-Verify</p> + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +import gov.nist.core.NameValue; +import gov.nist.core.Token; +import gov.nist.javax.sip.header.SIPHeaderList; +import gov.nist.javax.sip.header.ims.*; +import gov.nist.javax.sip.parser.HeaderParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +import java.text.ParseException; + + + +public class SecurityAgreeParser extends HeaderParser +{ + + public SecurityAgreeParser(String security) { + super(security); + } + + + protected SecurityAgreeParser(Lexer lexer) { + super(lexer); + } + + + protected void parseParameter(SecurityAgree header) + throws ParseException + { + if (debug) + dbg_enter("parseParameter"); + try { + NameValue nv = this.nameValue('='); + header.setParameter(nv); + } finally { + if (debug) + dbg_leave("parseParameter"); + } + } + + + public SIPHeaderList parse(SecurityAgree header) throws ParseException + { + + SIPHeaderList list; + + if (header.getClass().isInstance(new SecurityClient())) { + list = new SecurityClientList(); + } else if (header.getClass().isInstance(new SecurityServer())) { + list = new SecurityServerList(); + } else if (header.getClass().isInstance(new SecurityVerify())) { + list = new SecurityVerifyList(); + } + else + return null; + + + // the security-mechanism: + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + Token type = lexer.getNextToken(); + header.setSecurityMechanism(type.getTokenValue()); + this.lexer.SPorHT(); + + char la = lexer.lookAhead(0); + if (la == '\n') + { + list.add(header); + return list; + } + else if (la == ';') + this.lexer.match(';'); + + this.lexer.SPorHT(); + + // The parameters: + try { + while (lexer.lookAhead(0) != '\n') { + + this.parseParameter(header); + this.lexer.SPorHT(); + char laInLoop = lexer.lookAhead(0); + if (laInLoop == '\n' || laInLoop == '\0') + break; + else if (laInLoop == ',') + { + list.add(header); + if (header.getClass().isInstance(new SecurityClient())) { + header = new SecurityClient(); + } else if (header.getClass().isInstance(new SecurityServer())) { + header = new SecurityServer(); + } else if (header.getClass().isInstance(new SecurityVerify())) { + header = new SecurityVerify(); + } + + this.lexer.match(','); + // the security-mechanism: + this.lexer.SPorHT(); + lexer.match(TokenTypes.ID); + type = lexer.getNextToken(); + header.setSecurityMechanism(type.getTokenValue()); + + } + this.lexer.SPorHT(); + + if (lexer.lookAhead(0) == ';') + this.lexer.match(';'); + + this.lexer.SPorHT(); + + } + list.add(header); + + return list; + + } catch (ParseException ex) { + throw ex; + } + + + } + + + + +} + + diff --git a/java/gov/nist/javax/sip/parser/ims/SecurityClientParser.java b/java/gov/nist/javax/sip/parser/ims/SecurityClientParser.java new file mode 100644 index 0000000..bdafcce --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/SecurityClientParser.java @@ -0,0 +1,86 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * Security-Client header parser. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +import gov.nist.core.Token; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import java.text.ParseException; +import gov.nist.javax.sip.header.ims.SecurityClient; +import gov.nist.javax.sip.header.ims.SecurityClientList; + + +public class SecurityClientParser extends SecurityAgreeParser +{ + + public SecurityClientParser(String security) + { + super(security); + } + + protected SecurityClientParser(Lexer lexer) + { + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + dbg_enter("SecuriryClient parse"); + try { + + headerName(TokenTypes.SECURITY_CLIENT); + SecurityClient secClient = new SecurityClient(); + SecurityClientList secClientList = + (SecurityClientList) super.parse(secClient); + return secClientList; + + + } finally { + dbg_leave("SecuriryClient parse"); + } + } + + + + + +} + + diff --git a/java/gov/nist/javax/sip/parser/ims/SecurityServerParser.java b/java/gov/nist/javax/sip/parser/ims/SecurityServerParser.java new file mode 100644 index 0000000..9e2c1d8 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/SecurityServerParser.java @@ -0,0 +1,128 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * Security-Server header parser. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.SecurityServerList; +import gov.nist.javax.sip.header.ims.SecurityServer; + + +public class SecurityServerParser extends SecurityAgreeParser +{ + + public SecurityServerParser(String security) + { + super(security); + } + + protected SecurityServerParser(Lexer lexer) + { + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + dbg_enter("SecuriryServer parse"); + try { + + headerName(TokenTypes.SECURITY_SERVER); + SecurityServer secServer = new SecurityServer(); + SecurityServerList secServerList = + (SecurityServerList) super.parse(secServer); + return secServerList; + + } finally { + dbg_leave("SecuriryServer parse"); + } + } + + + + /** Test program + + public static void main(String args[]) throws ParseException { + String r[] = { + "Security-Server: ipsec-3gpp; ealg=aes-cbc; " + + "alg=hmac-md5-96; port-c=5062; port-s=5063; " + + "q=0.1\n" + }; + + String r2[] = { + "Security-Server: ipsec-3gpp; ealg=aes-cbc; " + + "alg=hmac-md5-96; port-c=5062; port-s=5063; " + + "q=0.1, " + + "digest; d-alg=md5; " + + "d-qop=auth-int; d-ver=AEF1D222; " + + "q=0.01\n" + }; + + + for (int i = 0; i < r.length; i++ ) + { + + SecurityServerParser parser = + new SecurityServerParser(r[i]); + + SecurityServer secServer= (SecurityServer) parser.parse(); + System.out.println("encoded = " + secServer.encode()); + } + + + for (int i = 0; i < r2.length; i++ ) { + SecurityServerParser parser = + new SecurityServerParser(r2[i]); + + java.util.ListIterator list; + SecurityServerList secList = (SecurityServerList) parser.parse(); + System.out.println("encoded = " + secList.encode()); + } + + + } + */ + + + +} + + diff --git a/java/gov/nist/javax/sip/parser/ims/SecurityVerifyParser.java b/java/gov/nist/javax/sip/parser/ims/SecurityVerifyParser.java new file mode 100644 index 0000000..3d65fa1 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/SecurityVerifyParser.java @@ -0,0 +1,84 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * Security-Verify header parser. + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; +import java.text.ParseException; +import gov.nist.javax.sip.header.ims.SecurityVerify; +import gov.nist.javax.sip.header.ims.SecurityVerifyList; + + +public class SecurityVerifyParser extends SecurityAgreeParser +{ + + public SecurityVerifyParser(String security) + { + super(security); + } + + protected SecurityVerifyParser(Lexer lexer) + { + super(lexer); + } + + + public SIPHeader parse() throws ParseException + { + dbg_enter("SecuriryVerify parse"); + try { + + headerName(TokenTypes.SECURITY_VERIFY); + SecurityVerify secVerify = new SecurityVerify(); + SecurityVerifyList secVerifyList = + (SecurityVerifyList) super.parse(secVerify); + return secVerifyList; + + } finally { + dbg_leave("SecuriryVerify parse"); + } + } + + + + + +} + + diff --git a/java/gov/nist/javax/sip/parser/ims/ServiceRouteParser.java b/java/gov/nist/javax/sip/parser/ims/ServiceRouteParser.java new file mode 100644 index 0000000..3d326c1 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/ServiceRouteParser.java @@ -0,0 +1,103 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************* + * PRODUCT OF PT INOVAO - EST DEPARTMENT * + *******************************************/ + +package gov.nist.javax.sip.parser.ims; + +import java.text.ParseException; + +import gov.nist.javax.sip.header.ims.ServiceRoute; +import gov.nist.javax.sip.header.ims.ServiceRouteList; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.parser.AddressParametersParser; +import gov.nist.javax.sip.parser.Lexer; +import gov.nist.javax.sip.parser.TokenTypes; + +/** + * Service-Route header parser. + * + * @author ALEXANDRE MIGUEL SILVA SANTOS + */ + +public class ServiceRouteParser extends AddressParametersParser { + + /** + * Constructor + */ + public ServiceRouteParser(String serviceRoute) { + super(serviceRoute); + + } + + protected ServiceRouteParser(Lexer lexer) { + super(lexer); + + } + + + + + /** + * parse the String message and generate the RecordRoute List Object + * @return SIPHeader the RecordRoute List object + * @throws ParseException if errors occur during the parsing + */ + + public SIPHeader parse() throws ParseException { + ServiceRouteList serviceRouteList = new ServiceRouteList(); + + if (debug) + dbg_enter("ServiceRouteParser.parse"); + + try { + this.lexer.match(TokenTypes.SERVICE_ROUTE); + this.lexer.SPorHT(); + this.lexer.match(':'); + this.lexer.SPorHT(); + while (true) { + ServiceRoute serviceRoute = new ServiceRoute(); + super.parse(serviceRoute); + serviceRouteList.add(serviceRoute); + this.lexer.SPorHT(); + if (lexer.lookAhead(0) == ',') { + this.lexer.match(','); + this.lexer.SPorHT(); + } else if (lexer.lookAhead(0) == '\n') + break; + else + throw createParseException("unexpected char"); + } + return serviceRouteList; + } finally { + if (debug) + dbg_leave("ServiceRouteParser.parse"); + } + + } + +} diff --git a/java/gov/nist/javax/sip/parser/ims/TokenNamesIms.java b/java/gov/nist/javax/sip/parser/ims/TokenNamesIms.java new file mode 100644 index 0000000..3f15b83 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/TokenNamesIms.java @@ -0,0 +1,52 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/************************************************************************************************ + * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal) * + ************************************************************************************************/ + + +package gov.nist.javax.sip.parser.ims; + +/** + * + * @author Miguel Freitas (IT) PT-Inovacao + */ + + +public interface TokenNamesIms + extends gov.nist.javax.sip.parser.TokenNames +{ + + public static final String IEEE_802_11A = "IEEE-802.11a"; + public static final String IEEE_802_11B = "IEEE-802.11b"; + public static final String GGGPP_GERAN = "3GPP-GERAN"; + public static final String GGGPP_UTRAN_FDD = "3GPP-UTRAN-FDD"; + public static final String GGGPP_UTRAN_TDD = "3GPP-UTRAN-TDD"; + public static final String GGGPP_CDMA2000 = "3GPP-CDMA2000"; + + + +} diff --git a/java/gov/nist/javax/sip/parser/ims/package.html b/java/gov/nist/javax/sip/parser/ims/package.html new file mode 100644 index 0000000..f599ffc --- /dev/null +++ b/java/gov/nist/javax/sip/parser/ims/package.html @@ -0,0 +1,7 @@ + +<body> +Parser for IMS headers. This code was contributed by +Jose Miguel Freitas (PT Innovacau) and ALEXANDRE MIGUEL SILVA SANTOS +to this project. This package +has been contributed to the public domain. +</body> diff --git a/java/gov/nist/javax/sip/parser/package.html b/java/gov/nist/javax/sip/parser/package.html new file mode 100644 index 0000000..54eba49 --- /dev/null +++ b/java/gov/nist/javax/sip/parser/package.html @@ -0,0 +1,4 @@ +<body> +Parsers for SIP Headers, URL's and addresses. +</body> + diff --git a/java/gov/nist/javax/sip/stack/DefaultMessageLogFactory.java b/java/gov/nist/javax/sip/stack/DefaultMessageLogFactory.java new file mode 100644 index 0000000..df83299 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/DefaultMessageLogFactory.java @@ -0,0 +1,29 @@ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.LogRecord; +import gov.nist.javax.sip.LogRecordFactory; + +/** + * The Default Message log factory. This can be replaced as a stack + * configuration parameter. + * + * @author M. Ranganathan + * + */ +public class DefaultMessageLogFactory implements LogRecordFactory { + + public LogRecord createLogRecord(String message, String source, + String destination, String timeStamp, boolean isSender, + String firstLine, String tid, String callId, long tsHeaderValue) { + return new MessageLog(message, source, destination, timeStamp, + isSender, firstLine, tid, callId, tsHeaderValue); + } + + public LogRecord createLogRecord(String message, String source, + String destination, long timeStamp, boolean isSender, + String firstLine, String tid, String callId, long timestampVal) { + return new MessageLog(message, source, destination, timeStamp, + isSender, firstLine, tid, callId, timestampVal); + } + +} diff --git a/java/gov/nist/javax/sip/stack/DefaultRouter.java b/java/gov/nist/javax/sip/stack/DefaultRouter.java new file mode 100644 index 0000000..3a56080 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/DefaultRouter.java @@ -0,0 +1,345 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.message.*; +import gov.nist.javax.sip.address.*; +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.*; +import gov.nist.core.*; +import gov.nist.core.net.AddressResolver; + +import javax.sip.*; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; + +import javax.sip.header.RouteHeader; +import javax.sip.header.ViaHeader; +import javax.sip.message.*; +import javax.sip.address.*; + +/* + * Bug reported by Will Scullin -- maddr was being ignored when routing + * requests. Bug reported by Antonis Karydas - the RequestURI can be a non-sip + * URI Jiang He - use address in route header. Significant changes to conform to + * RFC 3261 made by Jeroen van Bemmel. Hagai Sela contributed a bug fix to the + * strict route post processing code. + * + */ + +/** + * This is the default router. When the implementation wants to forward a + * request and had run out of othe options, then it calls this method to figure + * out where to send the request. The default router implements a simple + * "default routing algorithm" which just forwards to the configured proxy + * address. + * + * <p> + * When <code>javax.sip.USE_ROUTER_FOR_ALL_URIS</code> is set to + * <code>false</code>, the next hop is determined according to the following + * algorithm: + * <ul> + * <li> If the request contains one or more Route headers, use the URI of the + * topmost Route header as next hop, possibly modifying the request in the + * process if the topmost Route header contains no lr parameter(*) + * <li> Else, if the property <code>javax.sip.OUTBOUND_PROXY</code> is set, + * use its value as the next hop + * <li> Otherwise, use the request URI as next hop. If the request URI is not a + * SIP URI, call {@link javax.sip.address.Router#getNextHop(Request)} provided + * by the application. + * </ul> + * + * <p> + * (*)Note that in case the topmost Route header contains no 'lr' parameter + * (which means the next hop is a strict router), the implementation will + * perform 'Route Information Postprocessing' as described in RFC3261 section + * 16.6 step 6 (also known as "Route header popping"). That is, the following + * modifications will be made to the request: + * <ol> + * <li>The implementation places the Request-URI into the Route header field as + * the last value. + * <li>The implementation then places the first Route header field value into + * the Request-URI and removes that value from the Route header field. + * </ol> + * Subsequently, the request URI will be used as next hop target + * + * + * @version 1.2 $Revision: 1.17 $ $Date: 2009/11/14 20:06:17 $ + * + * @author M. Ranganathan <br/> + * + */ +public class DefaultRouter implements Router { + + private SipStackImpl sipStack; + + private Hop defaultRoute; + + private DefaultRouter() { + + } + + /** + * Constructor. + */ + public DefaultRouter(SipStack sipStack, String defaultRoute) { + this.sipStack = (SipStackImpl) sipStack; + if (defaultRoute != null) { + try { + this.defaultRoute = (Hop) this.sipStack.getAddressResolver() + .resolveAddress((Hop) (new HopImpl(defaultRoute))); + } catch (IllegalArgumentException ex) { + // The outbound proxy is optional. If specified it should be host:port/transport. + ((SIPTransactionStack) sipStack) + .getStackLogger() + .logError( + "Invalid default route specification - need host:port/transport"); + throw ex; + } + } + } + + /** + * Return addresses for default proxy to forward the request to. The list is + * organized in the following priority. If the requestURI refers directly to + * a host, the host and port information are extracted from it and made the + * next hop on the list. If the default route has been specified, then it is + * used to construct the next element of the list. <code> + * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME ); + * if (firstRoute!=null) { + * URI uri = firstRoute.getAddress().getURI(); + * if (uri.isSIPUri()) { + * SipURI nextHop = (SipURI) uri; + * if ( nextHop.hasLrParam() ) { + * // OK, use it + * } else { + * nextHop = fixStrictRouting( req ); <--- Here, make the modifications as per RFC3261 + * } + * } else { + * // error: non-SIP URI not allowed in Route headers + * throw new SipException( "Request has Route header with non-SIP URI" ); + * } + * } else if (outboundProxy!=null) { + * // use outbound proxy for nextHop + * } else if ( req.getRequestURI().isSipURI() ) { + * // use request URI for nextHop + * } + * + * </code> + * + * @param request + * is the sip request to route. + * + */ + public Hop getNextHop(Request request) throws SipException { + + SIPRequest sipRequest = (SIPRequest) request; + + RequestLine requestLine = sipRequest.getRequestLine(); + if (requestLine == null) { + return defaultRoute; + } + javax.sip.address.URI requestURI = requestLine.getUri(); + if (requestURI == null) + throw new IllegalArgumentException("Bad message: Null requestURI"); + + RouteList routes = sipRequest.getRouteHeaders(); + + /* + * In case the topmost Route header contains no 'lr' parameter (which + * means the next hop is a strict router), the implementation will + * perform 'Route Information Postprocessing' as described in RFC3261 + * section 16.6 step 6 (also known as "Route header popping"). That is, + * the following modifications will be made to the request: + * + * The implementation places the Request-URI into the Route header field + * as the last value. + * + * The implementation then places the first Route header field value + * into the Request-URI and removes that value from the Route header + * field. + * + * Subsequently, the request URI will be used as next hop target + */ + + if (routes != null) { + + // to send the request through a specified hop the application is + // supposed to prepend the appropriate Route header which. + Route route = (Route) routes.getFirst(); + URI uri = route.getAddress().getURI(); + if (uri.isSipURI()) { + SipURI sipUri = (SipURI) uri; + if (!sipUri.hasLrParam()) { + + fixStrictRouting(sipRequest); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("Route post processing fixed strict routing"); + } + + Hop hop = createHop(sipUri,request); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("NextHop based on Route:" + hop); + return hop; + } else { + throw new SipException("First Route not a SIP URI"); + } + + } else if (requestURI.isSipURI() + && ((SipURI) requestURI).getMAddrParam() != null) { + Hop hop = createHop((SipURI) requestURI,request); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("Using request URI maddr to route the request = " + + hop.toString()); + + // JvB: don't remove it! + // ((SipURI) requestURI).removeParameter("maddr"); + + return hop; + + } else if (defaultRoute != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("Using outbound proxy to route the request = " + + defaultRoute.toString()); + return defaultRoute; + } else if (requestURI.isSipURI()) { + Hop hop = createHop((SipURI) requestURI,request); + if (hop != null && sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Used request-URI for nextHop = " + + hop.toString()); + else if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger() + .logDebug("returning null hop -- loop detected"); + } + return hop; + + } else { + // The internal router should never be consulted for non-sip URIs. + InternalErrorHandler.handleException("Unexpected non-sip URI", + this.sipStack.getStackLogger()); + return null; + } + + } + + /** + * Performs strict router fix according to RFC3261 section 16.6 step 6 + * + * pre: top route header in request has no 'lr' parameter in URI post: + * request-URI added as last route header, new req-URI = top-route-URI + */ + public void fixStrictRouting(SIPRequest req) { + + RouteList routes = req.getRouteHeaders(); + Route first = (Route) routes.getFirst(); + SipUri firstUri = (SipUri) first.getAddress().getURI(); + routes.removeFirst(); + + // Add request-URI as last Route entry + AddressImpl addr = new AddressImpl(); + addr.setAddess(req.getRequestURI()); // don't clone it + Route route = new Route(addr); + + routes.add(route); // as last one + req.setRequestURI(firstUri); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("post: fixStrictRouting" + req); + } + } + + /** + * Utility method to create a hop from a SIP URI + * + * @param sipUri + * @return + */ + + + private final Hop createHop(SipURI sipUri, Request request) { + // always use TLS when secure + String transport = sipUri.isSecure() ? SIPConstants.TLS : sipUri + .getTransportParam(); + if (transport == null) { + //@see issue 131 + ViaHeader via = (ViaHeader) request.getHeader(ViaHeader.NAME); + transport = via.getTransport(); + } + + // sipUri.removeParameter("transport"); + + int port; + if (sipUri.getPort() != -1) { + port = sipUri.getPort(); + } else { + if (transport.equalsIgnoreCase(SIPConstants.TLS)) + port = 5061; + else + port = 5060; // TCP or UDP + } + String host = sipUri.getMAddrParam() != null ? sipUri.getMAddrParam() + : sipUri.getHost(); + AddressResolver addressResolver = this.sipStack.getAddressResolver(); + return addressResolver + .resolveAddress(new HopImpl(host, port, transport)); + + } + + /** + * Get the default hop. + * + * @return defaultRoute is the default route. public java.util.Iterator + * getDefaultRoute(Request request) { return + * this.getNextHops((SIPRequest)request); } + */ + + public javax.sip.address.Hop getOutboundProxy() { + return this.defaultRoute; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.address.Router#getNextHop(javax.sip.message.Request) + */ + public ListIterator getNextHops(Request request) { + try { + LinkedList llist = new LinkedList(); + llist.add(this.getNextHop(request)); + return llist.listIterator(); + } catch (SipException ex) { + return null; + } + + } +} diff --git a/java/gov/nist/javax/sip/stack/HandshakeCompletedListenerImpl.java b/java/gov/nist/javax/sip/stack/HandshakeCompletedListenerImpl.java new file mode 100644 index 0000000..c97459e --- /dev/null +++ b/java/gov/nist/javax/sip/stack/HandshakeCompletedListenerImpl.java @@ -0,0 +1,54 @@ +/* + * This software has been contributed by the author to the public domain. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.stack; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; + +public class HandshakeCompletedListenerImpl implements HandshakeCompletedListener { + + private HandshakeCompletedEvent handshakeCompletedEvent; + private TLSMessageChannel tlsMessageChannel; + + + public HandshakeCompletedListenerImpl(TLSMessageChannel tlsMessageChannel) { + this.tlsMessageChannel = tlsMessageChannel; + tlsMessageChannel.setHandshakeCompletedListener(this); + } + + + public void handshakeCompleted(HandshakeCompletedEvent handshakeCompletedEvent) { + this.handshakeCompletedEvent = handshakeCompletedEvent; + /* + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + + }*/ + } + + /** + * @return the handshakeCompletedEvent + */ + public HandshakeCompletedEvent getHandshakeCompletedEvent() { + return handshakeCompletedEvent; + } + + +} diff --git a/java/gov/nist/javax/sip/stack/HopImpl.java b/java/gov/nist/javax/sip/stack/HopImpl.java new file mode 100644 index 0000000..fbca8d6 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/HopImpl.java @@ -0,0 +1,188 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.stack; + +import java.io.Serializable; +import java.util.StringTokenizer; +/* + * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/> + * Network Research Team (http://www-r2.u-strasbg.fr))<br/> + * Louis Pasteur University - Strasbourg - France<br/> + * Bug fix for correct handling of IPV6 Address added by + * Daniel J. Martinez Manzano <dani@dif.um.es> + */ +/** + * Routing algorithms return a list of hops to which the request is + * routed. + * + * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:58:13 $ + * + * @author M. Ranganathan <br/> + * + * + * + + * + */ +public final class HopImpl extends Object implements javax.sip.address.Hop, Serializable { + protected String host; + protected int port; + protected String transport; + + protected boolean defaultRoute; // This is generated from the proxy addr + protected boolean uriRoute; // This is extracted from the requestURI. + + /** + * Debugging println. + */ + public String toString() { + return host + ":" + port + "/" + transport; + } + + /** + * Create new hop given host, port and transport. + * @param hostName hostname + * @param portNumber port + * @param trans transport + */ + public HopImpl(String hostName, int portNumber, String trans) { + host = hostName; + + // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + // for correct management of IPv6 addresses. + if(host.indexOf(":") >= 0) + if(host.indexOf("[") < 0) + host = "[" + host + "]"; + + port = portNumber; + transport = trans; + } + + + /** + * Creates new Hop + * @param hop is a hop string in the form of host:port/Transport + * @throws IllegalArgument exception if string is not properly formatted or null. + */ + HopImpl(String hop) throws IllegalArgumentException { + + if (hop == null) + throw new IllegalArgumentException("Null arg!"); + + // System.out.println("hop = " + hop); + int brack = hop.indexOf(']'); + int colon = hop.indexOf(':',brack); + int slash = hop.indexOf('/',colon); + + if (colon>0) { + this.host = hop.substring(0,colon); + String portstr; + if (slash>0) { + portstr = hop.substring(colon+1,slash); + this.transport = hop.substring(slash+1); + } else { + portstr = hop.substring(colon+1); + this.transport = "UDP"; + } + try { + port = Integer.parseInt(portstr); + } catch (NumberFormatException ex) { + throw new IllegalArgumentException("Bad port spec"); + } + } else { + if (slash>0) { + this.host = hop.substring(0,slash); + this.transport = hop.substring(slash+1); + this.port = transport.equalsIgnoreCase("TLS") ? 5061 : 5060; + } else { + this.host = hop; + this.transport = "UDP"; + this.port = 5060; + } + } + + // Validate it + if (host == null || host.length() == 0) + throw new IllegalArgumentException("no host!"); + + // normalize + this.host = this.host.trim(); + this.transport = this.transport.trim(); + + if ((brack>0) && host.charAt(0)!='[') { + throw new IllegalArgumentException("Bad IPv6 reference spec"); + } + + if (transport.compareToIgnoreCase("UDP") != 0 + && transport.compareToIgnoreCase("TLS") != 0 + && transport.compareToIgnoreCase("TCP") != 0) { + System.err.println("Bad transport string " + transport); + throw new IllegalArgumentException(hop); + } + } + + /** + * Retruns the host string. + * @return host String + */ + public String getHost() { + return host; + } + + /** + * Returns the port. + * @return port integer. + */ + public int getPort() { + return port; + } + + /** returns the transport string. + */ + public String getTransport() { + return transport; + } + + + + /** Return true if this is uriRoute + */ + public boolean isURIRoute() { + return uriRoute; + } + + /** Set the URIRoute flag. + */ + public void setURIRouteFlag() { + uriRoute = true; + } + + + +} diff --git a/java/gov/nist/javax/sip/stack/IOHandler.java b/java/gov/nist/javax/sip/stack/IOHandler.java new file mode 100644 index 0000000..c4be152 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/IOHandler.java @@ -0,0 +1,340 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 United States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.core.StackLogger; +import gov.nist.javax.sip.SipStackImpl; + +import java.io.*; +import java.net.*; +import java.util.Enumeration; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + +/* + * TLS support Added by Daniel J.Martinez Manzano <dani@dif.um.es> + * + */ + +/** + * Low level Input output to a socket. Caches TCP connections and takes care of re-connecting to + * the remote party if the other end drops the connection + * + * @version 1.2 + * + * @author M. Ranganathan <br/> + * + * + */ + +class IOHandler { + + private Semaphore ioSemaphore = new Semaphore(1); + + private SipStackImpl sipStack; + + private static String TCP = "tcp"; + + // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + private static String TLS = "tls"; + + // A cache of client sockets that can be re-used for + // sending tcp messages. + private ConcurrentHashMap<String, Socket> socketTable; + + protected static String makeKey(InetAddress addr, int port) { + return addr.getHostAddress() + ":" + port; + + } + + protected IOHandler(SIPTransactionStack sipStack) { + this.sipStack = (SipStackImpl) sipStack; + this.socketTable = new ConcurrentHashMap<String, Socket>(); + + } + + protected void putSocket(String key, Socket sock) { + socketTable.put(key, sock); + + } + + protected Socket getSocket(String key) { + return (Socket) socketTable.get(key); + } + + protected void removeSocket(String key) { + socketTable.remove(key); + } + + /** + * A private function to write things out. This needs to be synchronized as writes can occur + * from multiple threads. We write in chunks to allow the other side to synchronize for large + * sized writes. + */ + private void writeChunks(OutputStream outputStream, byte[] bytes, int length) + throws IOException { + // Chunk size is 16K - this hack is for large + // writes over slow connections. + synchronized (outputStream) { + // outputStream.write(bytes,0,length); + int chunksize = 8 * 1024; + for (int p = 0; p < length; p += chunksize) { + int chunk = p + chunksize < length ? chunksize : length - p; + outputStream.write(bytes, p, chunk); + } + } + outputStream.flush(); + } + + /** + * Creates and binds, if necessary, a socket connected to the specified destination address + * and port and then returns its local address. + * + * @param dst the destination address that the socket would need to connect to. + * @param dstPort the port number that the connection would be established with. + * @param localAddress the address that we would like to bind on (null for the "any" address). + * @param localPort the port that we'd like our socket to bind to (0 for a random port). + * + * @return the SocketAddress that this handler would use when connecting to the specified + * destination address and port. + * + * @throws IOException + */ + public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort, + InetAddress localAddress, int localPort) throws IOException { + String key = makeKey(dst, dstPort); + + Socket clientSock = getSocket(key); + + if (clientSock == null) { + clientSock = sipStack.getNetworkLayer().createSocket(dst, dstPort, localAddress, + localPort); + putSocket(key, clientSock); + } + + return clientSock.getLocalSocketAddress(); + + } + + /** + * Send an array of bytes. + * + * @param receiverAddress -- inet address + * @param contactPort -- port to connect to. + * @param transport -- tcp or udp. + * @param retry -- retry to connect if the other end closed connection + * @throws IOException -- if there is an IO exception sending message. + */ + + public Socket sendBytes(InetAddress senderAddress, InetAddress receiverAddress, + int contactPort, String transport, byte[] bytes, boolean retry, + MessageChannel messageChannel) throws IOException { + int retry_count = 0; + int max_retry = retry ? 2 : 1; + // Server uses TCP transport. TCP client sockets are cached + int length = bytes.length; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "sendBytes " + transport + " inAddr " + receiverAddress.getHostAddress() + + " port = " + contactPort + " length = " + length); + } + if (sipStack.isLoggingEnabled() && sipStack.isLogStackTraceOnMessageSend()) { + sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); + } + if (transport.compareToIgnoreCase(TCP) == 0) { + String key = makeKey(receiverAddress, contactPort); + // This should be in a synchronized block ( reported by + // Jayashenkhar ( lucent ). + + try { + boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS); + if (!retval) { + throw new IOException( + "Could not acquire IO Semaphore after 10 seconds -- giving up "); + } + } catch (InterruptedException ex) { + throw new IOException("exception in acquiring sem"); + } + Socket clientSock = getSocket(key); + + try { + + while (retry_count < max_retry) { + if (clientSock == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("inaddr = " + receiverAddress); + sipStack.getStackLogger().logDebug("port = " + contactPort); + } + // note that the IP Address for stack may not be + // assigned. + // sender address is the address of the listening point. + // in version 1.1 all listening points have the same IP + // address (i.e. that of the stack). In version 1.2 + // the IP address is on a per listening point basis. + clientSock = sipStack.getNetworkLayer().createSocket(receiverAddress, + contactPort, senderAddress); + OutputStream outputStream = clientSock.getOutputStream(); + writeChunks(outputStream, bytes, length); + putSocket(key, clientSock); + break; + } else { + try { + OutputStream outputStream = clientSock.getOutputStream(); + writeChunks(outputStream, bytes, length); + break; + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "IOException occured retryCount " + retry_count); + // old connection is bad. + // remove from our table. + removeSocket(key); + try { + clientSock.close(); + } catch (Exception e) { + } + clientSock = null; + retry_count++; + } + } + } + } finally { + ioSemaphore.release(); + } + + if (clientSock == null) { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug(this.socketTable.toString()); + sipStack.getStackLogger().logError( + "Could not connect to " + receiverAddress + ":" + contactPort); + } + + throw new IOException("Could not connect to " + receiverAddress + ":" + + contactPort); + } else + return clientSock; + + // Added by Daniel J. Martinez Manzano <dani@dif.um.es> + // Copied and modified from the former section for TCP + } else if (transport.compareToIgnoreCase(TLS) == 0) { + String key = makeKey(receiverAddress, contactPort); + try { + boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS); + if (!retval) + throw new IOException("Timeout acquiring IO SEM"); + } catch (InterruptedException ex) { + throw new IOException("exception in acquiring sem"); + } + Socket clientSock = getSocket(key); + + try { + while (retry_count < max_retry) { + if (clientSock == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("inaddr = " + receiverAddress); + sipStack.getStackLogger().logDebug("port = " + contactPort); + } + + clientSock = sipStack.getNetworkLayer().createSSLSocket(receiverAddress, + contactPort, senderAddress); + SSLSocket sslsock = (SSLSocket) clientSock; + HandshakeCompletedListener listner = new HandshakeCompletedListenerImpl( + (TLSMessageChannel) messageChannel); + ((TLSMessageChannel) messageChannel) + .setHandshakeCompletedListener(listner); + sslsock.addHandshakeCompletedListener(listner); + sslsock.setEnabledProtocols(sipStack.getEnabledProtocols()); + sslsock.startHandshake(); + + OutputStream outputStream = clientSock.getOutputStream(); + writeChunks(outputStream, bytes, length); + putSocket(key, clientSock); + break; + } else { + try { + OutputStream outputStream = clientSock.getOutputStream(); + writeChunks(outputStream, bytes, length); + break; + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + // old connection is bad. + // remove from our table. + removeSocket(key); + try { + clientSock.close(); + } catch (Exception e) { + } + clientSock = null; + retry_count++; + } + } + } + } finally { + ioSemaphore.release(); + } + if (clientSock == null) { + throw new IOException("Could not connect to " + receiverAddress + ":" + + contactPort); + } else + return clientSock; + + } else { + // This is a UDP transport... + DatagramSocket datagramSock = sipStack.getNetworkLayer().createDatagramSocket(); + datagramSock.connect(receiverAddress, contactPort); + DatagramPacket dgPacket = new DatagramPacket(bytes, 0, length, receiverAddress, + contactPort); + datagramSock.send(dgPacket); + datagramSock.close(); + return null; + } + + } + + /** + * Close all the cached connections. + */ + public void closeAll() { + for (Enumeration<Socket> values = socketTable.elements(); values.hasMoreElements();) { + Socket s = (Socket) values.nextElement(); + try { + s.close(); + } catch (IOException ex) { + } + } + + } + +} diff --git a/java/gov/nist/javax/sip/stack/MessageChannel.java b/java/gov/nist/javax/sip/stack/MessageChannel.java new file mode 100644 index 0000000..9987a9a --- /dev/null +++ b/java/gov/nist/javax/sip/stack/MessageChannel.java @@ -0,0 +1,489 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ + +package gov.nist.javax.sip.stack; + +import gov.nist.core.Host; +import gov.nist.core.HostPort; +import gov.nist.core.InternalErrorHandler; +import gov.nist.core.ServerLogger; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.ContentLength; +import gov.nist.javax.sip.header.ContentType; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.message.MessageFactoryImpl; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.ParseException; + +import javax.sip.address.Hop; +import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContactHeader; +import javax.sip.header.ContentLengthHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.FromHeader; +import javax.sip.header.ServerHeader; +import javax.sip.header.ToHeader; +import javax.sip.header.ViaHeader; + +/** + * Message channel abstraction for the SIP stack. + * + * @author M. Ranganathan <br/> Contains additions for support of symmetric NAT contributed by + * Hagai. + * + * @version 1.2 $Revision: 1.28 $ $Date: 2009/11/14 20:06:18 $ + * + * + */ +public abstract class MessageChannel { + + // Incremented whenever a transaction gets assigned + // to the message channel and decremented when + // a transaction gets freed from the message channel. + protected int useCount; + + /** + * Hook method, overridden by subclasses + */ + protected void uncache() {} + + /** + * Message processor to whom I belong (if set). + */ + protected transient MessageProcessor messageProcessor; + + /** + * Close the message channel. + */ + public abstract void close(); + + /** + * Get the SIPStack object from this message channel. + * + * @return SIPStack object of this message channel + */ + public abstract SIPTransactionStack getSIPStack(); + + /** + * Get transport string of this message channel. + * + * @return Transport string of this message channel. + */ + public abstract String getTransport(); + + /** + * Get whether this channel is reliable or not. + * + * @return True if reliable, false if not. + */ + public abstract boolean isReliable(); + + /** + * Return true if this is a secure channel. + */ + public abstract boolean isSecure(); + + /** + * Send the message (after it has been formatted) + * + * @param sipMessage Message to send. + */ + public abstract void sendMessage(SIPMessage sipMessage) throws IOException; + + /** + * Get the peer address of the machine that sent us this message. + * + * @return a string contianing the ip address or host name of the sender of the message. + */ + public abstract String getPeerAddress(); + + protected abstract InetAddress getPeerInetAddress(); + + protected abstract String getPeerProtocol(); + + /** + * Get the sender port ( the port of the other end that sent me the message). + */ + public abstract int getPeerPort(); + + public abstract int getPeerPacketSourcePort(); + + public abstract InetAddress getPeerPacketSourceAddress(); + + /** + * Generate a key which identifies the message channel. This allows us to cache the message + * channel. + */ + public abstract String getKey(); + + /** + * Get the host to assign for an outgoing Request via header. + */ + public abstract String getViaHost(); + + /** + * Get the port to assign for the via header of an outgoing message. + */ + public abstract int getViaPort(); + + /** + * Send the message (after it has been formatted), to a specified address and a specified port + * + * @param message Message to send. + * @param receiverAddress Address of the receiver. + * @param receiverPort Port of the receiver. + */ + protected abstract void sendMessage(byte[] message, InetAddress receiverAddress, + int receiverPort, boolean reconnectFlag) throws IOException; + + /** + * Get the host of this message channel. + * + * @return host of this messsage channel. + */ + public String getHost() { + return this.getMessageProcessor().getIpAddress().getHostAddress(); + } + + /** + * Get port of this message channel. + * + * @return Port of this message channel. + */ + public int getPort() { + if (this.messageProcessor != null) + return messageProcessor.getPort(); + else + return -1; + } + + /** + * Send a formatted message to the specified target. + * + * @param sipMessage Message to send. + * @param hop hop to send it to. + * @throws IOException If there is an error sending the message + */ + public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException { + long time = System.currentTimeMillis(); + InetAddress hopAddr = InetAddress.getByName(hop.getHost()); + + try { + + for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) { + if (messageProcessor.getIpAddress().equals(hopAddr) + && messageProcessor.getPort() == hop.getPort() + && messageProcessor.getTransport().equals(hop.getTransport())) { + MessageChannel messageChannel = messageProcessor.createMessageChannel( + hopAddr, hop.getPort()); + if (messageChannel instanceof RawMessageChannel) { + ((RawMessageChannel) messageChannel).processMessage(sipMessage); + if (getSIPStack().isLoggingEnabled()) + getSIPStack().getStackLogger().logDebug("Self routing message"); + return; + } + + } + } + byte[] msg = sipMessage.encodeAsBytes(this.getTransport()); + + this.sendMessage(msg, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest); + + } catch (IOException ioe) { + throw ioe; + } catch (Exception ex) { + if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) { + this.getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex); + } + // TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor + throw new IOException("Error self routing message"); + } finally { + + if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) + logMessage(sipMessage, hopAddr, hop.getPort(), time); + } + } + + /** + * Send a message given SIP message. + * + * @param sipMessage is the messge to send. + * @param receiverAddress is the address to which we want to send + * @param receiverPort is the port to which we want to send + */ + public void sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort) + throws IOException { + long time = System.currentTimeMillis(); + byte[] bytes = sipMessage.encodeAsBytes(this.getTransport()); + sendMessage(bytes, receiverAddress, receiverPort, sipMessage instanceof SIPRequest); + logMessage(sipMessage, receiverAddress, receiverPort, time); + } + + /** + * Convenience function to get the raw IP source address of a SIP message as a String. + */ + public String getRawIpSourceAddress() { + String sourceAddress = getPeerAddress(); + String rawIpSourceAddress = null; + try { + InetAddress sourceInetAddress = InetAddress.getByName(sourceAddress); + rawIpSourceAddress = sourceInetAddress.getHostAddress(); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + return rawIpSourceAddress; + } + + /** + * generate a key given the inet address port and transport. + */ + public static String getKey(InetAddress inetAddr, int port, String transport) { + return (transport + ":" + inetAddr.getHostAddress() + ":" + port).toLowerCase(); + } + + /** + * Generate a key given host and port. + */ + public static String getKey(HostPort hostPort, String transport) { + return (transport + ":" + hostPort.getHost().getHostname() + ":" + hostPort.getPort()) + .toLowerCase(); + } + + /** + * Get the hostport structure of this message channel. + */ + public HostPort getHostPort() { + HostPort retval = new HostPort(); + retval.setHost(new Host(this.getHost())); + retval.setPort(this.getPort()); + return retval; + } + + /** + * Get the peer host and port. + * + * @return a HostPort structure for the peer. + */ + public HostPort getPeerHostPort() { + HostPort retval = new HostPort(); + retval.setHost(new Host(this.getPeerAddress())); + retval.setPort(this.getPeerPort()); + return retval; + } + + /** + * Get the Via header for this transport. Note that this does not set a branch identifier. + * + * @return a via header for outgoing messages sent from this channel. + */ + public Via getViaHeader() { + Via channelViaHeader; + + channelViaHeader = new Via(); + try { + channelViaHeader.setTransport(getTransport()); + } catch (ParseException ex) { + } + channelViaHeader.setSentBy(getHostPort()); + return channelViaHeader; + } + + /** + * Get the via header host:port structure. This is extracted from the topmost via header of + * the request. + * + * @return a host:port structure + */ + public HostPort getViaHostPort() { + HostPort retval = new HostPort(); + retval.setHost(new Host(this.getViaHost())); + retval.setPort(this.getViaPort()); + return retval; + } + + /** + * Log a message sent to an address and port via the default interface. + * + * @param sipMessage is the message to log. + * @param address is the inet address to which the message is sent. + * @param port is the port to which the message is directed. + */ + protected void logMessage(SIPMessage sipMessage, InetAddress address, int port, long time) { + if (!getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) + return; + + // Default port. + if (port == -1) + port = 5060; + getSIPStack().serverLogger.logMessage(sipMessage, this.getHost() + ":" + this.getPort(), + address.getHostAddress().toString() + ":" + port, true, time); + } + + /** + * Log a response received at this message channel. This is used for processing incoming + * responses to a client transaction. + * + * @param receptionTime is the time at which the response was received. + * @param status is the processing status of the message. + * + */ + public void logResponse(SIPResponse sipResponse, long receptionTime, String status) { + int peerport = getPeerPort(); + if (peerport == 0 && sipResponse.getContactHeaders() != null) { + ContactHeader contact = (ContactHeader) sipResponse.getContactHeaders().getFirst(); + peerport = ((AddressImpl) contact.getAddress()).getPort(); + + } + String from = getPeerAddress().toString() + ":" + peerport; + String to = this.getHost() + ":" + getPort(); + this.getSIPStack().serverLogger.logMessage(sipResponse, from, to, status, false, + receptionTime); + } + + /** + * Creates a response to a bad request (ie one that causes a ParseException) + * + * @param badReq + * @return message bytes, null if unable to formulate response + */ + protected final String createBadReqRes(String badReq, ParseException pe) { + + StringBuffer buf = new StringBuffer(512); + buf.append("SIP/2.0 400 Bad Request (" + pe.getLocalizedMessage() + ')'); + + // We need the following headers: all Vias, CSeq, Call-ID, From, To + if (!copyViaHeaders(badReq, buf)) + return null; + if (!copyHeader(CSeqHeader.NAME, badReq, buf)) + return null; + if (!copyHeader(CallIdHeader.NAME, badReq, buf)) + return null; + if (!copyHeader(FromHeader.NAME, badReq, buf)) + return null; + if (!copyHeader(ToHeader.NAME, badReq, buf)) + return null; + + // Should add a to-tag if not already present... + int toStart = buf.indexOf(ToHeader.NAME); + if (toStart != -1 && buf.indexOf("tag", toStart) == -1) { + buf.append(";tag=badreq"); + } + + // Let's add a Server header too.. + ServerHeader s = MessageFactoryImpl.getDefaultServerHeader(); + if ( s != null ) { + buf.append("\r\n" + s.toString()); + } + int clength = badReq.length(); + if (! (this instanceof UDPMessageChannel) || + clength + buf.length() + ContentTypeHeader.NAME.length() + + ": message/sipfrag\r\n".length() + + ContentLengthHeader.NAME.length() < 1300) { + + /* + * Check to see we are within one UDP packet. + */ + ContentTypeHeader cth = new ContentType("message", "sipfrag"); + buf.append("\r\n" + cth.toString()); + ContentLength clengthHeader = new ContentLength(clength); + buf.append("\r\n" + clengthHeader.toString()); + buf.append("\r\n\r\n" + badReq); + } else { + ContentLength clengthHeader = new ContentLength(0); + buf.append("\r\n" + clengthHeader.toString()); + } + + return buf.toString(); + } + + /** + * Copies a header from a request + * + * @param name + * @param fromReq + * @param buf + * @return + * + * Note: some limitations here: does not work for short forms of headers, or continuations; + * problems when header names appear in other parts of the request + */ + private static final boolean copyHeader(String name, String fromReq, StringBuffer buf) { + int start = fromReq.indexOf(name); + if (start != -1) { + int end = fromReq.indexOf("\r\n", start); + if (end != -1) { + // XX Assumes no continuation here... + buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF + // in front + return true; + } + } + return false; + } + + /** + * Copies all via headers from a request + * + * @param fromReq + * @param buf + * @return + * + * Note: some limitations here: does not work for short forms of headers, or continuations + */ + private static final boolean copyViaHeaders(String fromReq, StringBuffer buf) { + int start = fromReq.indexOf(ViaHeader.NAME); + boolean found = false; + while (start != -1) { + int end = fromReq.indexOf("\r\n", start); + if (end != -1) { + // XX Assumes no continuation here... + buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF + // in front + found = true; + start = fromReq.indexOf(ViaHeader.NAME, end); + } else { + return false; + } + } + return found; + } + + /** + * Get the message processor. + */ + public MessageProcessor getMessageProcessor() { + return this.messageProcessor; + } +} diff --git a/java/gov/nist/javax/sip/stack/MessageLog.java b/java/gov/nist/javax/sip/stack/MessageLog.java new file mode 100644 index 0000000..37fdfe0 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/MessageLog.java @@ -0,0 +1,174 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ + +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.LogRecord; + +/** + * This class stores a message along with some other informations + * Used to log messages. + * + *@version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:13 $ + * + * @author M. Ranganathan <br/> + * @author Marc Bednarek <br/> + * + * + */ +class MessageLog implements LogRecord { + + private String message; + + private String source; + + private String destination; + + private long timeStamp; + + private boolean isSender; + + private String firstLine; + + private String tid; + + private String callId; + + private long timeStampHeaderValue; + + /* (non-Javadoc) + * @see gov.nist.javax.sip.stack.LogRecord#equals(java.lang.Object) + */ + public boolean equals(Object other) { + if (!(other instanceof MessageLog)) { + return false; + } else { + MessageLog otherLog = (MessageLog) other; + return otherLog.message.equals(message) + && otherLog.timeStamp == timeStamp; + } + } + + /** + * Constructor + */ + + public MessageLog( + String message, + String source, + String destination, + String timeStamp, + boolean isSender, + String firstLine, + String tid, + String callId, + long timeStampHeaderValue) { + if (message == null || message.equals("")) + throw new IllegalArgumentException("null msg"); + this.message = message; + this.source = source; + this.destination = destination; + try { + long ts = Long.parseLong(timeStamp); + if (ts < 0) + throw new IllegalArgumentException("Bad time stamp "); + this.timeStamp = ts; + } catch (NumberFormatException ex) { + throw new IllegalArgumentException( + "Bad number format " + timeStamp); + } + this.isSender = isSender; + this.firstLine = firstLine; + this.tid = tid; + this.callId = callId; + this.timeStampHeaderValue = timeStampHeaderValue; + } + + + + public MessageLog( + String message, + String source, + String destination, + long timeStamp, + boolean isSender, + String firstLine, + String tid, + String callId, + long timestampVal) { + if (message == null || message.equals("")) + throw new IllegalArgumentException("null msg"); + this.message = message; + this.source = source; + this.destination = destination; + if (timeStamp < 0) + throw new IllegalArgumentException("negative ts"); + this.timeStamp = timeStamp; + this.isSender = isSender; + this.firstLine = firstLine; + this.tid = tid; + this.callId = callId; + this.timeStampHeaderValue = timestampVal; + } + + + /* (non-Javadoc) + * @see gov.nist.javax.sip.stack.LogRecord#toString() + */ + + public String toString() { + String log; + + + log = + "<message\nfrom=\"" + + source + + "\" \nto=\"" + + destination + + "\" \ntime=\"" + + timeStamp + + "\"" + + (this.timeStampHeaderValue != 0 ? "\ntimeStamp = \"" + timeStampHeaderValue + "\"": "") + +"\nisSender=\"" + + isSender + + "\" \ntransactionId=\"" + + tid + + "\" \ncallId=\"" + + callId + + "\" \nfirstLine=\"" + + firstLine.trim() + "\"" + + " \n>\n"; + log += "<![CDATA["; + log += message; + log += "]]>\n"; + log += "</message>\n"; + + return log; + } +} diff --git a/java/gov/nist/javax/sip/stack/MessageProcessor.java b/java/gov/nist/javax/sip/stack/MessageProcessor.java new file mode 100644 index 0000000..b97cc22 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/MessageProcessor.java @@ -0,0 +1,356 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.stack; + +import gov.nist.core.Host; +import gov.nist.core.HostPort; +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.ListeningPointImpl; +import gov.nist.javax.sip.header.Via; + +import java.io.IOException; +import java.net.InetAddress; +import java.text.ParseException; + +import javax.sip.InvalidArgumentException; + +/** + * This is the Stack abstraction for the active object that waits for messages + * to appear on the wire and processes these messages by calling the + * MessageFactory interface to create a ServerRequest or ServerResponse object. + * The main job of the message processor is to instantiate message channels for + * the given transport. + * + * @version 1.2 $Revision: 1.18 $ $Date: 2009/10/16 22:58:41 $ + * + * @author M. Ranganathan <br/> + * + */ +public abstract class MessageProcessor implements Runnable { + /** + * A string containing the 0.0.0.0 IPv4 ANY address. + */ + protected static final String IN_ADDR_ANY = "0.0.0.0"; + + /** + * A string containing the ::0 IPv6 ANY address. + */ + protected static final String IN6_ADDR_ANY = "::0"; + /** + * My Sent by string ( which I use to set the outgoing via header) + */ + private String sentBy; + + private HostPort sentByHostPort; + + /* + * The IP Address that was originally assigned ( Can be ANY ) + */ + + private String savedIpAddress; + + /** + * The IP address where I am listening. + */ + private InetAddress ipAddress; + + /** + * The port where I am listening + */ + private int port; + + /** + * The transport where I am listening + */ + protected String transport; + + /** + * The Listening Point to which I am assigned. + */ + private ListeningPointImpl listeningPoint; + + private boolean sentBySet; + + /** + * Our stack (that created us). + */ + protected SIPTransactionStack sipStack; + + protected MessageProcessor( String transport ) { + this.transport = transport; + } + + /** + * Constructor + * + * @param ipAddress -- ip address where I am listening for incoming requests. + * @param port -- port where i am listening for incoming requests. + * @param transport -- transport to use for the message processor (UDP/TCP/TLS). + */ + protected MessageProcessor( InetAddress ipAddress, int port, String transport, + SIPTransactionStack transactionStack ) { + this( transport ); + this.initialize(ipAddress, port, transactionStack); + } + + /** + * Initializes this MessageProcessor. Needed for extensions + * that use classloading + * + * @param ipAddress2 + * @param transactionStack + * @param port2 + */ + public final void initialize( InetAddress ipAddress, int port, + SIPTransactionStack transactionStack ) { + + this.sipStack = transactionStack; + this.savedIpAddress = ipAddress.getHostAddress(); + this.ipAddress = ipAddress; + this.port = port; + this.sentByHostPort = new HostPort(); + this.sentByHostPort.setHost(new Host(ipAddress.getHostAddress())); + this.sentByHostPort.setPort(port); + } + + /** + * Get the transport string. + * + * @return A string that indicates the transport. (i.e. "tcp" or "udp") + */ + public String getTransport() { + return this.transport; + } + + /** + * Get the port identifier. + * + * @return the port for this message processor. This is where you receive + * messages. + */ + public int getPort() { + return this.port; + } + + /** + * Get the Via header to assign for this message processor. The topmost via + * header of the outoging messages use this. + * + * @return the ViaHeader to be used by the messages sent via this message processor. + */ + public Via getViaHeader() { + try { + Via via = new Via(); + if (this.sentByHostPort != null) { + via.setSentBy(sentByHostPort); + via.setTransport(this.getTransport()); + } else { + Host host = new Host(); + host.setHostname(this.getIpAddress().getHostAddress()); + via.setHost(host); + via.setPort(this.getPort()); + via.setTransport(this.getTransport()); + } + return via; + } catch (ParseException ex) { + ex.printStackTrace(); + return null; + } catch (InvalidArgumentException ex) { + ex.printStackTrace(); + return null; + } + } + public ListeningPointImpl getListeningPoint() { + if ( listeningPoint == null ) { + if ( this.getSIPStack().isLoggingEnabled()) { + this.getSIPStack().getStackLogger().logError("getListeningPoint" + this + + " returning null listeningpoint"); + + } + } + return listeningPoint; + } + + public void setListeningPoint(ListeningPointImpl lp) { + if ( this.getSIPStack().isLoggingEnabled()) { + this.getSIPStack().getStackLogger().logDebug("setListeningPoint" + this + + " listeningPoint = " + lp); + + } + if ( lp.getPort() != this.getPort()) + InternalErrorHandler.handleException + ("lp mismatch with provider",getSIPStack().getStackLogger()); + this.listeningPoint = lp; + + } + + /** + * Get the saved IP Address. + */ + public String getSavedIpAddress() { + return this.savedIpAddress; + } + /** + * @return the ip address for this message processor. + */ + public InetAddress getIpAddress() { + return this.ipAddress; + } + /** + * @param ipAddress the ipAddress to set + */ + protected void setIpAddress(InetAddress ipAddress) { + this.sentByHostPort.setHost( new Host(ipAddress.getHostAddress())); + this.ipAddress = ipAddress; + } + + /** + * Set the sentby string. This is used for stamping outgoing messages sent + * from this listening point. + * + * @param sentBy + */ + public void setSentBy(String sentBy) throws ParseException { + + int ind = sentBy.indexOf(":"); + if (ind == -1) { + this.sentByHostPort = new HostPort(); + this.sentByHostPort.setHost(new Host(sentBy)); + } else { + this.sentByHostPort = new HostPort(); + this.sentByHostPort.setHost(new Host(sentBy.substring(0, ind))); + String portStr = sentBy.substring(ind + 1); + try { + int port = Integer.parseInt(portStr); + this.sentByHostPort.setPort(port); + } catch (NumberFormatException ex) { + throw new ParseException("Bad format encountered at ", ind); + } + } + this.sentBySet = true; + this.sentBy = sentBy; + + } + + /** + * Get the sentby string. + * + */ + public String getSentBy() { + if ( this.sentBy == null && this.sentByHostPort != null) { + this.sentBy = this.sentByHostPort.toString(); + } + return this.sentBy; + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Abstract methods + /////////////////////////////////////////////////////////////////////////////////////// + /** + * Get the SIP Stack. + * + * @return the sip stack. + */ + public abstract SIPTransactionStack getSIPStack(); + + /** + * Create a message channel for the specified host/port. + * + * @return New MessageChannel for this processor. + */ + public abstract MessageChannel createMessageChannel(HostPort targetHostPort) + throws IOException; + + /** + * Create a message channel for the specified host/port. + * + * @return New MessageChannel for this processor. + */ + public abstract MessageChannel createMessageChannel(InetAddress targetHost, + int port) throws IOException; + + + /** + * Start our thread. + */ + public abstract void start() throws IOException; + + /** + * Stop method. + */ + public abstract void stop(); + + /** + * Default target port used by this processor. This is 5060 for TCP / UDP + */ + public abstract int getDefaultTargetPort(); + + /** + * Flags whether this processor is secure or not. + */ + public abstract boolean isSecure(); + + /** + * Maximum number of bytes that this processor can handle. + */ + public abstract int getMaximumMessageSize(); + + /** + * Return true if there are pending messages to be processed (which prevents + * the message channel from being closed). + */ + public abstract boolean inUse(); + + + + /** + * Run method. + */ + public abstract void run(); + + /** + * @return Returns the sentBySet. + */ + public boolean isSentBySet() { + return sentBySet; + } + + + /** + * Get the defalt port for the message processor. + * + * @param transport + * @return -- the default port for the message processor. + */ + + public static int getDefaultPort(String transport) { + + return transport.equalsIgnoreCase("TLS")?5061:5060; + } + + + +} diff --git a/java/gov/nist/javax/sip/stack/RawMessageChannel.java b/java/gov/nist/javax/sip/stack/RawMessageChannel.java new file mode 100644 index 0000000..1ee9ded --- /dev/null +++ b/java/gov/nist/javax/sip/stack/RawMessageChannel.java @@ -0,0 +1,9 @@ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.message.SIPMessage; + +public interface RawMessageChannel { + + public abstract void processMessage(SIPMessage sipMessage) throws Exception ; + +} diff --git a/java/gov/nist/javax/sip/stack/SIPClientTransaction.java b/java/gov/nist/javax/sip/stack/SIPClientTransaction.java new file mode 100644 index 0000000..dd915e4 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPClientTransaction.java @@ -0,0 +1,1570 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.stack; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.Utils; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.RecordRoute; +import gov.nist.javax.sip.header.RecordRouteList; +import gov.nist.javax.sip.header.Route; +import gov.nist.javax.sip.header.RouteList; +import gov.nist.javax.sip.header.TimeStamp; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.text.ParseException; +import java.util.ListIterator; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.sip.Dialog; +import javax.sip.DialogState; +import javax.sip.InvalidArgumentException; +import javax.sip.ObjectInUseException; +import javax.sip.SipException; +import javax.sip.Timeout; +import javax.sip.TimeoutEvent; +import javax.sip.TransactionState; +import javax.sip.address.Hop; +import javax.sip.address.SipURI; +import javax.sip.header.ExpiresHeader; +import javax.sip.header.RouteHeader; +import javax.sip.header.TimeStampHeader; +import javax.sip.message.Request; + +/* + * Jeff Keyser -- initial. Daniel J. Martinez Manzano --Added support for TLS message channel. + * Emil Ivov -- bug fixes. Chris Beardshear -- bug fix. Andreas Bystrom -- bug fixes. Matt Keller + * (Motorolla) -- bug fix. + */ + +/** + * Represents a client transaction. Implements the following state machines. (From RFC 3261) + * + * <pre> + * + * + * + * + * + * + * |INVITE from TU + * Timer A fires |INVITE sent + * Reset A, V Timer B fires + * INVITE sent +-----------+ or Transport Err. + * +---------| |---------------+inform TU + * | | Calling | | + * +-------->| |-------------->| + * +-----------+ 2xx | + * | | 2xx to TU | + * | |1xx | + * 300-699 +---------------+ |1xx to TU | + * ACK sent | | | + * resp. to TU | 1xx V | + * | 1xx to TU -----------+ | + * | +---------| | | + * | | |Proceeding |-------------->| + * | +-------->| | 2xx | + * | +-----------+ 2xx to TU | + * | 300-699 | | + * | ACK sent, | | + * | resp. to TU| | + * | | | NOTE: + * | 300-699 V | + * | ACK sent +-----------+Transport Err. | transitions + * | +---------| |Inform TU | labeled with + * | | | Completed |-------------->| the event + * | +-------->| | | over the action + * | +-----------+ | to take + * | ˆ | | + * | | | Timer D fires | + * +--------------+ | - | + * | | + * V | + * +-----------+ | + * | | | + * | Terminated|<--------------+ + * | | + * +-----------+ + * + * Figure 5: INVITE client transaction + * + * + * |Request from TU + * |send request + * Timer E V + * send request +-----------+ + * +---------| |-------------------+ + * | | Trying | Timer F | + * +-------->| | or Transport Err.| + * +-----------+ inform TU | + * 200-699 | | | + * resp. to TU | |1xx | + * +---------------+ |resp. to TU | + * | | | + * | Timer E V Timer F | + * | send req +-----------+ or Transport Err. | + * | +---------| | inform TU | + * | | |Proceeding |------------------>| + * | +-------->| |-----+ | + * | +-----------+ |1xx | + * | | ˆ |resp to TU | + * | 200-699 | +--------+ | + * | resp. to TU | | + * | | | + * | V | + * | +-----------+ | + * | | | | + * | | Completed | | + * | | | | + * | +-----------+ | + * | ˆ | | + * | | | Timer K | + * +--------------+ | - | + * | | + * V | + * NOTE: +-----------+ | + * | | | + * transitions | Terminated|<------------------+ + * labeled with | | + * the event +-----------+ + * over the action + * to take + * + * Figure 6: non-INVITE client transaction + * + * + * + * + * + * + * </pre> + * + * + * @author M. Ranganathan + * + * @version 1.2 $Revision: 1.122 $ $Date: 2009/12/17 23:33:52 $ + */ +public class SIPClientTransaction extends SIPTransaction implements ServerResponseInterface, + javax.sip.ClientTransaction, gov.nist.javax.sip.ClientTransactionExt { + + // a SIP Client transaction may belong simultaneously to multiple + // dialogs in the early state. These dialogs all have + // the same call ID and same From tag but different to tags. + + private ConcurrentHashMap<String,SIPDialog> sipDialogs; + + private SIPRequest lastRequest; + + private int viaPort; + + private String viaHost; + + // Real ResponseInterface to pass messages to + private transient ServerResponseInterface respondTo; + + private SIPDialog defaultDialog; + + private Hop nextHop; + + private boolean notifyOnRetransmit; + + private boolean timeoutIfStillInCallingState; + + private int callingStateTimeoutCount; + + public class TransactionTimer extends SIPStackTimerTask { + + public TransactionTimer() { + + } + + protected void runTask() { + SIPClientTransaction clientTransaction; + SIPTransactionStack sipStack; + clientTransaction = SIPClientTransaction.this; + sipStack = clientTransaction.sipStack; + + // If the transaction has terminated, + if (clientTransaction.isTerminated()) { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "removing = " + clientTransaction + " isReliable " + + clientTransaction.isReliable()); + } + + sipStack.removeTransaction(clientTransaction); + + try { + this.cancel(); + + } catch (IllegalStateException ex) { + if (!sipStack.isAlive()) + return; + } + + // Client transaction terminated. Kill connection if + // this is a TCP after the linger timer has expired. + // The linger timer is needed to allow any pending requests to + // return responses. + if ((!sipStack.cacheClientConnections) && clientTransaction.isReliable()) { + + int newUseCount = --clientTransaction.getMessageChannel().useCount; + if (newUseCount <= 0) { + // Let the connection linger for a while and then close + // it. + TimerTask myTimer = new LingerTimer(); + sipStack.getTimer().schedule(myTimer, + SIPTransactionStack.CONNECTION_LINGER_TIME * 1000); + } + + } else { + // Cache the client connections so dont close the + // connection. This keeps the connection open permanently + // until the client disconnects. + if (sipStack.isLoggingEnabled() && clientTransaction.isReliable()) { + int useCount = clientTransaction.getMessageChannel().useCount; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Client Use Count = " + useCount); + } + } + + } else { + // If this transaction has not + // terminated, + // Fire the transaction timer. + clientTransaction.fireTimer(); + + } + + } + + } + + /** + * Creates a new client transaction. + * + * @param newSIPStack Transaction stack this transaction belongs to. + * @param newChannelToUse Channel to encapsulate. + * @return the created client transaction. + */ + protected SIPClientTransaction(SIPTransactionStack newSIPStack, MessageChannel newChannelToUse) { + super(newSIPStack, newChannelToUse); + // Create a random branch parameter for this transaction + // setBranch( SIPConstants.BRANCH_MAGIC_COOKIE + + // Integer.toHexString( hashCode( ) ) ); + setBranch(Utils.getInstance().generateBranchId()); + this.messageProcessor = newChannelToUse.messageProcessor; + this.setEncapsulatedChannel(newChannelToUse); + this.notifyOnRetransmit = false; + this.timeoutIfStillInCallingState = false; + + // This semaphore guards the listener from being + // re-entered for this transaction. That is + // for a give tx, the listener is called at most + // once with an outstanding request. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Creating clientTransaction " + this); + sipStack.getStackLogger().logStackTrace(); + } + // this.startTransactionTimer(); + this.sipDialogs = new ConcurrentHashMap(); + } + + /** + * Sets the real ResponseInterface this transaction encapsulates. + * + * @param newRespondTo ResponseInterface to send messages to. + */ + public void setResponseInterface(ServerResponseInterface newRespondTo) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Setting response interface for " + this + " to " + newRespondTo); + if (newRespondTo == null) { + sipStack.getStackLogger().logStackTrace(); + sipStack.getStackLogger().logDebug("WARNING -- setting to null!"); + } + } + + respondTo = newRespondTo; + + } + + /** + * Returns this transaction. + */ + public MessageChannel getRequestChannel() { + + return this; + + } + + /** + * Deterines if the message is a part of this transaction. + * + * @param messageToTest Message to check if it is part of this transaction. + * + * @return true if the message is part of this transaction, false if not. + */ + public boolean isMessagePartOfTransaction(SIPMessage messageToTest) { + + // List of Via headers in the message to test + ViaList viaHeaders = messageToTest.getViaHeaders(); + // Flags whether the select message is part of this transaction + boolean transactionMatches; + String messageBranch = ((Via) viaHeaders.getFirst()).getBranch(); + boolean rfc3261Compliant = getBranch() != null + && messageBranch != null + && getBranch().toLowerCase().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE) + && messageBranch.toLowerCase().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE); + + transactionMatches = false; + if (TransactionState.COMPLETED == this.getState()) { + if (rfc3261Compliant) { + transactionMatches = getBranch().equalsIgnoreCase( + ((Via) viaHeaders.getFirst()).getBranch()) + && getMethod().equals(messageToTest.getCSeq().getMethod()); + } else { + transactionMatches = getBranch().equals(messageToTest.getTransactionId()); + } + } else if (!isTerminated()) { + if (rfc3261Compliant) { + if (viaHeaders != null) { + // If the branch parameter is the + // same as this transaction and the method is the same, + if (getBranch().equalsIgnoreCase(((Via) viaHeaders.getFirst()).getBranch())) { + transactionMatches = getOriginalRequest().getCSeq().getMethod().equals( + messageToTest.getCSeq().getMethod()); + + } + } + } else { + // not RFC 3261 compliant. + if (getBranch() != null) { + transactionMatches = getBranch().equalsIgnoreCase( + messageToTest.getTransactionId()); + } else { + transactionMatches = getOriginalRequest().getTransactionId() + .equalsIgnoreCase(messageToTest.getTransactionId()); + } + + } + + } + return transactionMatches; + + } + + /** + * Send a request message through this transaction and onto the client. + * + * @param messageToSend Request to process and send. + */ + public void sendMessage(SIPMessage messageToSend) throws IOException { + + try { + // Message typecast as a request + SIPRequest transactionRequest; + + transactionRequest = (SIPRequest) messageToSend; + + // Set the branch id for the top via header. + Via topVia = (Via) transactionRequest.getViaHeaders().getFirst(); + // Tack on a branch identifier to match responses. + try { + topVia.setBranch(getBranch()); + } catch (java.text.ParseException ex) { + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Sending Message " + messageToSend); + sipStack.getStackLogger().logDebug("TransactionState " + this.getState()); + } + // If this is the first request for this transaction, + if (TransactionState.PROCEEDING == getState() + || TransactionState.CALLING == getState()) { + + // If this is a TU-generated ACK request, + if (transactionRequest.getMethod().equals(Request.ACK)) { + + // Send directly to the underlying + // transport and close this transaction + if (isReliable()) { + this.setState(TransactionState.TERMINATED); + } else { + this.setState(TransactionState.COMPLETED); + } + // BUGBUG -- This suppresses sending the ACK uncomment this + // to + // test 4xx retransmission + // if (transactionRequest.getMethod() != Request.ACK) + super.sendMessage(transactionRequest); + return; + + } + + } + try { + + // Send the message to the server + lastRequest = transactionRequest; + if (getState() == null) { + // Save this request as the one this transaction + // is handling + setOriginalRequest(transactionRequest); + // Change to trying/calling state + // Set state first to avoid race condition.. + + if (transactionRequest.getMethod().equals(Request.INVITE)) { + this.setState(TransactionState.CALLING); + } else if (transactionRequest.getMethod().equals(Request.ACK)) { + // Acks are never retransmitted. + this.setState(TransactionState.TERMINATED); + } else { + this.setState(TransactionState.TRYING); + } + if (!isReliable()) { + enableRetransmissionTimer(); + } + if (isInviteTransaction()) { + enableTimeoutTimer(TIMER_B); + } else { + enableTimeoutTimer(TIMER_F); + } + } + // BUGBUG This supresses sending ACKS -- uncomment to test + // 4xx retransmission. + // if (transactionRequest.getMethod() != Request.ACK) + super.sendMessage(transactionRequest); + + } catch (IOException e) { + + this.setState(TransactionState.TERMINATED); + throw e; + + } + } finally { + this.isMapped = true; + this.startTransactionTimer(); + + } + + } + + /** + * Process a new response message through this transaction. If necessary, this message will + * also be passed onto the TU. + * + * @param transactionResponse Response to process. + * @param sourceChannel Channel that received this message. + */ + public synchronized void processResponse(SIPResponse transactionResponse, + MessageChannel sourceChannel, SIPDialog dialog) { + + // If the state has not yet been assigned then this is a + // spurious response. + + if (getState() == null) + return; + + // Ignore 1xx + if ((TransactionState.COMPLETED == this.getState() || TransactionState.TERMINATED == this + .getState()) + && transactionResponse.getStatusCode() / 100 == 1) { + return; + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "processing " + transactionResponse.getFirstLine() + "current state = " + + getState()); + sipStack.getStackLogger().logDebug("dialog = " + dialog); + } + + this.lastResponse = transactionResponse; + + /* + * JvB: this is now duplicate with code in the other processResponse + * + * if (dialog != null && transactionResponse.getStatusCode() != 100 && + * (transactionResponse.getTo().getTag() != null || sipStack .isRfc2543Supported())) { // + * add the route before you process the response. dialog.setLastResponse(this, + * transactionResponse); this.setDialog(dialog, transactionResponse.getDialogId(false)); } + */ + + try { + if (isInviteTransaction()) + inviteClientTransaction(transactionResponse, sourceChannel, dialog); + else + nonInviteClientTransaction(transactionResponse, sourceChannel, dialog); + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + this.setState(TransactionState.TERMINATED); + raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); + } + } + + /** + * Implements the state machine for invite client transactions. + * + * <pre> + * + * + * + * + * + * |Request from TU + * |send request + * Timer E V + * send request +-----------+ + * +---------| |-------------------+ + * | | Trying | Timer F | + * +-------->| | or Transport Err.| + * +-----------+ inform TU | + * 200-699 | | | + * resp. to TU | |1xx | + * +---------------+ |resp. to TU | + * | | | + * | Timer E V Timer F | + * | send req +-----------+ or Transport Err. | + * | +---------| | inform TU | + * | | |Proceeding |------------------>| + * | +-------->| |-----+ | + * | +-----------+ |1xx | + * | | ˆ |resp to TU | + * | 200-699 | +--------+ | + * | resp. to TU | | + * | | | + * | V | + * | +-----------+ | + * | | | | + * | | Completed | | + * | | | | + * | +-----------+ | + * | ˆ | | + * | | | Timer K | + * +--------------+ | - | + * | | + * V | + * NOTE: +-----------+ | + * | | | + * transitions | Terminated|<------------------+ + * labeled with | | + * the event +-----------+ + * over the action + * to take + * + * Figure 6: non-INVITE client transaction + * + * + * + * + * </pre> + * + * @param transactionResponse -- transaction response received. + * @param sourceChannel - source channel on which the response was received. + */ + private void nonInviteClientTransaction(SIPResponse transactionResponse, + MessageChannel sourceChannel, SIPDialog sipDialog) throws IOException { + int statusCode = transactionResponse.getStatusCode(); + if (TransactionState.TRYING == this.getState()) { + if (statusCode / 100 == 1) { + this.setState(TransactionState.PROCEEDING); + enableRetransmissionTimer(MAXIMUM_RETRANSMISSION_TICK_COUNT); + enableTimeoutTimer(TIMER_F); + // According to RFC, the TU has to be informed on + // this transition. + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, sipDialog); + } else { + this.semRelease(); + } + } else if (200 <= statusCode && statusCode <= 699) { + // Send the response up to the TU. + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, sipDialog); + } else { + this.semRelease(); + } + if (!isReliable()) { + this.setState(TransactionState.COMPLETED); + enableTimeoutTimer(TIMER_K); + } else { + this.setState(TransactionState.TERMINATED); + } + } + } else if (TransactionState.PROCEEDING == this.getState()) { + if (statusCode / 100 == 1) { + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, sipDialog); + } else { + this.semRelease(); + } + } else if (200 <= statusCode && statusCode <= 699) { + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, sipDialog); + } else { + this.semRelease(); + } + disableRetransmissionTimer(); + disableTimeoutTimer(); + if (!isReliable()) { + this.setState(TransactionState.COMPLETED); + enableTimeoutTimer(TIMER_K); + } else { + this.setState(TransactionState.TERMINATED); + } + } + } else { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + " Not sending response to TU! " + getState()); + } + this.semRelease(); + } + } + + /** + * Implements the state machine for invite client transactions. + * + * <pre> + * + * + * + * + * + * |INVITE from TU + * Timer A fires |INVITE sent + * Reset A, V Timer B fires + * INVITE sent +-----------+ or Transport Err. + * +---------| |---------------+inform TU + * | | Calling | | + * +-------->| |-------------->| + * +-----------+ 2xx | + * | | 2xx to TU | + * | |1xx | + * 300-699 +---------------+ |1xx to TU | + * ACK sent | | | + * resp. to TU | 1xx V | + * | 1xx to TU -----------+ | + * | +---------| | | + * | | |Proceeding |-------------->| + * | +-------->| | 2xx | + * | +-----------+ 2xx to TU | + * | 300-699 | | + * | ACK sent, | | + * | resp. to TU| | + * | | | NOTE: + * | 300-699 V | + * | ACK sent +-----------+Transport Err. | transitions + * | +---------| |Inform TU | labeled with + * | | | Completed |-------------->| the event + * | +-------->| | | over the action + * | +-----------+ | to take + * | ˆ | | + * | | | Timer D fires | + * +--------------+ | - | + * | | + * V | + * +-----------+ | + * | | | + * | Terminated|<--------------+ + * | | + * +-----------+ + * + * + * + * + * </pre> + * + * @param transactionResponse -- transaction response received. + * @param sourceChannel - source channel on which the response was received. + */ + + private void inviteClientTransaction(SIPResponse transactionResponse, + MessageChannel sourceChannel, SIPDialog dialog) throws IOException { + int statusCode = transactionResponse.getStatusCode(); + + if (TransactionState.TERMINATED == this.getState()) { + boolean ackAlreadySent = false; + if (dialog != null && dialog.isAckSeen() && dialog.getLastAckSent() != null) { + if (dialog.getLastAckSent().getCSeq().getSeqNumber() == transactionResponse.getCSeq() + .getSeqNumber() + && transactionResponse.getFromTag().equals( + dialog.getLastAckSent().getFromTag())) { + // the last ack sent corresponded to this response + ackAlreadySent = true; + } + } + // retransmit the ACK for this response. + if (dialog!= null && ackAlreadySent + && transactionResponse.getCSeq().getMethod().equals(dialog.getMethod())) { + try { + // Found the dialog - resend the ACK and + // dont pass up the null transaction + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("resending ACK"); + + dialog.resendAck(); + } catch (SipException ex) { + // What to do here ?? kill the dialog? + } + } + + this.semRelease(); + return; + } else if (TransactionState.CALLING == this.getState()) { + if (statusCode / 100 == 2) { + + // JvB: do this ~before~ calling the application, to avoid + // retransmissions + // of the INVITE after app sends ACK + disableRetransmissionTimer(); + disableTimeoutTimer(); + this.setState(TransactionState.TERMINATED); + + // 200 responses are always seen by TU. + if (respondTo != null) + respondTo.processResponse(transactionResponse, this, dialog); + else { + this.semRelease(); + } + + } else if (statusCode / 100 == 1) { + disableRetransmissionTimer(); + disableTimeoutTimer(); + this.setState(TransactionState.PROCEEDING); + + if (respondTo != null) + respondTo.processResponse(transactionResponse, this, dialog); + else { + this.semRelease(); + } + + } else if (300 <= statusCode && statusCode <= 699) { + // Send back an ACK request + + try { + sendMessage((SIPRequest) createErrorAck()); + + } catch (Exception ex) { + sipStack.getStackLogger().logError( + "Unexpected Exception sending ACK -- sending error AcK ", ex); + + } + + /* + * When in either the "Calling" or "Proceeding" states, reception of response with + * status code from 300-699 MUST cause the client transaction to transition to + * "Completed". The client transaction MUST pass the received response up to the + * TU, and the client transaction MUST generate an ACK request. + */ + + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, dialog); + } else { + this.semRelease(); + } + + if (this.getDialog() != null && ((SIPDialog)this.getDialog()).isBackToBackUserAgent()) { + ((SIPDialog) this.getDialog()).releaseAckSem(); + } + + if (!isReliable()) { + this.setState(TransactionState.COMPLETED); + enableTimeoutTimer(TIMER_D); + } else { + // Proceed immediately to the TERMINATED state. + this.setState(TransactionState.TERMINATED); + } + } + } else if (TransactionState.PROCEEDING == this.getState()) { + if (statusCode / 100 == 1) { + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, dialog); + } else { + this.semRelease(); + } + } else if (statusCode / 100 == 2) { + this.setState(TransactionState.TERMINATED); + if (respondTo != null) { + respondTo.processResponse(transactionResponse, this, dialog); + } else { + this.semRelease(); + } + + } else if (300 <= statusCode && statusCode <= 699) { + // Send back an ACK request + try { + sendMessage((SIPRequest) createErrorAck()); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + + if (this.getDialog() != null) { + ((SIPDialog) this.getDialog()).releaseAckSem(); + } + // JvB: update state before passing to app + if (!isReliable()) { + this.setState(TransactionState.COMPLETED); + this.enableTimeoutTimer(TIMER_D); + } else { + this.setState(TransactionState.TERMINATED); + } + + // Pass up to the TU for processing. + if (respondTo != null) + respondTo.processResponse(transactionResponse, this, dialog); + else { + this.semRelease(); + } + + // JvB: duplicate with line 874 + // if (!isReliable()) { + // enableTimeoutTimer(TIMER_D); + // } + } + } else if (TransactionState.COMPLETED == this.getState()) { + if (300 <= statusCode && statusCode <= 699) { + // Send back an ACK request + try { + sendMessage((SIPRequest) createErrorAck()); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } finally { + this.semRelease(); + } + } + + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.ClientTransaction#sendRequest() + */ + public void sendRequest() throws SipException { + SIPRequest sipRequest = this.getOriginalRequest(); + + if (this.getState() != null) + throw new SipException("Request already sent"); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("sendRequest() " + sipRequest); + } + + try { + sipRequest.checkHeaders(); + } catch (ParseException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("missing required header"); + throw new SipException(ex.getMessage()); + } + + if (getMethod().equals(Request.SUBSCRIBE) + && sipRequest.getHeader(ExpiresHeader.NAME) == null) { + /* + * If no "Expires" header is present in a SUBSCRIBE request, the implied default is + * defined by the event package being used. + * + */ + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning( + "Expires header missing in outgoing subscribe --" + + " Notifier will assume implied value on event package"); + } + try { + /* + * This check is removed because it causes problems for load balancers ( See issue + * 136) reported by Raghav Ramesh ( BT ) + * + */ + if (this.getOriginalRequest().getMethod().equals(Request.CANCEL) + && sipStack.isCancelClientTransactionChecked()) { + SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction( + this.getOriginalRequest(), false); + if (ct == null) { + /* + * If the original request has generated a final response, the CANCEL SHOULD + * NOT be sent, as it is an effective no-op, since CANCEL has no effect on + * requests that have already generated a final response. + */ + throw new SipException("Could not find original tx to cancel. RFC 3261 9.1"); + } else if (ct.getState() == null) { + throw new SipException( + "State is null no provisional response yet -- cannot cancel RFC 3261 9.1"); + } else if (!ct.getMethod().equals(Request.INVITE)) { + throw new SipException("Cannot cancel non-invite requests RFC 3261 9.1"); + } + } else + + if (this.getOriginalRequest().getMethod().equals(Request.BYE) + || this.getOriginalRequest().getMethod().equals(Request.NOTIFY)) { + SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest() + .getDialogId(false)); + // I want to behave like a user agent so send the BYE using the + // Dialog + if (this.getSipProvider().isAutomaticDialogSupportEnabled() && dialog != null) { + throw new SipException( + "Dialog is present and AutomaticDialogSupport is enabled for " + + " the provider -- Send the Request using the Dialog.sendRequest(transaction)"); + } + } + // Only map this after the fist request is sent out. + if (this.getMethod().equals(Request.INVITE)) { + SIPDialog dialog = this.getDefaultDialog(); + + if (dialog != null && dialog.isBackToBackUserAgent()) { + // Block sending re-INVITE till we see the ACK. + if ( ! dialog.takeAckSem() ) { + throw new SipException ("Failed to take ACK semaphore"); + } + + } + } + this.isMapped = true; + this.sendMessage(sipRequest); + + } catch (IOException ex) { + this.setState(TransactionState.TERMINATED); + throw new SipException("IO Error sending request", ex); + + } + + } + + /** + * Called by the transaction stack when a retransmission timer fires. + */ + protected void fireRetransmissionTimer() { + + try { + + // Resend the last request sent + if (this.getState() == null || !this.isMapped) + return; + + boolean inv = isInviteTransaction(); + TransactionState s = this.getState(); + + // JvB: INVITE CTs only retransmit in CALLING, non-INVITE in both TRYING and + // PROCEEDING + // Bug-fix for non-INVITE transactions not retransmitted when 1xx response received + if ((inv && TransactionState.CALLING == s) + || (!inv && (TransactionState.TRYING == s || TransactionState.PROCEEDING == s))) { + // If the retransmission filter is disabled then + // retransmission of the INVITE is the application + // responsibility. + + if (lastRequest != null) { + if (sipStack.generateTimeStampHeader + && lastRequest.getHeader(TimeStampHeader.NAME) != null) { + long milisec = System.currentTimeMillis(); + TimeStamp timeStamp = new TimeStamp(); + try { + timeStamp.setTimeStamp(milisec); + } catch (InvalidArgumentException ex) { + InternalErrorHandler.handleException(ex); + } + lastRequest.setHeader(timeStamp); + } + super.sendMessage(lastRequest); + if (this.notifyOnRetransmit) { + TimeoutEvent txTimeout = new TimeoutEvent(this.getSipProvider(), this, + Timeout.RETRANSMIT); + this.getSipProvider().handleEvent(txTimeout, this); + } + if (this.timeoutIfStillInCallingState + && this.getState() == TransactionState.CALLING) { + this.callingStateTimeoutCount--; + if (callingStateTimeoutCount == 0) { + TimeoutEvent timeoutEvent = new TimeoutEvent(this.getSipProvider(), + this, Timeout.RETRANSMIT); + this.getSipProvider().handleEvent(timeoutEvent, this); + this.timeoutIfStillInCallingState = false; + } + + } + } + + } + } catch (IOException e) { + this.raiseIOExceptionEvent(); + raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); + } + + } + + /** + * Called by the transaction stack when a timeout timer fires. + */ + protected void fireTimeoutTimer() { + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("fireTimeoutTimer " + this); + + SIPDialog dialog = (SIPDialog) this.getDialog(); + if (TransactionState.CALLING == this.getState() + || TransactionState.TRYING == this.getState() + || TransactionState.PROCEEDING == this.getState()) { + // Timeout occured. If this is asociated with a transaction + // creation then kill the dialog. + if (dialog != null + && (dialog.getState() == null || dialog.getState() == DialogState.EARLY)) { + if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this + .getOriginalRequest().getMethod())) { + // If this is a re-invite we do not delete the dialog even + // if the + // reinvite times out. Else + // terminate the enclosing dialog. + dialog.delete(); + } + } else if (dialog != null) { + // Guard against the case of BYE time out. + + if (getOriginalRequest().getMethod().equalsIgnoreCase(Request.BYE) + && dialog.isTerminatedOnBye()) { + // Terminate the associated dialog on BYE Timeout. + dialog.delete(); + } + } + } + if (TransactionState.COMPLETED != this.getState()) { + raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); + // Got a timeout error on a cancel. + if (this.getOriginalRequest().getMethod().equalsIgnoreCase(Request.CANCEL)) { + SIPClientTransaction inviteTx = (SIPClientTransaction) this.getOriginalRequest() + .getInviteTransaction(); + if (inviteTx != null + && ((inviteTx.getState() == TransactionState.CALLING || inviteTx + .getState() == TransactionState.PROCEEDING)) + && inviteTx.getDialog() != null) { + /* + * A proxy server should have started TIMER C and take care of the Termination + * using transaction.terminate() by itself (i.e. this is not the job of the + * stack at this point but we do it to be nice. + */ + inviteTx.setState(TransactionState.TERMINATED); + + } + } + + } else { + this.setState(TransactionState.TERMINATED); + } + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.ClientTransaction#createCancel() + */ + public Request createCancel() throws SipException { + SIPRequest originalRequest = this.getOriginalRequest(); + if (originalRequest == null) + throw new SipException("Bad state " + getState()); + if (!originalRequest.getMethod().equals(Request.INVITE)) + throw new SipException("Only INIVTE may be cancelled"); + + if (originalRequest.getMethod().equalsIgnoreCase(Request.ACK)) + throw new SipException("Cannot Cancel ACK!"); + else { + SIPRequest cancelRequest = originalRequest.createCancelRequest(); + cancelRequest.setInviteTransaction(this); + return cancelRequest; + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.ClientTransaction#createAck() + */ + public Request createAck() throws SipException { + SIPRequest originalRequest = this.getOriginalRequest(); + if (originalRequest == null) + throw new SipException("bad state " + getState()); + if (getMethod().equalsIgnoreCase(Request.ACK)) { + throw new SipException("Cannot ACK an ACK!"); + } else if (lastResponse == null) { + throw new SipException("bad Transaction state"); + } else if (lastResponse.getStatusCode() < 200) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse); + } + throw new SipException("Cannot ACK a provisional response!"); + } + SIPRequest ackRequest = originalRequest.createAckRequest((To) lastResponse.getTo()); + // Pull the record route headers from the last reesponse. + RecordRouteList recordRouteList = lastResponse.getRecordRouteHeaders(); + if (recordRouteList == null) { + // If the record route list is null then we can + // construct the ACK from the specified contact header. + // Note the 3xx check here because 3xx is a redirect. + // The contact header for the 3xx is the redirected + // location so we cannot use that to construct the + // request URI. + if (lastResponse.getContactHeaders() != null + && lastResponse.getStatusCode() / 100 != 3) { + Contact contact = (Contact) lastResponse.getContactHeaders().getFirst(); + javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI() + .clone(); + ackRequest.setRequestURI(uri); + } + return ackRequest; + } + + ackRequest.removeHeader(RouteHeader.NAME); + RouteList routeList = new RouteList(); + // start at the end of the list and walk backwards + ListIterator<RecordRoute> li = recordRouteList.listIterator(recordRouteList.size()); + while (li.hasPrevious()) { + RecordRoute rr = (RecordRoute) li.previous(); + + Route route = new Route(); + route.setAddress((AddressImpl) ((AddressImpl) rr.getAddress()).clone()); + route.setParameters((NameValueList) rr.getParameters().clone()); + routeList.add(route); + } + + Contact contact = null; + if (lastResponse.getContactHeaders() != null) { + contact = (Contact) lastResponse.getContactHeaders().getFirst(); + } + + if (!((SipURI) ((Route) routeList.getFirst()).getAddress().getURI()).hasLrParam()) { + + // Contact may not yet be there (bug reported by Andreas B). + + Route route = null; + if (contact != null) { + route = new Route(); + route.setAddress((AddressImpl) ((AddressImpl) (contact.getAddress())).clone()); + } + + Route firstRoute = (Route) routeList.getFirst(); + routeList.removeFirst(); + javax.sip.address.URI uri = firstRoute.getAddress().getURI(); + ackRequest.setRequestURI(uri); + + if (route != null) + routeList.add(route); + + ackRequest.addHeader(routeList); + } else { + if (contact != null) { + javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI() + .clone(); + ackRequest.setRequestURI(uri); + ackRequest.addHeader(routeList); + } + } + return ackRequest; + + } + + /* + * Creates an ACK for an error response, according to RFC3261 section 17.1.1.3 + * + * Note that this is different from an ACK for 2xx + */ + private final Request createErrorAck() throws SipException, ParseException { + SIPRequest originalRequest = this.getOriginalRequest(); + if (originalRequest == null) + throw new SipException("bad state " + getState()); + if (!getMethod().equals(Request.INVITE)) { + throw new SipException("Can only ACK an INVITE!"); + } else if (lastResponse == null) { + throw new SipException("bad Transaction state"); + } else if (lastResponse.getStatusCode() < 200) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse); + } + throw new SipException("Cannot ACK a provisional response!"); + } + return originalRequest.createErrorAck((To) lastResponse.getTo()); + } + + /** + * Set the port of the recipient. + */ + protected void setViaPort(int port) { + this.viaPort = port; + } + + /** + * Set the port of the recipient. + */ + protected void setViaHost(String host) { + this.viaHost = host; + } + + /** + * Get the port of the recipient. + */ + public int getViaPort() { + return this.viaPort; + } + + /** + * Get the host of the recipient. + */ + public String getViaHost() { + return this.viaHost; + } + + /** + * get the via header for an outgoing request. + */ + public Via getOutgoingViaHeader() { + return this.getMessageProcessor().getViaHeader(); + } + + /** + * This is called by the stack after a non-invite client transaction goes to completed state. + */ + public void clearState() { + // reduce the state to minimum + // This assumes that the application will not need + // to access the request once the transaction is + // completed. + // TODO -- revisit this - results in a null pointer + // occuring occasionally. + // this.lastRequest = null; + // this.originalRequest = null; + // this.lastResponse = null; + } + + /** + * Sets a timeout after which the connection is closed (provided the server does not use the + * connection for outgoing requests in this time period) and calls the superclass to set + * state. + */ + public void setState(TransactionState newState) { + // Set this timer for connection caching + // of incoming connections. + if (newState == TransactionState.TERMINATED && this.isReliable() + && (!getSIPStack().cacheClientConnections)) { + // Set a time after which the connection + // is closed. + this.collectionTime = TIMER_J; + + } + if (super.getState() != TransactionState.COMPLETED + && (newState == TransactionState.COMPLETED || newState == TransactionState.TERMINATED)) { + sipStack.decrementActiveClientTransactionCount(); + } + super.setState(newState); + } + + /** + * Start the timer task. + */ + protected void startTransactionTimer() { + if (this.transactionTimerStarted.compareAndSet(false, true)) { + TimerTask myTimer = new TransactionTimer(); + if ( sipStack.getTimer() != null ) { + sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL); + } + } + } + + /* + * Terminate a transaction. This marks the tx as terminated The tx scanner will run and remove + * the tx. (non-Javadoc) + * + * @see javax.sip.Transaction#terminate() + */ + public void terminate() throws ObjectInUseException { + this.setState(TransactionState.TERMINATED); + + } + + /** + * Check if the From tag of the response matches the from tag of the original message. A + * Response with a tag mismatch should be dropped if a Dialog has been created for the + * original request. + * + * @param sipResponse the response to check. + * @return true if the check passes. + */ + public boolean checkFromTag(SIPResponse sipResponse) { + String originalFromTag = ((SIPRequest) this.getRequest()).getFromTag(); + if (this.defaultDialog != null) { + if (originalFromTag == null ^ sipResponse.getFrom().getTag() == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); + return false; + } + if (originalFromTag != null + && !originalFromTag.equalsIgnoreCase(sipResponse.getFrom().getTag())) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); + return false; + } + } + return true; + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.ServerResponseInterface#processResponse(gov.nist.javax.sip.message.SIPResponse, + * gov.nist.javax.sip.stack.MessageChannel) + */ + public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) { + + // If a dialog has already been created for this response, + // pass it up. + SIPDialog dialog = null; + String method = sipResponse.getCSeq().getMethod(); + String dialogId = sipResponse.getDialogId(false); + if (method.equals(Request.CANCEL) && lastRequest != null) { + // JvB for CANCEL: use invite CT in CANCEL request to get dialog + // (instead of stripping tag) + SIPClientTransaction ict = (SIPClientTransaction) lastRequest.getInviteTransaction(); + if (ict != null) { + dialog = ict.defaultDialog; + } + } else { + dialog = this.getDialog(dialogId); + } + + // JvB: Check all conditions required for creating a new Dialog + if (dialog == null) { + int code = sipResponse.getStatusCode(); + if ((code > 100 && code < 300) + /* skip 100 (may have a to tag */ + && (sipResponse.getToTag() != null || sipStack.isRfc2543Supported()) + && sipStack.isDialogCreated(method)) { + + /* + * Dialog cannot be found for the response. This must be a forked response. no + * dialog assigned to this response but a default dialog has been assigned. Note + * that if automatic dialog support is configured then a default dialog is always + * created. + */ + + synchronized (this) { + /* + * We need synchronization here because two responses may compete for the + * default dialog simultaneously + */ + if (defaultDialog != null) { + if (sipResponse.getFromTag() != null) { + SIPResponse dialogResponse = defaultDialog.getLastResponse(); + String defaultDialogId = defaultDialog.getDialogId(); + if (dialogResponse == null + || (method.equals(Request.SUBSCRIBE) + && dialogResponse.getCSeq().getMethod().equals( + Request.NOTIFY) && defaultDialogId + .equals(dialogId))) { + // The default dialog has not been claimed yet. + defaultDialog.setLastResponse(this, sipResponse); + dialog = defaultDialog; + } else { + /* + * check if we have created one previously (happens in the case of + * REINVITE processing. JvB: should not happen, this.defaultDialog + * should then get set in Dialog#sendRequest line 1662 + */ + + dialog = sipStack.getDialog(dialogId); + if (dialog == null) { + if (defaultDialog.isAssigned()) { + /* + * Nop we dont have one. so go ahead and allocate a new + * one. + */ + dialog = sipStack.createDialog(this, sipResponse); + + } + } + + } + if ( dialog != null ) { + this.setDialog(dialog, dialog.getDialogId()); + } else { + sipStack.getStackLogger().logError("dialog is unexpectedly null",new NullPointerException()); + } + } else { + throw new RuntimeException("Response without from-tag"); + } + } else { + // Need to create a new Dialog, this becomes default + // JvB: not sure if this ever gets executed + if (sipStack.isAutomaticDialogSupportEnabled) { + dialog = sipStack.createDialog(this, sipResponse); + this.setDialog(dialog, dialog.getDialogId()); + } + } + } // synchronized + } else { + dialog = defaultDialog; + } + } else { + dialog.setLastResponse(this, sipResponse); + } + this.processResponse(sipResponse, incomingChannel, dialog); + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.SIPTransaction#getDialog() + */ + public Dialog getDialog() { + // This is for backwards compatibility. + Dialog retval = null; + if (this.lastResponse != null && this.lastResponse.getFromTag() != null + && this.lastResponse.getToTag() != null + && this.lastResponse.getStatusCode() != 100) { + String dialogId = this.lastResponse.getDialogId(false); + retval = (Dialog) getDialog(dialogId); + } + + if (retval == null) { + retval = (Dialog) this.defaultDialog; + + } + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + " sipDialogs = " + sipDialogs + " default dialog " + this.defaultDialog + + " retval " + retval); + } + return retval; + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, + * gov.nist.javax.sip.message.SIPMessage) + */ + public SIPDialog getDialog(String dialogId) { + SIPDialog retval = (SIPDialog) this.sipDialogs.get(dialogId); + return retval; + + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, + * gov.nist.javax.sip.message.SIPMessage) + */ + public void setDialog(SIPDialog sipDialog, String dialogId) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "setDialog: " + dialogId + "sipDialog = " + sipDialog); + + if (sipDialog == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("NULL DIALOG!!"); + throw new NullPointerException("bad dialog null"); + } + if (this.defaultDialog == null) { + this.defaultDialog = sipDialog; + if ( this.getMethod().equals(Request.INVITE) && this.getSIPStack().maxForkTime != 0) { + this.getSIPStack().addForkedClientTransaction(this); + } + } + if (dialogId != null && sipDialog.getDialogId() != null) { + this.sipDialogs.put(dialogId, sipDialog); + + } + + } + + public SIPDialog getDefaultDialog() { + return this.defaultDialog; + } + + /** + * Set the next hop ( if it has already been computed). + * + * @param hop -- the hop that has been previously computed. + */ + public void setNextHop(Hop hop) { + this.nextHop = hop; + + } + + /** + * Reeturn the previously computed next hop (avoid computing it twice). + * + * @return -- next hop previously computed. + */ + public Hop getNextHop() { + return nextHop; + } + + /** + * Set this flag if you want your Listener to get Timeout.RETRANSMIT notifications each time a + * retransmission occurs. + * + * @param notifyOnRetransmit the notifyOnRetransmit to set + */ + public void setNotifyOnRetransmit(boolean notifyOnRetransmit) { + this.notifyOnRetransmit = notifyOnRetransmit; + } + + /** + * @return the notifyOnRetransmit + */ + public boolean isNotifyOnRetransmit() { + return notifyOnRetransmit; + } + + public void alertIfStillInCallingStateBy(int count) { + this.timeoutIfStillInCallingState = true; + this.callingStateTimeoutCount = count; + } + + + +} diff --git a/java/gov/nist/javax/sip/stack/SIPDialog.java b/java/gov/nist/javax/sip/stack/SIPDialog.java new file mode 100644 index 0000000..807fa1a --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPDialog.java @@ -0,0 +1,3343 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/**************************************************************************/ +/* Product of NIST Advanced Networking Technologies Division */ +/**************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.core.NameValueList; +import gov.nist.javax.sip.DialogExt; +import gov.nist.javax.sip.ListeningPointImpl; +import gov.nist.javax.sip.SipListenerExt; +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.Utils; +import gov.nist.javax.sip.address.AddressImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.header.Authorization; +import gov.nist.javax.sip.header.CSeq; +import gov.nist.javax.sip.header.Contact; +import gov.nist.javax.sip.header.ContactList; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.MaxForwards; +import gov.nist.javax.sip.header.RAck; +import gov.nist.javax.sip.header.RSeq; +import gov.nist.javax.sip.header.Reason; +import gov.nist.javax.sip.header.RecordRoute; +import gov.nist.javax.sip.header.RecordRouteList; +import gov.nist.javax.sip.header.Require; +import gov.nist.javax.sip.header.Route; +import gov.nist.javax.sip.header.RouteList; +import gov.nist.javax.sip.header.SIPHeader; +import gov.nist.javax.sip.header.TimeStamp; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.message.MessageFactoryImpl; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.net.InetAddress; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.sip.ClientTransaction; +import javax.sip.DialogDoesNotExistException; +import javax.sip.DialogState; +import javax.sip.IOExceptionEvent; +import javax.sip.InvalidArgumentException; +import javax.sip.ListeningPoint; +import javax.sip.ObjectInUseException; +import javax.sip.SipException; +import javax.sip.Transaction; +import javax.sip.TransactionDoesNotExistException; +import javax.sip.TransactionState; +import javax.sip.address.Address; +import javax.sip.address.Hop; +import javax.sip.address.SipURI; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContactHeader; +import javax.sip.header.EventHeader; +import javax.sip.header.OptionTag; +import javax.sip.header.RAckHeader; +import javax.sip.header.RSeqHeader; +import javax.sip.header.ReasonHeader; +import javax.sip.header.RequireHeader; +import javax.sip.header.RouteHeader; +import javax.sip.header.SupportedHeader; +import javax.sip.header.TimeStampHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Acknowledgements: + * + * Bugs in this class were reported by Antonis Karydas, Brad Templeton, Jeff Adams, Alex Rootham , + * Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela + * reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and + * the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when + * 180 contained a To tag. + * + */ + +/** + * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For + * INVITE transactions, a Dialog is created when a success message is received (i.e. a response + * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a + * dialog identifier that can be used to retrieve this structure from the SipStack. + * + * @version 1.2 $Revision: 1.159 $ $Date: 2010/01/08 15:14:12 $ + * + * @author M. Ranganathan + * + * + */ + +public class SIPDialog implements javax.sip.Dialog, DialogExt { + + private static final long serialVersionUID = -1429794423085204069L; + + private transient boolean dialogTerminatedEventDelivered; // prevent duplicate + + private transient String stackTrace; // for semaphore debugging. + + private String method; + + // delivery of the event + private transient boolean isAssigned; + + private boolean reInviteFlag; + + private transient Object applicationData; // Opaque pointer to application data. + + private transient SIPRequest originalRequest; + + // Last response (JvB: either sent or received). + private SIPResponse lastResponse; + + // Should be transient, in case the dialog is serialized it will be null + // so when a subsequent request will be sent it will be set and a new message channel can be + // created + private transient SIPTransaction firstTransaction; + + private transient SIPTransaction lastTransaction; + + private String dialogId; + + private transient String earlyDialogId; + + private long localSequenceNumber; + + private long remoteSequenceNumber; + + protected String myTag; + + protected String hisTag; + + private RouteList routeList; + + private transient SIPTransactionStack sipStack; + + private int dialogState; + + protected transient boolean ackSeen; + + private transient SIPRequest lastAckSent; + + private SIPRequest lastAckReceived; + + // could be set on recovery by examining the method looks like a duplicate of ackSeen + protected transient boolean ackProcessed; + + protected transient DialogTimerTask timerTask; + + protected transient Long nextSeqno; + + private transient int retransmissionTicksLeft; + + private transient int prevRetransmissionTicks; + + private long originalLocalSequenceNumber; + + // This is for debugging only. + private transient int ackLine; + + // Audit tag used by the SIP Stack audit + public transient long auditTag = 0; + + // The following fields are extracted from the request that created the + // Dialog. + + protected javax.sip.address.Address localParty; + + protected javax.sip.address.Address remoteParty; + + protected CallIdHeader callIdHeader; + + public final static int NULL_STATE = -1; + + public final static int EARLY_STATE = DialogState._EARLY; + + public final static int CONFIRMED_STATE = DialogState._CONFIRMED; + + public final static int TERMINATED_STATE = DialogState._TERMINATED; + + // the amount of time to keep this dialog around before the stack GC's it + + private static final int DIALOG_LINGER_TIME = 8; + + private boolean serverTransactionFlag; + + private transient SipProviderImpl sipProvider; + + private boolean terminateOnBye; + + private transient boolean byeSent; // Flag set when BYE is sent, to disallow new + + // requests + + private Address remoteTarget; + + private EventHeader eventHeader; // for Subscribe notify + + // Stores the last OK for the INVITE + // Used in createAck. + private transient long lastInviteOkReceived; + + private transient Semaphore ackSem = new Semaphore(1); + + private transient int reInviteWaitTime = 100; + + private transient DialogDeleteTask dialogDeleteTask; + + private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask; + + private transient boolean isAcknowledged; + + private transient long highestSequenceNumberAcknowledged = -1; + + private boolean isBackToBackUserAgent; + + private boolean sequenceNumberValidation = true; + + // List of event listeners for this dialog + private transient Set<SIPDialogEventListener> eventListeners; + // added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248 + private Semaphore timerTaskLock = new Semaphore(1); + + // We store here the useful data from the first transaction without having to + // keep the whole transaction object for the duration of the dialog. It also + // contains the non-transient information used in the replication of dialogs. + protected boolean firstTransactionSecure; + protected boolean firstTransactionSeen; + protected String firstTransactionMethod; + protected String firstTransactionId; + protected boolean firstTransactionIsServerTransaction; + protected int firstTransactionPort = 5060; + protected Contact contactHeader; + + // ////////////////////////////////////////////////////// + // Inner classes + // ////////////////////////////////////////////////////// + + /** + * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This + * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives + * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed + * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening + * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this + * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before + * sending the next re-INVITE. + */ + public class ReInviteSender implements Runnable, Serializable { + private static final long serialVersionUID = 1019346148741070635L; + ClientTransaction ctx; + + public void terminate() { + try { + ctx.terminate(); + Thread.currentThread().interrupt(); + } catch (ObjectInUseException e) { + sipStack.getStackLogger().logError("unexpected error", e); + } + } + + public ReInviteSender(ClientTransaction ctx) { + this.ctx = ctx; + } + + public void run() { + try { + long timeToWait = 0; + long startTime = System.currentTimeMillis(); + + if (!SIPDialog.this.takeAckSem()) { + /* + * Could not send re-INVITE fire a timeout on the INVITE. + */ + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError( + "Could not send re-INVITE time out ClientTransaction"); + ((SIPClientTransaction) ctx).fireTimeoutTimer(); + /* + * Send BYE to the Dialog. + */ + if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { + raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT); + } else { + Request byeRequest = SIPDialog.this.createRequest(Request.BYE); + if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { + byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + } + ReasonHeader reasonHeader = new Reason(); + reasonHeader.setCause(1024); + reasonHeader.setText("Timed out waiting to re-INVITE"); + byeRequest.addHeader(reasonHeader); + ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); + SIPDialog.this.sendRequest(byeCtx); + return; + } + } + if (getState() != DialogState.TERMINATED) { + + timeToWait = System.currentTimeMillis() - startTime; + } + + /* + * If we had to wait for ACK then wait for the ACK to actually get to the other + * side. Wait for any ACK retransmissions to finish. Then send out the request. + * This is a hack in support of some UA that want re-INVITEs to be spaced out in + * time ( else they return a 400 error code ). + */ + try { + if (timeToWait != 0) { + Thread.sleep(SIPDialog.this.reInviteWaitTime); + } + } catch (InterruptedException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Interrupted sleep"); + return; + } + if (SIPDialog.this.getState() != DialogState.TERMINATED) { + SIPDialog.this.sendRequest(ctx, true); + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("re-INVITE successfully sent"); + } catch (Exception ex) { + sipStack.getStackLogger().logError("Error sending re-INVITE", ex); + } finally { + this.ctx = null; + } + } + } + + class LingerTimer extends SIPStackTimerTask implements Serializable { + + public LingerTimer() { + + } + + protected void runTask() { + SIPDialog dialog = SIPDialog.this; + if(eventListeners != null) { + eventListeners.clear(); + } + timerTaskLock = null; + sipStack.removeDialog(dialog); + } + + } + + class DialogTimerTask extends SIPStackTimerTask implements Serializable { + int nRetransmissions; + + SIPServerTransaction transaction; + + public DialogTimerTask(SIPServerTransaction transaction) { + this.transaction = transaction; + this.nRetransmissions = 0; + } + + protected void runTask() { + // If I ACK has not been seen on Dialog, + // resend last response. + SIPDialog dialog = SIPDialog.this; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Running dialog timer"); + nRetransmissions++; + SIPServerTransaction transaction = this.transaction; + /* + * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport + * with an interval that starts at T1 seconds and doubles for each retransmission + * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1 + * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD + * be terminated. + */ + + if (nRetransmissions > 64 * SIPTransaction.T1) { + if (sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { + raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT); + } else { + dialog.delete(); + } + if (transaction != null + && transaction.getState() != javax.sip.TransactionState.TERMINATED) { + transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); + } + } else if ((!dialog.ackSeen) && (transaction != null)) { + // Retransmit to 200 until ack receivedialog. + SIPResponse response = transaction.getLastResponse(); + if (response.getStatusCode() == 200) { + try { + + // resend the last response. + if (dialog.toRetransmitFinalResponse(transaction.T2)) + transaction.sendMessage(response); + + } catch (IOException ex) { + + raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(), + transaction.getPeerProtocol()); + + } finally { + // Need to fire the timer so + // transaction will eventually + // time out whether or not + // the IOException occurs + // Note that this firing also + // drives Listener timeout. + SIPTransactionStack stack = dialog.sipStack; + if (stack.isLoggingEnabled()) { + stack.getStackLogger().logDebug("resend 200 response from " + dialog); + } + transaction.fireTimer(); + } + } + } + + // Stop running this timer if the dialog is in the + // confirmed state or ack seen if retransmit filter on. + if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) { + this.transaction = null; + this.cancel(); + + } + + } + + } + + /** + * This timer task is used to garbage collect the dialog after some time. + * + */ + + class DialogDeleteTask extends SIPStackTimerTask implements Serializable { + + protected void runTask() { + delete(); + } + + } + + /** + * This timer task is used to garbage collect the dialog after some time. + * + */ + + class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable { + private long seqno; + + public DialogDeleteIfNoAckSentTask(long seqno) { + this.seqno = seqno; + } + + protected void runTask() { + if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) { + /* + * Did not send ACK so we need to delete the dialog. + * B2BUA NOTE: we may want to send BYE to the Dialog at this + * point. Do we want to make this behavior tailorable? + */ + dialogDeleteIfNoAckSentTask = null; + if ( !SIPDialog.this.isBackToBackUserAgent) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("ACK Was not sent. killing dialog"); + if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ + raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); + } else { + delete(); + } + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("ACK Was not sent. Sending BYE"); + if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ + raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); + } else { + + /* + * Send BYE to the Dialog. + * This will be removed for the next spec revision. + */ + try { + Request byeRequest = SIPDialog.this.createRequest(Request.BYE); + if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { + byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + } + ReasonHeader reasonHeader = new Reason(); + reasonHeader.setProtocol("SIP"); + reasonHeader.setCause(1025); + reasonHeader.setText("Timed out waiting to send ACK"); + byeRequest.addHeader(reasonHeader); + ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); + SIPDialog.this.sendRequest(byeCtx); + return; + } catch (Exception ex) { + SIPDialog.this.delete(); + } + } + } + } + } + + } + + // /////////////////////////////////////////////////////////// + // Constructors. + // /////////////////////////////////////////////////////////// + /** + * Protected Dialog constructor. + */ + private SIPDialog(SipProviderImpl provider) { + this.terminateOnBye = true; + this.routeList = new RouteList(); + this.dialogState = NULL_STATE; // not yet initialized. + localSequenceNumber = 0; + remoteSequenceNumber = -1; + this.sipProvider = provider; + eventListeners = new CopyOnWriteArraySet<SIPDialogEventListener>(); + } + + private void recordStackTrace() { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + new Exception().printStackTrace(writer); + this.stackTrace = stringWriter.getBuffer().toString(); + } + + /** + * Constructor given the first transaction. + * + * @param transaction is the first transaction. + */ + public SIPDialog(SIPTransaction transaction) { + this(transaction.getSipProvider()); + + SIPRequest sipRequest = (SIPRequest) transaction.getRequest(); + this.callIdHeader = sipRequest.getCallId(); + this.earlyDialogId = sipRequest.getDialogId(false); + if (transaction == null) + throw new NullPointerException("Null tx"); + this.sipStack = transaction.sipStack; + + // this.defaultRouter = new DefaultRouter((SipStack) sipStack, + // sipStack.outboundProxy); + + this.sipProvider = (SipProviderImpl) transaction.getSipProvider(); + if (sipProvider == null) + throw new NullPointerException("Null Provider!"); + this.addTransaction(transaction); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Creating a dialog : " + this); + sipStack.getStackLogger().logDebug( + "provider port = " + this.sipProvider.getListeningPoint().getPort()); + sipStack.getStackLogger().logStackTrace(); + } + this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; + addEventListener(sipStack); + } + + /** + * Constructor given a transaction and a response. + * + * @param transaction -- the transaction ( client/server) + * @param sipResponse -- response with the appropriate tags. + */ + public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) { + this(transaction); + if (sipResponse == null) + throw new NullPointerException("Null SipResponse"); + this.setLastResponse(transaction, sipResponse); + this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; + } + + /** + * create a sip dialog with a response ( no tx) + */ + public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) { + this(sipProvider); + this.sipStack = (SIPTransactionStack) sipProvider.getSipStack(); + this.setLastResponse(null, sipResponse); + this.localSequenceNumber = sipResponse.getCSeq().getSeqNumber(); + this.originalLocalSequenceNumber = localSequenceNumber; + this.myTag = sipResponse.getFrom().getTag(); + this.hisTag = sipResponse.getTo().getTag(); + this.localParty = sipResponse.getFrom().getAddress(); + this.remoteParty = sipResponse.getTo().getAddress(); + this.method = sipResponse.getCSeq().getMethod(); + this.callIdHeader = sipResponse.getCallId(); + this.serverTransactionFlag = false; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Creating a dialog : " + this); + sipStack.getStackLogger().logStackTrace(); + } + this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; + addEventListener(sipStack); + } + + // /////////////////////////////////////////////////////////// + // Private methods + // /////////////////////////////////////////////////////////// + /** + * A debugging print routine. + */ + private void printRouteList() { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("this : " + this); + sipStack.getStackLogger().logDebug("printRouteList : " + this.routeList.encode()); + } + } + + /** + * Return true if this is a client dialog. + * + * @return true if the transaction that created this dialog is a client transaction and false + * otherwise. + */ + private boolean isClientDialog() { + SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction(); + return transaction instanceof SIPClientTransaction; + } + + /** + * Raise an io exception for asyncrhonous retransmission of responses + * + * @param host -- host to where the io was headed + * @param port -- remote port + * @param protocol -- protocol (udp/tcp/tls) + */ + private void raiseIOException(String host, int port, String protocol) { + // Error occured in retransmitting response. + // Deliver the error event to the listener + // Kill the dialog. + + IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol); + sipProvider.handleEvent(ioError, null); + + setState(SIPDialog.TERMINATED_STATE); + } + + /** + * Raise a dialog timeout if an ACK has not been sent or received + * + * @param dialogTimeoutError + */ + private void raiseErrorEvent(int dialogTimeoutError) { + // Error event to send to all listeners + SIPDialogErrorEvent newErrorEvent; + // Iterator through the list of listeners + Iterator<SIPDialogEventListener> listenerIterator; + // Next listener in the list + SIPDialogEventListener nextListener; + + // Create the error event + newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError); + + // Loop through all listeners of this transaction + synchronized (eventListeners) { + listenerIterator = eventListeners.iterator(); + while (listenerIterator.hasNext()) { + // Send the event to the next listener + nextListener = (SIPDialogEventListener) listenerIterator.next(); + nextListener.dialogErrorEvent(newErrorEvent); + } + } + // Clear the event listeners after propagating the error. + eventListeners.clear(); + // Errors always terminate a dialog except if a timeout has occured because an ACK was not sent or received, then it is the responsibility of the app to terminate + // the dialog, either by sending a BYE or by calling delete() on the dialog + if(dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT && + dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT && + dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) { + delete(); + } + // we stop the timer in any case + stopTimer(); + } + + /** + * Set the remote party for this Dialog. + * + * @param sipMessage -- SIP Message to extract the relevant information from. + */ + private void setRemoteParty(SIPMessage sipMessage) { + + if (!isServer()) { + + this.remoteParty = sipMessage.getTo().getAddress(); + } else { + this.remoteParty = sipMessage.getFrom().getAddress(); + + } + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("settingRemoteParty " + this.remoteParty); + } + } + + /** + * Add a route list extracted from a record route list. If this is a server dialog then we + * assume that the record are added to the route list IN order. If this is a client dialog + * then we assume that the record route headers give us the route list to add in reverse + * order. + * + * @param recordRouteList -- the record route list from the incoming message. + */ + + private void addRoute(RecordRouteList recordRouteList) { + try { + if (this.isClientDialog()) { + // This is a client dialog so we extract the record + // route from the response and reverse its order to + // careate a route list. + this.routeList = new RouteList(); + // start at the end of the list and walk backwards + + ListIterator li = recordRouteList.listIterator(recordRouteList.size()); + boolean addRoute = true; + while (li.hasPrevious()) { + RecordRoute rr = (RecordRoute) li.previous(); + + if (addRoute) { + Route route = new Route(); + AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) + .clone()); + + route.setAddress(address); + route.setParameters((NameValueList) rr.getParameters().clone()); + + this.routeList.add(route); + } + } + } else { + // This is a server dialog. The top most record route + // header is the one that is closest to us. We extract the + // route list in the same order as the addresses in the + // incoming request. + this.routeList = new RouteList(); + ListIterator li = recordRouteList.listIterator(); + boolean addRoute = true; + while (li.hasNext()) { + RecordRoute rr = (RecordRoute) li.next(); + + if (addRoute) { + Route route = new Route(); + AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) + .clone()); + route.setAddress(address); + route.setParameters((NameValueList) rr.getParameters().clone()); + routeList.add(route); + } + } + } + } finally { + if (sipStack.getStackLogger().isLoggingEnabled()) { + Iterator it = routeList.iterator(); + + while (it.hasNext()) { + SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI()); + if (!sipUri.hasLrParam()) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logWarning( + "NON LR route in Route set detected for dialog : " + this); + sipStack.getStackLogger().logStackTrace(); + } + } + } + } + } + } + + /** + * Add a route list extacted from the contact list of the incoming message. + * + * @param contactList -- contact list extracted from the incoming message. + * + */ + + void setRemoteTarget(ContactHeader contact) { + this.remoteTarget = contact.getAddress(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Dialog.setRemoteTarget: " + this.remoteTarget); + sipStack.getStackLogger().logStackTrace(); + } + + } + + /** + * Extract the route information from this SIP Message and add the relevant information to the + * route set. + * + * @param sipMessage is the SIP message for which we want to add the route. + */ + private synchronized void addRoute(SIPResponse sipResponse) { + + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "setContact: dialogState: " + this + "state = " + this.getState()); + } + if (sipResponse.getStatusCode() == 100) { + // Do nothing for trying messages. + return; + } else if (this.dialogState == TERMINATED_STATE) { + // Do nothing if the dialog state is terminated. + return; + } else if (this.dialogState == CONFIRMED_STATE) { + // cannot add route list after the dialog is initialized. + // Remote target is updated on RE-INVITE but not + // the route list. + if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) { + ContactList contactList = sipResponse.getContactHeaders(); + if (contactList != null + && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) { + this.setRemoteTarget((ContactHeader) contactList.getFirst()); + } + } + return; + } + + // Update route list on response if I am a client dialog. + if (!isServer()) { + + // only update the route set if the dialog is not in the confirmed state. + if (this.getState() != DialogState.CONFIRMED + && this.getState() != DialogState.TERMINATED) { + RecordRouteList rrlist = sipResponse.getRecordRouteHeaders(); + // Add the route set from the incoming response in reverse + // order for record route headers. + if (rrlist != null) { + this.addRoute(rrlist); + } else { + // Set the rotue list to the last seen route list. + this.routeList = new RouteList(); + } + } + + ContactList contactList = sipResponse.getContactHeaders(); + if (contactList != null) { + this.setRemoteTarget((ContactHeader) contactList.getFirst()); + } + } + + } finally { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logStackTrace(); + } + } + } + + /** + * Get a cloned copy of route list for the Dialog. + * + * @return -- a cloned copy of the dialog route list. + */ + private synchronized RouteList getRouteList() { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("getRouteList " + this); + // Find the top via in the route list. + ListIterator li; + RouteList retval = new RouteList(); + + retval = new RouteList(); + if (this.routeList != null) { + li = routeList.listIterator(); + while (li.hasNext()) { + Route route = (Route) li.next(); + retval.add((Route) route.clone()); + } + } + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("----- "); + sipStack.getStackLogger().logDebug("getRouteList for " + this); + if (retval != null) + sipStack.getStackLogger().logDebug("RouteList = " + retval.encode()); + if (routeList != null) + sipStack.getStackLogger().logDebug("myRouteList = " + routeList.encode()); + sipStack.getStackLogger().logDebug("----- "); + } + return retval; + } + + void setRouteList(RouteList routeList) { + this.routeList = routeList; + } + + /** + * Sends ACK Request to the remote party of this Dialogue. + * + * + * @param request the new ACK Request message to send. + * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise, + * no exception is propagated. + * @param releaseAckSem - release ack semaphore. + * @throws SipException if implementation cannot send the ACK Request for any other reason + * + */ + private void sendAck(Request request, boolean throwIOExceptionAsSipException) + throws SipException { + SIPRequest ackRequest = (SIPRequest) request; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("sendAck" + this); + + if (!ackRequest.getMethod().equals(Request.ACK)) + throw new SipException("Bad request method -- should be ACK"); + if (this.getState() == null || this.getState().getValue() == EARLY_STATE) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError( + "Bad Dialog State for " + this + " dialogID = " + this.getDialogId()); + } + throw new SipException("Bad dialog state " + this.getState()); + } + + if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("CallID " + this.getCallId()); + sipStack.getStackLogger().logError( + "RequestCallID = " + ackRequest.getCallId().getCallId()); + sipStack.getStackLogger().logError("dialog = " + this); + } + throw new SipException("Bad call ID in request"); + } + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "setting from tag For outgoing ACK= " + this.getLocalTag()); + sipStack.getStackLogger().logDebug( + "setting To tag for outgoing ACK = " + this.getRemoteTag()); + sipStack.getStackLogger().logDebug("ack = " + ackRequest); + } + if (this.getLocalTag() != null) + ackRequest.getFrom().setTag(this.getLocalTag()); + if (this.getRemoteTag() != null) + ackRequest.getTo().setTag(this.getRemoteTag()); + } catch (ParseException ex) { + throw new SipException(ex.getMessage()); + } + + Hop hop = sipStack.getNextHop(ackRequest); + // Hop hop = defaultRouter.getNextHop(ackRequest); + if (hop == null) + throw new SipException("No route!"); + try { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("hop = " + hop); + ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop + .getTransport()); + if (lp == null) + throw new SipException("No listening point for this provider registered at " + + hop); + InetAddress inetAddress = InetAddress.getByName(hop.getHost()); + MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel( + inetAddress, hop.getPort()); + boolean releaseAckSem = false; + long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber(); + if (!this.isAckSent(cseqNo)) { + releaseAckSem = true; + } + + this.setLastAckSent(ackRequest); + messageChannel.sendMessage(ackRequest); + // Sent atleast one ACK. + this.isAcknowledged = true; + this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged, + ((SIPRequest)ackRequest).getCSeq().getSeqNumber()); + if (releaseAckSem && this.isBackToBackUserAgent) { + this.releaseAckSem(); + } else { + if ( sipStack.isLoggingEnabled() ) { + sipStack.getStackLogger().logDebug("Not releasing ack sem for " + this + " isAckSent " + releaseAckSem ); + } + } + } catch (IOException ex) { + if (throwIOExceptionAsSipException) + throw new SipException("Could not send ack", ex); + this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport()); + } catch (SipException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + throw ex; + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + throw new SipException("Could not create message channel", ex); + } + if (this.dialogDeleteTask != null) { + this.dialogDeleteTask.cancel(); + this.dialogDeleteTask = null; + } + this.ackSeen = true; + + } + + // ///////////////////////////////////////////////////////////// + // Package local methods + // ///////////////////////////////////////////////////////////// + + /** + * Set the stack address. Prevent us from routing messages to ourselves. + * + * @param sipStack the address of the SIP stack. + * + */ + void setStack(SIPTransactionStack sipStack) { + this.sipStack = sipStack; + + } + + /** + * Get the stack . + * + * @return sipStack the SIP stack of the dialog. + * + */ + SIPTransactionStack getStack() { + return sipStack; + } + + /** + * Return True if this dialog is terminated on BYE. + * + */ + boolean isTerminatedOnBye() { + + return this.terminateOnBye; + } + + /** + * Mark that the dialog has seen an ACK. + */ + void ackReceived(SIPRequest sipRequest) { + + // Suppress retransmission of the final response + if (this.ackSeen) + return; + SIPServerTransaction tr = this.getInviteTransaction(); + if (tr != null) { + if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) { + acquireTimerTaskSem(); + try { + if (this.timerTask != null) { + this.timerTask.cancel(); + this.timerTask = null; + } + } finally { + releaseTimerTaskSem(); + } + this.ackSeen = true; + if (this.dialogDeleteTask != null) { + this.dialogDeleteTask.cancel(); + this.dialogDeleteTask = null; + } + this.setLastAckReceived(sipRequest); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "ackReceived for " + ((SIPTransaction) tr).getMethod()); + this.ackLine = sipStack.getStackLogger().getLineCount(); + this.printDebugInfo(); + } + if (this.isBackToBackUserAgent) { + this.releaseAckSem(); + } + this.setState(CONFIRMED_STATE); + } + } + } + + /** + * Return true if a terminated event was delivered to the application as a result of the + * dialog termination. + * + */ + synchronized boolean testAndSetIsDialogTerminatedEventDelivered() { + boolean retval = this.dialogTerminatedEventDelivered; + this.dialogTerminatedEventDelivered = true; + return retval; + } + + // ///////////////////////////////////////////////////////// + // Public methods + // ///////////////////////////////////////////////////////// + + /** + * Adds a new event listener to this dialog. + * + * @param newListener + * Listener to add. + */ + public void addEventListener(SIPDialogEventListener newListener) { + eventListeners.add(newListener); + } + + /** + * Removed an event listener from this dialog. + * + * @param oldListener + * Listener to remove. + */ + public void removeEventListener(SIPDialogEventListener oldListener) { + eventListeners.remove(oldListener); + } + + /* + * @see javax.sip.Dialog#setApplicationData() + */ + public void setApplicationData(Object applicationData) { + this.applicationData = applicationData; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getApplicationData() + */ + public Object getApplicationData() { + return this.applicationData; + } + + /** + * Updates the next consumable seqno. + * + */ + public synchronized void requestConsumed() { + this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1); + + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug( + "Request Consumed -- next consumable Request Seqno = " + this.nextSeqno); + } + + } + + /** + * Return true if this request can be consumed by the dialog. + * + * @param dialogRequest is the request to check with the dialog. + * @return true if the dialogRequest sequence number matches the next consumable seqno. + */ + public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) { + // have not yet set remote seqno - this is a fresh + if (dialogRequest.getMethod().equals(Request.ACK)) + throw new RuntimeException("Illegal method"); + + // For loose validation this function is delegated to the application + if (!this.isSequnceNumberValidation()) { + return true; + } + + // JvB: Acceptable iff remoteCSeq < cseq. remoteCSeq==-1 + // when not defined yet, so that works too + return remoteSequenceNumber < dialogRequest.getCSeq().getSeqNumber(); + } + + /** + * This method is called when a forked dialog is created from the client side. It starts a + * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled + * (i.e. garbage collected ). + * + */ + public void doDeferredDelete() { + if (sipStack.getTimer() == null) + this.setState(TERMINATED_STATE); + else { + this.dialogDeleteTask = new DialogDeleteTask(); + // Delete the transaction after the max ack timeout. + sipStack.getTimer().schedule(this.dialogDeleteTask, + SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL); + } + + } + + /** + * Set the state for this dialog. + * + * @param state is the state to set for the dialog. + */ + + public void setState(int state) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Setting dialog state for " + this + "newState = " + state); + sipStack.getStackLogger().logStackTrace(); + if (state != NULL_STATE && state != this.dialogState) + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + this + " old dialog state is " + this.getState()); + sipStack.getStackLogger().logDebug( + this + " New dialog state is " + DialogState.getObject(state)); + } + + } + this.dialogState = state; + // Dialog is in terminated state set it up for GC. + if (state == TERMINATED_STATE) { + if (sipStack.getTimer() != null) { // may be null after shutdown + sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000); + } + this.stopTimer(); + + } + } + + /** + * Debugging print for the dialog. + */ + public void printDebugInfo() { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("isServer = " + isServer()); + sipStack.getStackLogger().logDebug("localTag = " + getLocalTag()); + sipStack.getStackLogger().logDebug("remoteTag = " + getRemoteTag()); + sipStack.getStackLogger().logDebug("localSequenceNumer = " + getLocalSeqNumber()); + sipStack.getStackLogger().logDebug("remoteSequenceNumer = " + getRemoteSeqNumber()); + sipStack.getStackLogger().logDebug("ackLine:" + this.getRemoteTag() + " " + ackLine); + } + } + + /** + * Return true if the dialog has already seen the ack. + * + * @return flag that records if the ack has been seen. + */ + public boolean isAckSeen() { + return this.ackSeen; + } + + /** + * Get the last ACK for this transaction. + */ + public SIPRequest getLastAckSent() { + return this.lastAckSent; + } + + /** + * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont + * send ACK). + */ + public boolean isAckSent(long cseqNo) { + if (this.getLastTransaction() == null) + return true; + if (this.getLastTransaction() instanceof ClientTransaction) { + if (this.getLastAckSent() == null) { + return false; + } else { + return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber(); + } + } else { + return true; + } + } + + /** + * Get the transaction that created this dialog. + */ + public Transaction getFirstTransaction() { + return this.firstTransaction; + } + + + /** + * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST + * be set to the list of URIs in the Record-Route header field from the request, taken in + * order and preserving all URI parameters. When acting as an User Agent Client the route set + * MUST be set to the list of URIs in the Record-Route header field from the response, taken + * in reverse order and preserving all URI parameters. If no Record-Route header field is + * present in the request or response, the route set MUST be set to the empty set. This route + * set, even if empty, overrides any pre-existing route set for future requests in this + * dialog. + * <p> + * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these + * requests do not cause the dialog's route set to be modified. + * <p> + * The User Agent Client uses the remote target and route set to build the Request-URI and + * Route header field of the request. + * + * @return an Iterator containing a list of route headers to be used for forwarding. Empty + * iterator is returned if route has not been established. + */ + public Iterator getRouteSet() { + if (this.routeList == null) { + return new LinkedList().listIterator(); + } else { + return this.getRouteList().listIterator(); + } + } + + /** + * Add a Route list extracted from a SIPRequest to this Dialog. + * + * @param sipRequest + */ + public synchronized void addRoute(SIPRequest sipRequest) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "setContact: dialogState: " + this + "state = " + this.getState()); + } + + if (this.dialogState == CONFIRMED_STATE + && SIPRequest.isTargetRefresh(sipRequest.getMethod())) { + this.doTargetRefresh(sipRequest); + } + if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) { + return; + } + + // Fix for issue #225: mustn't learn Route set from mid-dialog requests + if ( sipRequest.getToTag()!=null ) return; + + // Incoming Request has the route list + RecordRouteList rrlist = sipRequest.getRecordRouteHeaders(); + // Add the route set from the incoming response in reverse + // order + if (rrlist != null) { + this.addRoute(rrlist); + } else { + // Set the rotue list to the last seen route list. + this.routeList = new RouteList(); + } + + // put the contact header from the incoming request into + // the route set. JvB: some duplication here, ref. doTargetRefresh + ContactList contactList = sipRequest.getContactHeaders(); + if (contactList != null) { + this.setRemoteTarget((ContactHeader) contactList.getFirst()); + } + } + + /** + * Set the dialog identifier. + */ + public void setDialogId(String dialogId) { + this.dialogId = dialogId; + } + + /** + * Creates a new dialog based on a received NOTIFY. The dialog state is initialized + * appropriately. The NOTIFY differs in the From tag + * + * Made this a separate method to clearly distinguish what's happening here - this is a + * non-trivial case + * + * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent + * @param notifyST - the ServerTransaction created for an incoming NOTIFY + * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction. + * + * + */ + public static SIPDialog createFromNOTIFY(SIPClientTransaction subscribeTx, + SIPTransaction notifyST) { + SIPDialog d = new SIPDialog(notifyST); + // + // The above sets d.firstTransaction to NOTIFY (ST), correct that + // + d.serverTransactionFlag = false; + // they share this one + d.lastTransaction = subscribeTx; + storeFirstTransactionInfo(d, subscribeTx); + d.terminateOnBye = false; + d.localSequenceNumber = subscribeTx.getCSeq(); + SIPRequest not = (SIPRequest) notifyST.getRequest(); + d.remoteSequenceNumber = not.getCSeq().getSeqNumber(); + d.setDialogId(not.getDialogId(true)); + d.setLocalTag(not.getToTag()); + d.setRemoteTag(not.getFromTag()); + // to properly create the Dialog object. + // If not the stack will throw an exception when creating the response. + d.setLastResponse(subscribeTx, subscribeTx.getLastResponse()); + + // Dont use setLocal / setRemote here, they make other assumptions + d.localParty = not.getTo().getAddress(); + d.remoteParty = not.getFrom().getAddress(); + + // initialize d's route set based on the NOTIFY. Any proxies must have + // Record-Routed + d.addRoute(not); + d.setState(CONFIRMED_STATE); // set state, *after* setting route set! + return d; + } + + /** + * Return true if is server. + * + * @return true if is server transaction created this dialog. + */ + public boolean isServer() { + if (this.firstTransactionSeen == false) + return this.serverTransactionFlag; + else + return this.firstTransactionIsServerTransaction; + + } + + /** + * Return true if this is a re-establishment of the dialog. + * + * @return true if the reInvite flag is set. + */ + protected boolean isReInvite() { + return this.reInviteFlag; + } + + /** + * Get the id for this dialog. + * + * @return the string identifier for this dialog. + * + */ + public String getDialogId() { + + if (this.dialogId == null && this.lastResponse != null) + this.dialogId = this.lastResponse.getDialogId(isServer()); + + return this.dialogId; + } + + private static void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) { + dialog.firstTransaction = transaction; + dialog.firstTransactionSeen = true; + dialog.firstTransactionIsServerTransaction = transaction.isServerTransaction(); + dialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme() + .equalsIgnoreCase("sips"); + dialog.firstTransactionPort = transaction.getPort(); + dialog.firstTransactionId = transaction.getBranchId(); + dialog.firstTransactionMethod = transaction.getMethod(); + + if (dialog.isServer()) { + SIPServerTransaction st = (SIPServerTransaction) transaction; + SIPResponse response = st.getLastResponse(); + dialog.contactHeader = response != null ? response.getContactHeader() : null; + } else { + SIPClientTransaction ct = (SIPClientTransaction) transaction; + if (ct != null){ + SIPRequest sipRequest = ct.getOriginalRequest(); + dialog.contactHeader = sipRequest.getContactHeader(); + } + } + } + /** + * Add a transaction record to the dialog. + * + * @param transaction is the transaction to add to the dialog. + */ + public void addTransaction(SIPTransaction transaction) { + + SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest(); + + // Proessing a re-invite. + if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId()) + && transaction.getMethod().equals(firstTransactionMethod)) { + this.reInviteFlag = true; + } + + if (firstTransactionSeen == false) { + // Record the local and remote sequenc + // numbers and the from and to tags for future + // use on this dialog. + storeFirstTransactionInfo(this, transaction); + if (sipRequest.getMethod().equals(Request.SUBSCRIBE)) + this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME); + + this.setLocalParty(sipRequest); + this.setRemoteParty(sipRequest); + this.setCallId(sipRequest); + if (this.originalRequest == null) { + this.originalRequest = sipRequest; + } + if (this.method == null) { + this.method = sipRequest.getMethod(); + } + + if (transaction instanceof SIPServerTransaction) { + this.hisTag = sipRequest.getFrom().getTag(); + // My tag is assigned when sending response + } else { + setLocalSequenceNumber(sipRequest.getCSeq().getSeqNumber()); + this.originalLocalSequenceNumber = localSequenceNumber; + this.myTag = sipRequest.getFrom().getTag(); + if (myTag == null) + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError( + "The request's From header is missing the required Tag parameter."); + } + } else if (transaction.getMethod().equals(firstTransactionMethod) + && firstTransactionIsServerTransaction != transaction.isServerTransaction()) { + // This case occurs when you are processing a re-invite. + // Switch from client side to server side for re-invite + // (put the other side on hold). + + storeFirstTransactionInfo(this, transaction); + + this.setLocalParty(sipRequest); + this.setRemoteParty(sipRequest); + this.setCallId(sipRequest); + this.originalRequest = sipRequest; + this.method = sipRequest.getMethod(); + + } + if (transaction instanceof SIPServerTransaction) + setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber()); + + // If this is a server transaction record the remote + // sequence number to avoid re-processing of requests + // with the same sequence number directed towards this + // dialog. + + this.lastTransaction = transaction; + // set a back ptr in the incoming dialog. + // CHECKME -- why is this here? + // transaction.setDialog(this,sipRequest); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger() + .logDebug("Transaction Added " + this + myTag + "/" + hisTag); + sipStack.getStackLogger().logDebug( + "TID = " + transaction.getTransactionId() + "/" + + transaction.isServerTransaction()); + sipStack.getStackLogger().logStackTrace(); + } + } + + /** + * Set the remote tag. + * + * @param hisTag is the remote tag to set. + */ + private void setRemoteTag(String hisTag) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "setRemoteTag(): " + this + " remoteTag = " + this.hisTag + " new tag = " + + hisTag); + } + if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) { + if (this.getState() != DialogState.EARLY) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dialog is already established -- ignoring remote tag re-assignment"); + return; + } else if (sipStack.isRemoteTagReassignmentAllowed()) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "UNSAFE OPERATION ! tag re-assignment " + this.hisTag + + " trying to set to " + hisTag + + " can cause unexpected effects "); + boolean removed = false; + if (this.sipStack.getDialog(dialogId) == this) { + this.sipStack.removeDialog(dialogId); + removed = true; + + } + // Force recomputation of Dialog ID; + this.dialogId = null; + this.hisTag = hisTag; + if (removed) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("ReInserting Dialog"); + this.sipStack.putDialog(this); + } + } + } else { + if (hisTag != null) { + this.hisTag = hisTag; + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning("setRemoteTag : called with null argument "); + } + } + } + + /** + * Get the last transaction from the dialog. + */ + public SIPTransaction getLastTransaction() { + return this.lastTransaction; + } + + /** + * Get the INVITE transaction (null if no invite transaction). + */ + public SIPServerTransaction getInviteTransaction() { + DialogTimerTask t = this.timerTask; + if (t != null) + return t.transaction; + else + return null; + } + + /** + * Set the local sequece number for the dialog (defaults to 1 when the dialog is created). + * + * @param lCseq is the local cseq number. + * + */ + private void setLocalSequenceNumber(long lCseq) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "setLocalSequenceNumber: original " + this.localSequenceNumber + " new = " + + lCseq); + if (lCseq <= this.localSequenceNumber) + throw new RuntimeException("Sequence number should not decrease !"); + this.localSequenceNumber = lCseq; + } + + /** + * Set the remote sequence number for the dialog. + * + * @param rCseq is the remote cseq number. + * + */ + public void setRemoteSequenceNumber(long rCseq) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("setRemoteSeqno " + this + "/" + rCseq); + this.remoteSequenceNumber = rCseq; + } + + /** + * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole + * in the sequence number i.e. route a request outside the dialog and then resume within the + * dialog. + */ + public void incrementLocalSequenceNumber() { + ++this.localSequenceNumber; + } + + /** + * Get the remote sequence number (for cseq assignment of outgoing requests within this + * dialog). + * + * @deprecated + * @return local sequence number. + */ + + public int getRemoteSequenceNumber() { + return (int) this.remoteSequenceNumber; + } + + /** + * Get the local sequence number (for cseq assignment of outgoing requests within this + * dialog). + * + * @deprecated + * @return local sequence number. + */ + + public int getLocalSequenceNumber() { + return (int) this.localSequenceNumber; + } + + /** + * Get the sequence number for the request that origianlly created the Dialog. + * + * @return -- the original starting sequence number for this dialog. + */ + public long getOriginalLocalSequenceNumber() { + return this.originalLocalSequenceNumber; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getLocalSequenceNumberLong() + */ + public long getLocalSeqNumber() { + return this.localSequenceNumber; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getRemoteSequenceNumberLong() + */ + public long getRemoteSeqNumber() { + return this.remoteSequenceNumber; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getLocalTag() + */ + public String getLocalTag() { + return this.myTag; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getRemoteTag() + */ + public String getRemoteTag() { + + return hisTag; + } + + /** + * Set local tag for the transaction. + * + * @param mytag is the tag to use in From headers client transactions that belong to this + * dialog and for generating To tags for Server transaction requests that belong to + * this dialog. + */ + private void setLocalTag(String mytag) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("set Local tag " + mytag + " " + this.dialogId); + sipStack.getStackLogger().logStackTrace(); + } + + this.myTag = mytag; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#delete() + */ + + public void delete() { + // the reaper will get him later. + this.setState(TERMINATED_STATE); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getCallId() + */ + public CallIdHeader getCallId() { + return this.callIdHeader; + } + + /** + * set the call id header for this dialog. + */ + private void setCallId(SIPRequest sipRequest) { + this.callIdHeader = sipRequest.getCallId(); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getLocalParty() + */ + + public javax.sip.address.Address getLocalParty() { + return this.localParty; + } + + private void setLocalParty(SIPMessage sipMessage) { + if (!isServer()) { + this.localParty = sipMessage.getFrom().getAddress(); + } else { + this.localParty = sipMessage.getTo().getAddress(); + } + } + + /** + * Returns the Address identifying the remote party. This is the value of the To header of + * locally initiated requests in this dialogue when acting as an User Agent Client. + * <p> + * This is the value of the From header of recieved responses in this dialogue when acting as + * an User Agent Server. + * + * @return the address object of the remote party. + */ + public javax.sip.address.Address getRemoteParty() { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("gettingRemoteParty " + this.remoteParty); + } + return this.remoteParty; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getRemoteTarget() + */ + public javax.sip.address.Address getRemoteTarget() { + + return this.remoteTarget; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#getState() + */ + public DialogState getState() { + if (this.dialogState == NULL_STATE) + return null; // not yet initialized + return DialogState.getObject(this.dialogState); + } + + /** + * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the + * Request-URI contained a SIPS URI, the "secure" flag is set to TRUE. + * + * @return <code>true</code> if this dialogue was established using a sips URI over TLS, and + * <code>false</code> otherwise. + */ + public boolean isSecure() { + return this.firstTransactionSecure; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#sendAck(javax.sip.message.Request) + */ + public void sendAck(Request request) throws SipException { + this.sendAck(request, true); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#createRequest(java.lang.String) + */ + public Request createRequest(String method) throws SipException { + + if (method.equals(Request.ACK) || method.equals(Request.PRACK)) { + throw new SipException("Invalid method specified for createRequest:" + method); + } + if (lastResponse != null) + return this.createRequest(method, this.lastResponse); + else + throw new SipException("Dialog not yet established -- no response!"); + } + + /** + * The method that actually does the work of creating a request. + * + * @param method + * @param response + * @return + * @throws SipException + */ + private Request createRequest(String method, SIPResponse sipResponse) throws SipException { + /* + * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY + * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on + * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs. + * + * Throw out cancel request. + */ + + if (method == null || sipResponse == null) + throw new NullPointerException("null argument"); + + if (method.equals(Request.CANCEL)) + throw new SipException("Dialog.createRequest(): Invalid request"); + + if (this.getState() == null + || (this.getState().getValue() == TERMINATED_STATE && !method + .equalsIgnoreCase(Request.BYE)) + || (this.isServer() && this.getState().getValue() == EARLY_STATE && method + .equalsIgnoreCase(Request.BYE))) + throw new SipException("Dialog " + getDialogId() + + " not yet established or terminated " + this.getState()); + + SipUri sipUri = null; + if (this.getRemoteTarget() != null) + sipUri = (SipUri) this.getRemoteTarget().getURI().clone(); + else { + sipUri = (SipUri) this.getRemoteParty().getURI().clone(); + sipUri.clearUriParms(); + } + + CSeq cseq = new CSeq(); + try { + cseq.setMethod(method); + cseq.setSeqNumber(this.getLocalSeqNumber()); + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("Unexpected error"); + InternalErrorHandler.handleException(ex); + } + /* + * Add a via header for the outbound request based on the transport of the message + * processor. + */ + + ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider + .getListeningPoint(sipResponse.getTopmostVia().getTransport()); + if (lp == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError( + "Cannot find listening point for transport " + + sipResponse.getTopmostVia().getTransport()); + throw new SipException("Cannot find listening point for transport " + + sipResponse.getTopmostVia().getTransport()); + } + Via via = lp.getViaHeader(); + + From from = new From(); + from.setAddress(this.localParty); + To to = new To(); + to.setAddress(this.remoteParty); + SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to); + + /* + * The default contact header is obtained from the provider. The application can override + * this. + * + * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc + */ + + if (SIPRequest.isTargetRefresh(method)) { + ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider + .getListeningPoint(lp.getTransport())).createContactHeader(); + + ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure()); + sipRequest.setHeader(contactHeader); + } + + try { + /* + * Guess of local sequence number - this is being re-set when the request is actually + * dispatched + */ + cseq = (CSeq) sipRequest.getCSeq(); + cseq.setSeqNumber(this.localSequenceNumber + 1); + + } catch (InvalidArgumentException ex) { + InternalErrorHandler.handleException(ex); + } + + if (method.equals(Request.SUBSCRIBE)) { + + if (eventHeader != null) + sipRequest.addHeader(eventHeader); + + } + + /* + * RFC3261, section 12.2.1.1: + * + * The URI in the To field of the request MUST be set to the remote URI from the dialog + * state. The tag in the To header field of the request MUST be set to the remote tag of + * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog + * state. The tag in the From header field of the request MUST be set to the local tag of + * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST + * be omitted from the To or From header fields, respectively. + */ + + try { + if (this.getLocalTag() != null) { + from.setTag(this.getLocalTag()); + } else { + from.removeTag(); + } + if (this.getRemoteTag() != null) { + to.setTag(this.getRemoteTag()); + } else { + to.removeTag(); + } + } catch (ParseException ex) { + InternalErrorHandler.handleException(ex); + } + + // get the route list from the dialog. + this.updateRequest(sipRequest); + + return sipRequest; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#sendRequest(javax.sip.ClientTransaction) + */ + + public void sendRequest(ClientTransaction clientTransactionId) + throws TransactionDoesNotExistException, SipException { + this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent); + } + + public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving) + throws TransactionDoesNotExistException, SipException { + + if ( (!allowInterleaving) + && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) { + new Thread((new ReInviteSender(clientTransactionId))).start(); + return; + } + + SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId) + .getOriginalRequest(); + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n" + + dialogRequest); + + if (clientTransactionId == null) + throw new NullPointerException("null parameter"); + + if (dialogRequest.getMethod().equals(Request.ACK) + || dialogRequest.getMethod().equals(Request.CANCEL)) + throw new SipException("Bad Request Method. " + dialogRequest.getMethod()); + + // JvB: added, allow re-sending of BYE after challenge + if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("BYE already sent for " + this); + throw new SipException("Cannot send request; BYE already sent"); + } + + if (dialogRequest.getTopmostVia() == null) { + Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader(); + dialogRequest.addHeader(via); + } + if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("CallID " + this.getCallId()); + sipStack.getStackLogger().logError( + "RequestCallID = " + dialogRequest.getCallId().getCallId()); + sipStack.getStackLogger().logError("dialog = " + this); + } + throw new SipException("Bad call ID in request"); + } + + // Set the dialog back pointer. + ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId); + + this.addTransaction((SIPTransaction) clientTransactionId); + // Enable the retransmission filter for the transaction + + ((SIPClientTransaction) clientTransactionId).isMapped = true; + + From from = (From) dialogRequest.getFrom(); + To to = (To) dialogRequest.getTo(); + + // Caller already did the tag assignment -- check to see if the + // tag assignment is OK. + if (this.getLocalTag() != null && from.getTag() != null + && !from.getTag().equals(this.getLocalTag())) + throw new SipException("From tag mismatch expecting " + this.getLocalTag()); + + if (this.getRemoteTag() != null && to.getTag() != null + && !to.getTag().equals(this.getRemoteTag())) { + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logWarning( + "To header tag mismatch expecting " + this.getRemoteTag()); + } + /* + * The application is sending a NOTIFY before sending the response of the dialog. + */ + if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) { + if (!this.getMethod().equals(Request.SUBSCRIBE)) + throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!"); + this.setLocalTag(from.getTag()); + + } + + try { + if (this.getLocalTag() != null) + from.setTag(this.getLocalTag()); + if (this.getRemoteTag() != null) + to.setTag(this.getRemoteTag()); + + } catch (ParseException ex) { + + InternalErrorHandler.handleException(ex); + + } + + Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Using hop = " + hop.getHost() + " : " + hop.getPort()); + } + + try { + MessageChannel messageChannel = sipStack.createRawMessageChannel(this + .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(), + this.firstTransactionPort, hop); + + MessageChannel oldChannel = ((SIPClientTransaction) + clientTransactionId).getMessageChannel(); + + // Remove this from the connection cache if it is in the + // connection + // cache and is not yet active. + oldChannel.uncache(); + + // Not configured to cache client connections. + if (!sipStack.cacheClientConnections) { + oldChannel.useCount--; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "oldChannel: useCount " + oldChannel.useCount); + + } + + if (messageChannel == null) { + /* + * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried + * but the resulting next hop cannot be resolved (recall that the exception thrown + * is caught and ignored in SIPStack.createMessageChannel() so we end up here with + * a null messageChannel instead of the exception handler below). All else + * failing, try the outbound proxy in accordance with 8.1.2, in particular: This + * ensures that outbound proxies that do not add Record-Route header field values + * will drop out of the path of subsequent requests. It allows endpoints that + * cannot resolve the first Route URI to delegate that task to an outbound proxy. + * + * if one considers the 'first Route URI' of a request constructed according to + * 12.2.1.1 to be the request URI when the route set is empty. + */ + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Null message channel using outbound proxy !"); + Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy(); + if (outboundProxy == null) + throw new SipException("No route found! hop=" + hop); + messageChannel = sipStack.createRawMessageChannel(this.getSipProvider() + .getListeningPoint(outboundProxy.getTransport()).getIPAddress(), + this.firstTransactionPort, outboundProxy); + if (messageChannel != null) + ((SIPClientTransaction) clientTransactionId) + .setEncapsulatedChannel(messageChannel); + } else { + ((SIPClientTransaction) clientTransactionId) + .setEncapsulatedChannel(messageChannel); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("using message channel " + messageChannel); + + } + + } + + if (messageChannel != null) messageChannel.useCount++; + + // See if we need to release the previously mapped channel. + if ((!sipStack.cacheClientConnections) && oldChannel != null + && oldChannel.useCount <= 0) + oldChannel.close(); + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + throw new SipException("Could not create message channel", ex); + } + + try { + // Increment before setting!! + localSequenceNumber++; + dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber()); + } catch (InvalidArgumentException ex) { + sipStack.getStackLogger().logFatalError(ex.getMessage()); + } + + try { + ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest); + /* + * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED + * state so we only set state after successful send. + */ + if (dialogRequest.getMethod().equals(Request.BYE)) { + this.byeSent = true; + /* + * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182. + */ + if (isTerminatedOnBye()) { + this.setState(DialogState._TERMINATED); + } + } + } catch (IOException ex) { + throw new SipException("error sending message", ex); + } + + } + + /** + * Return yes if the last response is to be retransmitted. + */ + private boolean toRetransmitFinalResponse(int T2) { + if (--retransmissionTicksLeft == 0) { + if (2 * prevRetransmissionTicks <= T2) + this.retransmissionTicksLeft = 2 * prevRetransmissionTicks; + else + this.retransmissionTicksLeft = prevRetransmissionTicks; + this.prevRetransmissionTicks = retransmissionTicksLeft; + return true; + } else + return false; + + } + + protected void setRetransmissionTicks() { + this.retransmissionTicksLeft = 1; + this.prevRetransmissionTicks = 1; + } + + /** + * Resend the last ack. + */ + public void resendAck() throws SipException { + // Check for null. + + if (this.getLastAckSent() != null) { + if (getLastAckSent().getHeader(TimeStampHeader.NAME) != null + && sipStack.generateTimeStampHeader) { + TimeStamp ts = new TimeStamp(); + try { + ts.setTimeStamp(System.currentTimeMillis()); + getLastAckSent().setHeader(ts); + } catch (InvalidArgumentException e) { + + } + } + this.sendAck(getLastAckSent(), false); + } + + } + + /** + * Get the method of the request/response that resulted in the creation of the Dialog. + * + * @return -- the method of the dialog. + */ + public String getMethod() { + // Method of the request or response used to create this dialog + return this.method; + } + + /** + * Start the dialog timer. + * + * @param transaction + */ + + protected void startTimer(SIPServerTransaction transaction) { + if (this.timerTask != null && timerTask.transaction == transaction) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Timer already running for " + getDialogId()); + return; + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Starting dialog timer for " + getDialogId()); + this.ackSeen = false; + + acquireTimerTaskSem(); + try { + if (this.timerTask != null) { + this.timerTask.transaction = transaction; + } else { + this.timerTask = new DialogTimerTask(transaction); + sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL, + SIPTransactionStack.BASE_TIMER_INTERVAL); + } + } finally { + releaseTimerTaskSem(); + } + + this.setRetransmissionTicks(); + } + + /** + * Stop the dialog timer. This is called when the dialog is terminated. + * + */ + protected void stopTimer() { + try { + acquireTimerTaskSem(); + try { + if (this.timerTask != null) { + this.timerTask.cancel(); + this.timerTask = null; + } + } finally { + releaseTimerTaskSem(); + } + } catch (Exception ex) { + } + } + + /* + * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching + * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the + * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A + * matching PRACK is defined as one within the same dialog as the response, and whose method, + * CSeq-num, and response-num in the RAck header field match, respectively, the method from + * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the + * reliable provisional response. + * + * @see javax.sip.Dialog#createPrack(javax.sip.message.Response) + */ + public Request createPrack(Response relResponse) throws DialogDoesNotExistException, + SipException { + + if (this.getState() == null || this.getState().equals(DialogState.TERMINATED)) + throw new DialogDoesNotExistException("Dialog not initialized or terminated"); + + if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) { + throw new SipException("Missing RSeq Header"); + } + + try { + SIPResponse sipResponse = (SIPResponse) relResponse; + SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK, + (SIPResponse) relResponse); + String toHeaderTag = sipResponse.getTo().getTag(); + sipRequest.setToTag(toHeaderTag); + RAck rack = new RAck(); + RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME); + rack.setMethod(sipResponse.getCSeq().getMethod()); + rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber()); + rack.setRSequenceNumber(rseq.getSeqNumber()); + sipRequest.setHeader(rack); + return (Request) sipRequest; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + return null; + } + + } + + private void updateRequest(SIPRequest sipRequest) { + + RouteList rl = this.getRouteList(); + if (rl.size() > 0) { + sipRequest.setHeader(rl); + } else { + sipRequest.removeHeader(RouteHeader.NAME); + } + if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { + sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); + } + + } + + /* + * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the + * transaction layer. The header fields of the ACK are constructed in the same way as for any + * request sent within a dialog (see Section 12) with the exception of the CSeq and the header + * fields related to authentication. The sequence number of the CSeq header field MUST be the + * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST + * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the + * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is + * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE + * immediately. + * + * Note that for the case of forked requests, you can create multiple outgoing invites each + * with a different cseq and hence you need to supply the invite. + * + * @see javax.sip.Dialog#createAck(long) + */ + public Request createAck(long cseqno) throws InvalidArgumentException, SipException { + + // JvB: strictly speaking it is allowed to start a dialog with + // SUBSCRIBE, + // then send INVITE+ACK later on + if (!method.equals(Request.INVITE)) + throw new SipException("Dialog was not created with an INVITE" + method); + + if (cseqno <= 0) + throw new InvalidArgumentException("bad cseq <= 0 "); + else if (cseqno > ((((long) 1) << 32) - 1)) + throw new InvalidArgumentException("bad cseq > " + ((((long) 1) << 32) - 1)); + + if (this.remoteTarget == null) { + throw new SipException("Cannot create ACK - no remote Target!"); + } + + if (this.sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("createAck " + this + " cseqno " + cseqno); + } + + // MUST ack in the same order that the OKs were received. This traps + // out of order ACK sending. Old ACKs seqno's can always be ACKed. + if (lastInviteOkReceived < cseqno) { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug( + "WARNING : Attempt to crete ACK without OK " + this); + this.sipStack.getStackLogger().logDebug("LAST RESPONSE = " + this.lastResponse); + } + throw new SipException("Dialog not yet established -- no OK response!"); + } + + try { + + // JvB: Transport from first entry in route set, or remote Contact + // if none + // Only used to find correct LP & create correct Via + SipURI uri4transport = null; + + if (this.routeList != null && !this.routeList.isEmpty()) { + Route r = (Route) this.routeList.getFirst(); + uri4transport = ((SipURI) r.getAddress().getURI()); + } else { // should be !=null, checked above + uri4transport = ((SipURI) this.remoteTarget.getURI()); + } + + String transport = uri4transport.getTransportParam(); + if (transport == null) { + // JvB fix: also support TLS + transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP; + } + ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport); + if (lp == null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError( + "remoteTargetURI " + this.remoteTarget.getURI()); + sipStack.getStackLogger().logError("uri4transport = " + uri4transport); + sipStack.getStackLogger().logError("No LP found for transport=" + transport); + } + throw new SipException( + "Cannot create ACK - no ListeningPoint for transport towards next hop found:" + + transport); + } + SIPRequest sipRequest = new SIPRequest(); + sipRequest.setMethod(Request.ACK); + sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone()); + sipRequest.setCallId(this.callIdHeader); + sipRequest.setCSeq(new CSeq(cseqno, Request.ACK)); + List<Via> vias = new ArrayList<Via>(); + // Via via = lp.getViaHeader(); + // The user may have touched the sentby for the response. + // so use the via header extracted from the response for the ACK => + // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205 + // strip the params from the via of the response and use the params from the + // original request + Via via = this.lastResponse.getTopmostVia(); + via.removeParameters(); + if (originalRequest != null && originalRequest.getTopmostVia() != null) { + NameValueList originalRequestParameters = originalRequest.getTopmostVia() + .getParameters(); + if (originalRequestParameters != null && originalRequestParameters.size() > 0) { + via.setParameters((NameValueList) originalRequestParameters.clone()); + } + } + via.setBranch(Utils.getInstance().generateBranchId()); // new branch + vias.add(via); + sipRequest.setVia(vias); + From from = new From(); + from.setAddress(this.localParty); + from.setTag(this.myTag); + sipRequest.setFrom(from); + To to = new To(); + to.setAddress(this.remoteParty); + if (hisTag != null) + to.setTag(this.hisTag); + sipRequest.setTo(to); + sipRequest.setMaxForwards(new MaxForwards(70)); + + if (this.originalRequest != null) { + Authorization authorization = this.originalRequest.getAuthorization(); + if (authorization != null) + sipRequest.setHeader(authorization); + } + + // ACKs for 2xx responses + // use the Route values learned from the Record-Route of the 2xx + // responses. + this.updateRequest(sipRequest); + + return sipRequest; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + throw new SipException("unexpected exception ", ex); + } + + } + + /** + * Get the provider for this Dialog. + * + * SPEC_REVISION + * + * @return -- the SIP Provider associated with this transaction. + */ + public SipProviderImpl getSipProvider() { + return this.sipProvider; + } + + /** + * @param sipProvider the sipProvider to set + */ + public void setSipProvider(SipProviderImpl sipProvider) { + this.sipProvider = sipProvider; + } + + /** + * Check the tags of the response against the tags of the Dialog. Return true if the respnse + * matches the tags of the dialog. We do this check wehn sending out a response. + * + * @param sipResponse -- the response to check. + * + */ + public void setResponseTags(SIPResponse sipResponse) { + if (this.getLocalTag() != null || this.getRemoteTag() != null) { + return; + } + String responseFromTag = sipResponse.getFromTag(); + if ( responseFromTag != null ) { + if (responseFromTag.equals(this.getLocalTag())) { + sipResponse.setToTag(this.getRemoteTag()); + } else if (responseFromTag.equals(this.getRemoteTag())) { + sipResponse.setToTag(this.getLocalTag()); + } + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning("No from tag in response! Not RFC 3261 compatible."); + } + + } + + /** + * Set the last response for this dialog. This method is called for updating the dialog state + * when a response is either sent or received from within a Dialog. + * + * @param transaction -- the transaction associated with the response + * @param sipResponse -- the last response to set. + */ + public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) { + this.callIdHeader = sipResponse.getCallId(); + int statusCode = sipResponse.getStatusCode(); + if (statusCode == 100) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logWarning( + "Invalid status code - 100 in setLastResponse - ignoring"); + return; + } + + this.lastResponse = sipResponse; + this.setAssigned(); + // Adjust state of the Dialog state machine. + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "sipDialog: setLastResponse:" + this + " lastResponse = " + + this.lastResponse.getFirstLine()); + } + if (this.getState() == DialogState.TERMINATED) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "sipDialog: setLastResponse -- dialog is terminated - ignoring "); + } + // Capture the OK response for later use in createAck + // This is handy for late arriving OK's that we want to ACK. + if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) { + + this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), + this.lastInviteOkReceived); + } + return; + } + String cseqMethod = sipResponse.getCSeq().getMethod(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logStackTrace(); + sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod); + sipStack.getStackLogger().logDebug("dialogState = " + this.getState()); + sipStack.getStackLogger().logDebug("method = " + this.getMethod()); + sipStack.getStackLogger().logDebug("statusCode = " + statusCode); + sipStack.getStackLogger().logDebug("transaction = " + transaction); + } + + // JvB: don't use "!this.isServer" here + // note that the transaction can be null for forked + // responses. + if (transaction == null || transaction instanceof ClientTransaction) { + if (sipStack.isDialogCreated(cseqMethod)) { + // Make a final tag assignment. + if (getState() == null && (statusCode / 100 == 1)) { + /* + * Guard aginst slipping back into early state from confirmed state. + */ + // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported) + setState(SIPDialog.EARLY_STATE); + if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported) + && this.getRemoteTag() == null) { + setRemoteTag(sipResponse.getToTag()); + this.setDialogId(sipResponse.getDialogId(false)); + sipStack.putDialog(this); + this.addRoute(sipResponse); + } + } else if (getState() != null && getState().equals(DialogState.EARLY) + && statusCode / 100 == 1) { + /* + * This case occurs for forked dialog responses. The To tag can change as a + * result of the forking. The remote target can also change as a result of the + * forking. + */ + if (cseqMethod.equals(getMethod()) && transaction != null + && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) { + setRemoteTag(sipResponse.getToTag()); + this.setDialogId(sipResponse.getDialogId(false)); + sipStack.putDialog(this); + this.addRoute(sipResponse); + } + } else if (statusCode / 100 == 2) { + // This is a dialog creating method (such as INVITE). + // 2xx response -- set the state to the confirmed + // state. To tag is MANDATORY for the response. + + // Only do this if method equals initial request! + + if (cseqMethod.equals(getMethod()) + && (sipResponse.getToTag() != null || sipStack.rfc2543Supported) + && this.getState() != DialogState.CONFIRMED) { + setRemoteTag(sipResponse.getToTag()); + this.setDialogId(sipResponse.getDialogId(false)); + sipStack.putDialog(this); + this.addRoute(sipResponse); + + setState(SIPDialog.CONFIRMED_STATE); + } + + // Capture the OK response for later use in createAck + if (cseqMethod.equals(Request.INVITE)) { + this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), + this.lastInviteOkReceived); + } + + } else if (statusCode >= 300 + && statusCode <= 699 + && (getState() == null || (cseqMethod.equals(getMethod()) && getState() + .getValue() == SIPDialog.EARLY_STATE))) { + /* + * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 - + * dialog termination. Independent of the method, if a request outside of a + * dialog generates a non-2xx final response, any early dialogs created + * through provisional responses to that request are terminated. + */ + setState(SIPDialog.TERMINATED_STATE); + } + + /* + * This code is in support of "proxy" servers that are constructed as back to back + * user agents. This could be a dialog in the middle of the call setup path + * somewhere. Hence the incoming invite has record route headers in it. The + * response will have additional record route headers. However, for this dialog + * only the downstream record route headers matter. Ideally proxy servers should + * not be constructed as Back to Back User Agents. Remove all the record routes + * that are present in the incoming INVITE so you only have the downstream Route + * headers present in the dialog. Note that for an endpoint - you will have no + * record route headers present in the original request so the loop will not + * execute. + */ + if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) { + if (originalRequest != null) { + RecordRouteList rrList = originalRequest.getRecordRouteHeaders(); + if (rrList != null) { + ListIterator<RecordRoute> it = rrList.listIterator(rrList.size()); + while (it.hasPrevious()) { + RecordRoute rr = (RecordRoute) it.previous(); + Route route = (Route) routeList.getFirst(); + if (route != null && rr.getAddress().equals(route.getAddress())) { + routeList.removeFirst(); + } else + break; + } + } + } + } + + } else if (cseqMethod.equals(Request.NOTIFY) + && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals( + Request.REFER)) && sipResponse.getStatusCode() / 100 == 2 + && this.getState() == null) { + // This is a notify response. + this.setDialogId(sipResponse.getDialogId(true)); + sipStack.putDialog(this); + this.setState(SIPDialog.CONFIRMED_STATE); + + } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 + && isTerminatedOnBye()) { + // Dialog will be terminated when the transction is terminated. + setState(SIPDialog.TERMINATED_STATE); + } + } else { + // Processing Server Dialog. + + if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 + && this.isTerminatedOnBye()) { + /* + * Only transition to terminated state when 200 OK is returned for the BYE. Other + * status codes just result in leaving the state in COMPLETED state. + */ + this.setState(SIPDialog.TERMINATED_STATE); + } else { + boolean doPutDialog = false; + + if (getLocalTag() == null && sipResponse.getTo().getTag() != null + && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) { + setLocalTag(sipResponse.getTo().getTag()); + + doPutDialog = true; + } + + if (statusCode / 100 != 2) { + if (statusCode / 100 == 1) { + if (doPutDialog) { + + setState(SIPDialog.EARLY_STATE); + this.setDialogId(sipResponse.getDialogId(true)); + sipStack.putDialog(this); + } + } else { + /* + * RFC 3265 chapter 3.1.4.1 "Non-200 class final responses indicate that + * no subscription or dialog has been created, and no subsequent NOTIFY + * message will be sent. All non-200 class" + responses (with the + * exception of "489", described herein) have the same meanings and + * handling as described in SIP" + */ + // Bug Fix by Jens tinfors + // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797 + if (statusCode == 489 + && (cseqMethod.equals(Request.NOTIFY) || cseqMethod + .equals(Request.SUBSCRIBE))) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "RFC 3265 : Not setting dialog to TERMINATED for 489"); + } else { + // baranowb: simplest fix to + // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175 + // application is responsible for terminating in this case + // see rfc 5057 for better explanation + if (!this.isReInvite() && getState() != DialogState.CONFIRMED) { + this.setState(SIPDialog.TERMINATED_STATE); + } + } + } + + } else { + + /* + * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to + * CONFIRMED + */ + if (this.dialogState <= SIPDialog.EARLY_STATE + && (cseqMethod.equals(Request.INVITE) + || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod + .equals(Request.REFER))) { + this.setState(SIPDialog.CONFIRMED_STATE); + } + + if (doPutDialog) { + this.setDialogId(sipResponse.getDialogId(true)); + sipStack.putDialog(this); + } + /* + * We put the dialog into the table. We must wait for ACK before re-INVITE is + * sent + */ + if (transaction.getState() != TransactionState.TERMINATED + && sipResponse.getStatusCode() == Response.OK + && cseqMethod.equals(Request.INVITE) + && this.isBackToBackUserAgent) { + /* + * Acquire the flag for re-INVITE so that we cannot re-INVITE before + * ACK is received. + */ + if (!this.takeAckSem()) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Delete dialog -- cannot acquire ackSem"); + } + this.delete(); + return; + } + + } + } + } + + } + + } + + /** + * Start the retransmit timer. + * + * @param sipServerTx -- server transaction on which the response was sent + * @param response - response that was sent. + */ + public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) { + if (sipServerTx.getRequest().getMethod().equals(Request.INVITE) + && response.getStatusCode() / 100 == 2) { + this.startTimer(sipServerTx); + } + } + + /** + * @return -- the last response associated with the dialog. + */ + public SIPResponse getLastResponse() { + + return lastResponse; + } + + /** + * Do taget refresh dialog state updates. + * + * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields. + * However, these requests do not cause the dialog's route set to be modified, although they + * may modify the remote target URI. Specifically, requests that are not target refresh + * requests do not modify the dialog's remote target URI, and requests that are target refresh + * requests do. For dialogs that have been established with an + * + * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other + * extensions may define different target refresh requests for dialogs established in other + * ways. + */ + private void doTargetRefresh(SIPMessage sipMessage) { + + ContactList contactList = sipMessage.getContactHeaders(); + + /* + * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for + * subscribe dialogs from the client side. This modifies the remote target URI potentially + */ + if (contactList != null) { + + Contact contact = (Contact) contactList.getFirst(); + this.setRemoteTarget(contact); + + } + + } + + private static final boolean optionPresent(ListIterator l, String option) { + while (l.hasNext()) { + OptionTag opt = (OptionTag) l.next(); + if (opt != null && option.equalsIgnoreCase(opt.getOptionTag())) + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#createReliableProvisionalResponse(int) + */ + public Response createReliableProvisionalResponse(int statusCode) + throws InvalidArgumentException, SipException { + + if (!(firstTransactionIsServerTransaction)) { + throw new SipException("Not a Server Dialog!"); + + } + /* + * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional + * responses numbered 101 to 199 may be sent reliably. If the request did not include + * either a Supported or Require header field indicating this feature, the UAS MUST NOT + * send the provisional response reliably. + */ + if (statusCode <= 100 || statusCode > 199) + throw new InvalidArgumentException("Bad status code "); + SIPRequest request = this.originalRequest; + if (!request.getMethod().equals(Request.INVITE)) + throw new SipException("Bad method"); + + ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME); + if (list == null || !optionPresent(list, "100rel")) { + list = request.getHeaders(RequireHeader.NAME); + if (list == null || !optionPresent(list, "100rel")) { + throw new SipException("No Supported/Require 100rel header in the request"); + } + } + + SIPResponse response = request.createResponse(statusCode); + /* + * The provisional response to be sent reliably is constructed by the UAS core according + * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require + * header field containing the option tag 100rel, and MUST include an RSeq header field. + * The value of the header field for the first reliable provisional response in a + * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen + * uniformly in this range. The RSeq numbering space is within a single transaction. This + * means that provisional responses for different requests MAY use the same values for the + * RSeq number. + */ + Require require = new Require(); + try { + require.setOptionTag("100rel"); + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + response.addHeader(require); + RSeq rseq = new RSeq(); + /* + * set an arbitrary sequence number. This is actually set when the response is sent out + */ + rseq.setSeqNumber(1L); + /* + * Copy the record route headers from the request to the response ( Issue 160 ). Note that + * other 1xx headers do not get their Record Route headers copied over but reliable + * provisional responses do. See RFC 3262 Table 2. + */ + RecordRouteList rrl = request.getRecordRouteHeaders(); + if (rrl != null) { + RecordRouteList rrlclone = (RecordRouteList) rrl.clone(); + response.setHeader(rrlclone); + } + + return response; + } + + /** + * Do the processing necessary for the PRACK + * + * @param prackRequest + * @return true if this is the first time the tx has seen the prack ( and hence needs to be + * passed up to the TU) + */ + public boolean handlePrack(SIPRequest prackRequest) { + /* + * The RAck header is sent in a PRACK request to support reliability of provisional + * responses. It contains two numbers and a method tag. The first number is the value from + * the RSeq header in the provisional response that is being acknowledged. The next + * number, and the method, are copied from the CSeq in the response that is being + * acknowledged. The method name in the RAck header is case sensitive. + */ + if (!this.isServer()) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog"); + return false; + } + SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this + .getFirstTransaction(); + SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse(); + + if (sipResponse == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("Dropping Prack -- ReliableResponse not found"); + return false; + } + + RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME); + + if (rack == null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found"); + return false; + } + CSeq cseq = (CSeq) sipResponse.getCSeq(); + + if (!rack.getMethod().equals(cseq.getMethod())) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping Prack -- CSeq Header does not match PRACK"); + return false; + } + + if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping Prack -- CSeq Header does not match PRACK"); + return false; + } + + RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME); + + if (rack.getRSequenceNumber() != rseq.getSeqNumber()) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "Dropping Prack -- RSeq Header does not match PRACK"); + return false; + } + + return sipServerTransaction.prackRecieved(); + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response) + */ + public void sendReliableProvisionalResponse(Response relResponse) throws SipException { + if (!this.isServer()) { + throw new SipException("Not a Server Dialog"); + } + + SIPResponse sipResponse = (SIPResponse) relResponse; + + if (relResponse.getStatusCode() == 100) + throw new SipException("Cannot send 100 as a reliable provisional response"); + + if (relResponse.getStatusCode() / 100 > 2) + throw new SipException( + "Response code is not a 1xx response - should be in the range 101 to 199 "); + + /* + * Do a little checking on the outgoing response. + */ + if (sipResponse.getToTag() == null) { + throw new SipException( + "Badly formatted response -- To tag mandatory for Reliable Provisional Response"); + } + ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME); + boolean found = false; + + if (requireList != null) { + + while (requireList.hasNext() && !found) { + RequireHeader rh = (RequireHeader) requireList.next(); + if (rh.getOptionTag().equalsIgnoreCase("100rel")) { + found = true; + } + } + } + + if (!found) { + Require require = new Require("100rel"); + relResponse.addHeader(require); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Require header with optionTag 100rel is needed -- adding one"); + } + + } + + SIPServerTransaction serverTransaction = (SIPServerTransaction) this + .getFirstTransaction(); + /* + * put into the dialog table before sending the response so as to avoid race condition + * with PRACK + */ + this.setLastResponse(serverTransaction, sipResponse); + + this.setDialogId(sipResponse.getDialogId(true)); + + serverTransaction.sendReliableProvisionalResponse(relResponse); + + this.startRetransmitTimer(serverTransaction, relResponse); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Dialog#terminateOnBye(boolean) + */ + public void terminateOnBye(boolean terminateFlag) throws SipException { + + this.terminateOnBye = terminateFlag; + } + + /** + * Set the "assigned" flag to true. We do this when inserting the dialog into the dialog table + * of the stack. + * + */ + public void setAssigned() { + this.isAssigned = true; + } + + /** + * Return true if the dialog has already been mapped to a transaction. + * + */ + + public boolean isAssigned() { + return this.isAssigned; + } + + /** + * Get the contact header that the owner of this dialog assigned. Subsequent Requests are + * considered to belong to the dialog if the dialog identifier matches and the contact header + * matches the ip address and port on which the request is received. + * + * @return contact header belonging to the dialog. + */ + public Contact getMyContactHeader() { + return contactHeader; + } + + /** + * Do the necessary processing to handle an ACK directed at this Dialog. + * + * @param ackTransaction -- the ACK transaction that was directed at this dialog. + * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the + * dialog state being changed. + */ + public boolean handleAck(SIPServerTransaction ackTransaction) { + SIPRequest sipRequest = ackTransaction.getOriginalRequest(); + + if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "ACK already seen by dialog -- dropping Ack" + " retransmission"); + } + acquireTimerTaskSem(); + try { + if (this.timerTask != null) { + this.timerTask.cancel(); + this.timerTask = null; + } + } finally { + releaseTimerTaskSem(); + } + return false; + } else if (this.getState() == DialogState.TERMINATED) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping ACK"); + return false; + + } else { + + /* + * This could be a re-invite processing. check to see if the ack matches with the last + * transaction. s + */ + + SIPServerTransaction tr = getInviteTransaction(); + + SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null); + + // Idiot check for sending ACK from the wrong side! + if (tr != null + && sipResponse != null + && sipResponse.getStatusCode() / 100 == 2 + && sipResponse.getCSeq().getMethod().equals(Request.INVITE) + && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq() + .getSeqNumber()) { + + ackTransaction.setDialog(this, sipResponse.getDialogId(false)); + /* + * record that we already saw an ACK for this dialog. + */ + + ackReceived(sipRequest); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("ACK for 2XX response --- sending to TU "); + return true; + + } else { + /* + * This happens when the ACK is re-transmitted and arrives too late to be + * processed. + */ + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + " INVITE transaction not found -- Discarding ACK"); + return false; + } + } + } + + void setEarlyDialogId(String earlyDialogId) { + this.earlyDialogId = earlyDialogId; + } + + String getEarlyDialogId() { + return earlyDialogId; + } + + /** + * Release the semaphore for ACK processing so the next re-INVITE may proceed. + */ + void releaseAckSem() { + if (this.isBackToBackUserAgent) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("releaseAckSem]" + this); + } + this.ackSem.release(); + } + + } + + boolean takeAckSem() { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("[takeAckSem " + this); + } + try { + if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); + } + + if ( sipStack.isLoggingEnabled() ) { + sipStack.getStackLogger().logDebug("Semaphore previously acquired at " + this.stackTrace); + sipStack.getStackLogger().logStackTrace(); + + } + return false; + } + + if ( sipStack.isLoggingEnabled() ) { + + this.recordStackTrace(); + } + + } catch (InterruptedException ex) { + sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); + return false; + + } + return true; + + } + + /** + * @param lastAckReceived the lastAckReceived to set + */ + private void setLastAckReceived(SIPRequest lastAckReceived) { + this.lastAckReceived = lastAckReceived; + } + + /** + * @return the lastAckReceived + */ + protected SIPRequest getLastAckReceived() { + return lastAckReceived; + } + + /** + * @param lastAckSent the lastAckSent to set + */ + private void setLastAckSent(SIPRequest lastAckSent) { + this.lastAckSent = lastAckSent; + } + + /** + * @return true if an ack was ever sent for this Dialog + */ + public boolean isAtleastOneAckSent() { + return this.isAcknowledged; + } + + + + public boolean isBackToBackUserAgent() { + return this.isBackToBackUserAgent; + } + + public synchronized void doDeferredDeleteIfNoAckSent(long seqno) { + if (sipStack.getTimer() == null) { + this.setState(TERMINATED_STATE); + } else if(dialogDeleteIfNoAckSentTask == null){ + // Delete the transaction after the max ack timeout. + dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno); + sipStack.getTimer().schedule( + dialogDeleteIfNoAckSentTask, + SIPTransaction.TIMER_J + * SIPTransactionStack.BASE_TIMER_INTERVAL); + } + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.DialogExt#setBackToBackUserAgent(boolean) + */ + public void setBackToBackUserAgent() { + this.isBackToBackUserAgent = true; + } + + /** + * @return the eventHeader + */ + EventHeader getEventHeader() { + return eventHeader; + } + + /** + * @param eventHeader the eventHeader to set + */ + void setEventHeader(EventHeader eventHeader) { + this.eventHeader = eventHeader; + } + + /** + * @param serverTransactionFlag the serverTransactionFlag to set + */ + void setServerTransactionFlag(boolean serverTransactionFlag) { + this.serverTransactionFlag = serverTransactionFlag; + } + + /** + * @param reInviteFlag the reinviteFlag to set + */ + void setReInviteFlag(boolean reInviteFlag) { + this.reInviteFlag = reInviteFlag; + } + + + public boolean isSequnceNumberValidation() { + return this.sequenceNumberValidation; + } + + public void disableSequenceNumberValidation() { + this.sequenceNumberValidation = false; + } + + + public void acquireTimerTaskSem() { + boolean acquired = false; + try { + acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS); + } catch ( InterruptedException ex) { + acquired = false; + } + if(!acquired) { + throw new IllegalStateException("Impossible to acquire the dialog timer task lock"); + } + } + + public void releaseTimerTaskSem() { + this.timerTaskLock.release(); + } + + +} diff --git a/java/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java b/java/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java new file mode 100644 index 0000000..2b533f1 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java @@ -0,0 +1,73 @@ +/* + * This source code has been contributed to the public domain by Mobicents + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip.stack; + + +import java.util.EventObject; + +/** + * An event that indicates that a dialog has encountered an error. + * + * @author jean deruelle + * @since 2.0 + */ +public class SIPDialogErrorEvent extends EventObject { + + + /** + * This event ID indicates that the transaction has timed out. + */ + public static final int DIALOG_ACK_NOT_RECEIVED_TIMEOUT = 1; + + /** + * This event ID indicates that there was an error sending a message using + * the underlying transport. + */ + public static final int DIALOG_ACK_NOT_SENT_TIMEOUT = 2; + + /** + * This event ID indicates a timeout occured waiting to send re-INVITE ( for B2BUA) + */ + public static final int DIALOG_REINVITE_TIMEOUT = 3; + + + // ID of this error event + private int errorID; + + /** + * Creates a dialog error event. + * + * @param sourceDialog Dialog which is raising the error. + * @param dialogErrorID ID of the error that has ocurred. + */ + SIPDialogErrorEvent( + SIPDialog sourceDialog, + int dialogErrorID) { + + super(sourceDialog); + errorID = dialogErrorID; + + } + + /** + * Returns the ID of the error. + * + * @return Error ID. + */ + public int getErrorID() { + return errorID; + } +} diff --git a/java/gov/nist/javax/sip/stack/SIPDialogEventListener.java b/java/gov/nist/javax/sip/stack/SIPDialogEventListener.java new file mode 100644 index 0000000..98771d1 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPDialogEventListener.java @@ -0,0 +1,35 @@ +/* + * This source code has been contributed to the public domain by Mobicents + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement. + */ +package gov.nist.javax.sip.stack; + +import java.util.EventListener; + +/** + * Interface implemented by classes that want to be notified of asynchronous + * dialog events. + * + * @author jean deruelle + * @since 2.0 + */ +public interface SIPDialogEventListener extends EventListener { + + /** + * Invoked when an error has ocurred with a dialog. + * + * @param dialogErrorEvent Error event. + */ + public void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent); +} diff --git a/java/gov/nist/javax/sip/stack/SIPServerTransaction.java b/java/gov/nist/javax/sip/stack/SIPServerTransaction.java new file mode 100644 index 0000000..c5d6659 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPServerTransaction.java @@ -0,0 +1,1711 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.stack; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.ServerTransactionExt; +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.Utils; +import gov.nist.javax.sip.header.Expires; +import gov.nist.javax.sip.header.ParameterNames; +import gov.nist.javax.sip.header.RSeq; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.text.ParseException; +import java.util.TimerTask; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.sip.Dialog; +import javax.sip.DialogState; +import javax.sip.DialogTerminatedEvent; +import javax.sip.ObjectInUseException; +import javax.sip.SipException; +import javax.sip.Timeout; +import javax.sip.TimeoutEvent; +import javax.sip.TransactionState; +import javax.sip.address.Hop; +import javax.sip.header.ContactHeader; +import javax.sip.header.ExpiresHeader; +import javax.sip.header.RSeqHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Bug fixes / enhancements:Emil Ivov, Antonis Karydas, Daniel J. Martinez Manzano, Daniel, Hagai + * Sela, Vazques-Illa, Bill Roome, Thomas Froment and Pierre De Rop, Christophe Anzille and Jeroen + * van Bemmel, Frank Reif. + * Carolyn Beeton ( Avaya ). + * + */ + +/** + * Represents a server transaction. Implements the following state machines. + * + * <pre> + * + * + * + * |INVITE + * |pass INV to TU + * INVITE V send 100 if TU won't in 200ms + * send response+-----------+ + * +--------| |--------+101-199 from TU + * | | Proceeding| |send response + * +------->| |<-------+ + * | | Transport Err. + * | | Inform TU + * | |--------------->+ + * +-----------+ | + * 300-699 from TU | |2xx from TU | + * send response | |send response | + * | +------------------>+ + * | | + * INVITE V Timer G fires | + * send response+-----------+ send response | + * +--------| |--------+ | + * | | Completed | | | + * +------->| |<-------+ | + * +-----------+ | + * | | | + * ACK | | | + * - | +------------------>+ + * | Timer H fires | + * V or Transport Err.| + * +-----------+ Inform TU | + * | | | + * | Confirmed | | + * | | | + * +-----------+ | + * | | + * |Timer I fires | + * |- | + * | | + * V | + * +-----------+ | + * | | | + * | Terminated|<---------------+ + * | | + * +-----------+ + * + * Figure 7: INVITE server transaction + * Request received + * |pass to TU + * + * V + * +-----------+ + * | | + * | Trying |-------------+ + * | | | + * +-----------+ |200-699 from TU + * | |send response + * |1xx from TU | + * |send response | + * | | + * Request V 1xx from TU | + * send response+-----------+send response| + * +--------| |--------+ | + * | | Proceeding| | | + * +------->| |<-------+ | + * +<--------------| | | + * |Trnsprt Err +-----------+ | + * |Inform TU | | + * | | | + * | |200-699 from TU | + * | |send response | + * | Request V | + * | send response+-----------+ | + * | +--------| | | + * | | | Completed |<------------+ + * | +------->| | + * +<--------------| | + * |Trnsprt Err +-----------+ + * |Inform TU | + * | |Timer J fires + * | |- + * | | + * | V + * | +-----------+ + * | | | + * +-------------->| Terminated| + * | | + * +-----------+ + * + * + * + * + * + * </pre> + * + * @version 1.2 $Revision: 1.118 $ $Date: 2010/01/10 00:13:14 $ + * @author M. Ranganathan + * + */ +public class SIPServerTransaction extends SIPTransaction implements ServerRequestInterface, + javax.sip.ServerTransaction, ServerTransactionExt { + + // force the listener to see transaction + + private int rseqNumber; + + // private LinkedList pendingRequests; + + // Real RequestInterface to pass messages to + private transient ServerRequestInterface requestOf; + + private SIPDialog dialog; + + // the unacknowledged SIPResponse + + private SIPResponse pendingReliableResponse; + + // The pending reliable Response Timer + private ProvisionalResponseTask provisionalResponseTask; + + private boolean retransmissionAlertEnabled; + + private RetransmissionAlertTimerTask retransmissionAlertTimerTask; + + protected boolean isAckSeen; + + private SIPClientTransaction pendingSubscribeTransaction; + + private SIPServerTransaction inviteTransaction; + + private Semaphore provisionalResponseSem = new Semaphore(1); + + /** + * This timer task is used for alerting the application to send retransmission alerts. + * + * + */ + class RetransmissionAlertTimerTask extends SIPStackTimerTask { + + String dialogId; + + int ticks; + + int ticksLeft; + + public RetransmissionAlertTimerTask(String dialogId) { + + this.ticks = SIPTransaction.T1; + this.ticksLeft = this.ticks; + } + + protected void runTask() { + SIPServerTransaction serverTransaction = SIPServerTransaction.this; + ticksLeft--; + if (ticksLeft == -1) { + serverTransaction.fireRetransmissionTimer(); + this.ticksLeft = 2 * ticks; + } + + } + + } + + class ProvisionalResponseTask extends SIPStackTimerTask { + + int ticks; + + int ticksLeft; + + public ProvisionalResponseTask() { + this.ticks = SIPTransaction.T1; + this.ticksLeft = this.ticks; + } + + protected void runTask() { + SIPServerTransaction serverTransaction = SIPServerTransaction.this; + /* + * The reliable provisional response is passed to the transaction layer periodically + * with an interval that starts at T1 seconds and doubles for each retransmission (T1 + * is defined in Section 17 of RFC 3261). Once passed to the server transaction, it is + * added to an internal list of unacknowledged reliable provisional responses. The + * transaction layer will forward each retransmission passed from the UAS core. + * + * This differs from retransmissions of 2xx responses, whose intervals cap at T2 + * seconds. This is because retransmissions of ACK are triggered on receipt of a 2xx, + * but retransmissions of PRACK take place independently of reception of 1xx. + */ + // If the transaction has terminated, + if (serverTransaction.isTerminated()) { + + this.cancel(); + + } else { + ticksLeft--; + if (ticksLeft == -1) { + serverTransaction.fireReliableResponseRetransmissionTimer(); + this.ticksLeft = 2 * ticks; + this.ticks = this.ticksLeft; + // timer H MUST be set to fire in 64*T1 seconds for all transports. Timer H + // determines when the server + // transaction abandons retransmitting the response + if (this.ticksLeft >= SIPTransaction.TIMER_H) { + this.cancel(); + setState(TERMINATED_STATE); + fireTimeoutTimer(); + } + } + + } + + } + + } + + /** + * This timer task will terminate the transaction if the listener does not respond in a + * pre-determined time period. This helps prevent buggy listeners (who fail to respond) from + * causing memory leaks. This allows a container to protect itself from buggy code ( that + * fails to respond to a server transaction). + * + */ + class ListenerExecutionMaxTimer extends SIPStackTimerTask { + SIPServerTransaction serverTransaction = SIPServerTransaction.this; + + ListenerExecutionMaxTimer() { + } + + protected void runTask() { + try { + if (serverTransaction.getState() == null) { + serverTransaction.terminate(); + SIPTransactionStack sipStack = serverTransaction.getSIPStack(); + sipStack.removePendingTransaction(serverTransaction); + sipStack.removeTransaction(serverTransaction); + + } + } catch (Exception ex) { + sipStack.getStackLogger().logError("unexpected exception", ex); + } + } + } + + /** + * This timer task is for INVITE server transactions. It will send a trying in 200 ms. if the + * TU does not do so. + * + */ + class SendTrying extends SIPStackTimerTask { + + protected SendTrying() { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("scheduled timer for " + SIPServerTransaction.this); + + } + + protected void runTask() { + SIPServerTransaction serverTransaction = SIPServerTransaction.this; + + TransactionState realState = serverTransaction.getRealState(); + + if (realState == null || TransactionState.TRYING == realState) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug(" sending Trying current state = " + + serverTransaction.getRealState()); + try { + serverTransaction.sendMessage(serverTransaction.getOriginalRequest() + .createResponse(100, "Trying")); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug(" trying sent " + + serverTransaction.getRealState()); + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("IO error sending TRYING"); + } + } + + } + } + + class TransactionTimer extends SIPStackTimerTask { + + public TransactionTimer() { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("TransactionTimer() : " + getTransactionId()); + } + + } + + protected void runTask() { + // If the transaction has terminated, + if (isTerminated()) { + // Keep the transaction hanging around in the transaction table + // to catch the incoming ACK -- this is needed for tcp only. + // Note that the transaction record is actually removed in + // the connection linger timer. + try { + this.cancel(); + } catch (IllegalStateException ex) { + if (!sipStack.isAlive()) + return; + } + + // Oneshot timer that garbage collects the SeverTransaction + // after a scheduled amount of time. The linger timer allows + // the client side of the tx to use the same connection to + // send an ACK and prevents a race condition for creation + // of new server tx + TimerTask myTimer = new LingerTimer(); + + sipStack.getTimer().schedule(myTimer, + SIPTransactionStack.CONNECTION_LINGER_TIME * 1000); + + } else { + // Add to the fire list -- needs to be moved + // outside the synchronized block to prevent + // deadlock. + fireTimer(); + + } + } + + } + + /** + * Send a response. + * + * @param transactionResponse -- the response to send + * + */ + + private void sendResponse(SIPResponse transactionResponse) throws IOException { + + try { + // RFC18.2.2. Sending Responses + // The server transport uses the value of the top Via header field + // in + // order + // to determine where to send a response. + // It MUST follow the following process: + // If the "sent-protocol" is a reliable transport + // protocol such as TCP or SCTP, + // or TLS over those, the response MUST be + // sent using the existing connection + // to the source of the original request + // that created the transaction, if that connection is still open. + if (isReliable()) { + + getMessageChannel().sendMessage(transactionResponse); + + // TODO If that connection attempt fails, the server SHOULD + // use SRV 3263 procedures + // for servers in order to determine the IP address + // and port to open the connection and send the response to. + + } else { + Via via = transactionResponse.getTopmostVia(); + String transport = via.getTransport(); + if (transport == null) + throw new IOException("missing transport!"); + // @@@ hagai Symmetric NAT support + int port = via.getRPort(); + if (port == -1) + port = via.getPort(); + if (port == -1) { + if (transport.equalsIgnoreCase("TLS")) + port = 5061; + else + port = 5060; + } + + // Otherwise, if the Via header field value contains a + // "maddr" parameter, the response MUST be forwarded to + // the address listed there, using the port indicated in + // "sent-by", + // or port 5060 if none is present. If the address is a + // multicast + // address, the response SHOULD be sent using + // the TTL indicated in the "ttl" parameter, or with a + // TTL of 1 if that parameter is not present. + String host = null; + if (via.getMAddr() != null) { + host = via.getMAddr(); + } else { + // Otherwise (for unreliable unicast transports), + // if the top Via has a "received" parameter, the response + // MUST + // be sent to the + // address in the "received" parameter, using the port + // indicated + // in the + // "sent-by" value, or using port 5060 if none is specified + // explicitly. + host = via.getParameter(Via.RECEIVED); + if (host == null) { + // Otherwise, if it is not receiver-tagged, the response + // MUST be + // sent to the address indicated by the "sent-by" value, + // using the procedures in Section 5 + // RFC 3263 PROCEDURE TO BE DONE HERE + host = via.getHost(); + } + } + + Hop hop = sipStack.addressResolver.resolveAddress(new HopImpl(host, port, + transport)); + + MessageChannel messageChannel = ((SIPTransactionStack) getSIPStack()) + .createRawMessageChannel(this.getSipProvider().getListeningPoint( + hop.getTransport()).getIPAddress(), this.getPort(), hop); + if (messageChannel != null) + messageChannel.sendMessage(transactionResponse); + else + throw new IOException("Could not create a message channel for " + hop); + + } + } finally { + this.startTransactionTimer(); + } + } + + /** + * Creates a new server transaction. + * + * @param sipStack Transaction stack this transaction belongs to. + * @param newChannelToUse Channel to encapsulate. + */ + protected SIPServerTransaction(SIPTransactionStack sipStack, MessageChannel newChannelToUse) { + + super(sipStack, newChannelToUse); + + if (sipStack.maxListenerResponseTime != -1) { + sipStack.getTimer().schedule(new ListenerExecutionMaxTimer(), + sipStack.maxListenerResponseTime * 1000); + } + + this.rseqNumber = (int) (Math.random() * 1000); + // Only one outstanding request for a given server tx. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Creating Server Transaction" + this.getBranchId()); + sipStack.getStackLogger().logStackTrace(); + } + + } + + /** + * Sets the real RequestInterface this transaction encapsulates. + * + * @param newRequestOf RequestInterface to send messages to. + */ + public void setRequestInterface(ServerRequestInterface newRequestOf) { + + requestOf = newRequestOf; + + } + + /** + * Returns this transaction. + */ + public MessageChannel getResponseChannel() { + + return this; + + } + + + + /** + * Determines if the message is a part of this transaction. + * + * @param messageToTest Message to check if it is part of this transaction. + * + * @return True if the message is part of this transaction, false if not. + */ + public boolean isMessagePartOfTransaction(SIPMessage messageToTest) { + + // List of Via headers in the message to test + ViaList viaHeaders; + // Topmost Via header in the list + Via topViaHeader; + // Branch code in the topmost Via header + String messageBranch; + // Flags whether the select message is part of this transaction + boolean transactionMatches; + + transactionMatches = false; + + String method = messageToTest.getCSeq().getMethod(); + // Invite Server transactions linger in the terminated state in the + // transaction + // table and are matched to compensate for + // http://bugs.sipit.net/show_bug.cgi?id=769 + if ((method.equals(Request.INVITE) || !isTerminated())) { + + // Get the topmost Via header and its branch parameter + viaHeaders = messageToTest.getViaHeaders(); + if (viaHeaders != null) { + + topViaHeader = (Via) viaHeaders.getFirst(); + messageBranch = topViaHeader.getBranch(); + if (messageBranch != null) { + + // If the branch parameter exists but + // does not start with the magic cookie, + if (!messageBranch.toLowerCase().startsWith( + SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { + + // Flags this as old + // (RFC2543-compatible) client + // version + messageBranch = null; + + } + + } + + // If a new branch parameter exists, + if (messageBranch != null && this.getBranch() != null) { + if (method.equals(Request.CANCEL)) { + // Cancel is handled as a special case because it + // shares the same same branch id of the invite + // that it is trying to cancel. + transactionMatches = this.getMethod().equals(Request.CANCEL) + && getBranch().equalsIgnoreCase(messageBranch) + && topViaHeader.getSentBy().equals( + ((Via) getOriginalRequest().getViaHeaders().getFirst()) + .getSentBy()); + + } else { + // Matching server side transaction with only the + // branch parameter. + transactionMatches = getBranch().equalsIgnoreCase(messageBranch) + && topViaHeader.getSentBy().equals( + ((Via) getOriginalRequest().getViaHeaders().getFirst()) + .getSentBy()); + + } + + } else { + // This is an RFC2543-compliant message; this code is here + // for backwards compatibility. + // It is a weak check. + // If RequestURI, To tag, From tag, CallID, CSeq number, and + // top Via headers are the same, the + // SIPMessage matches this transaction. An exception is for + // a CANCEL request, which is not deemed + // to be part of an otherwise-matching INVITE transaction. + String originalFromTag = super.fromTag; + + String thisFromTag = messageToTest.getFrom().getTag(); + + boolean skipFrom = (originalFromTag == null || thisFromTag == null); + + String originalToTag = super.toTag; + + String thisToTag = messageToTest.getTo().getTag(); + + boolean skipTo = (originalToTag == null || thisToTag == null); + boolean isResponse = (messageToTest instanceof SIPResponse); + // Issue #96: special case handling for a CANCEL request - + // the CSeq method of the original request must + // be CANCEL for it to have a chance at matching. + if (messageToTest.getCSeq().getMethod().equalsIgnoreCase(Request.CANCEL) + && !getOriginalRequest().getCSeq().getMethod().equalsIgnoreCase( + Request.CANCEL)) { + transactionMatches = false; + } else if ((isResponse || getOriginalRequest().getRequestURI().equals( + ((SIPRequest) messageToTest).getRequestURI())) + && (skipFrom || originalFromTag != null && originalFromTag.equalsIgnoreCase(thisFromTag)) + && (skipTo || originalToTag != null && originalToTag.equalsIgnoreCase(thisToTag)) + && getOriginalRequest().getCallId().getCallId().equalsIgnoreCase( + messageToTest.getCallId().getCallId()) + && getOriginalRequest().getCSeq().getSeqNumber() == messageToTest + .getCSeq().getSeqNumber() + && ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) || getOriginalRequest() + .getMethod().equals(messageToTest.getCSeq().getMethod())) + && topViaHeader.equals(getOriginalRequest().getViaHeaders() + .getFirst())) { + + transactionMatches = true; + } + + } + + } + + } + return transactionMatches; + + } + + /** + * Send out a trying response (only happens when the transaction is mapped). Otherwise the + * transaction is not known to the stack. + */ + protected void map() { + // note that TRYING is a pseudo-state for invite transactions + + TransactionState realState = getRealState(); + + if (realState == null || realState == TransactionState.TRYING) { + // JvB: Removed the condition 'dialog!=null'. Trying should also + // be + // sent by intermediate proxies. This fixes some TCK tests + // null check added as the stack may be stopped. + if (isInviteTransaction() && !this.isMapped && sipStack.getTimer() != null) { + this.isMapped = true; + // Schedule a timer to fire in 200 ms if the + // TU did not send a trying in that time. + sipStack.getTimer().schedule(new SendTrying(), 200); + + } else { + isMapped = true; + } + } + + // Pull it out of the pending transactions list. + sipStack.removePendingTransaction(this); + } + + /** + * Return true if the transaction is known to stack. + */ + public boolean isTransactionMapped() { + return this.isMapped; + } + + /** + * Process a new request message through this transaction. If necessary, this message will + * also be passed onto the TU. + * + * @param transactionRequest Request to process. + * @param sourceChannel Channel that received this message. + */ + public void processRequest(SIPRequest transactionRequest, MessageChannel sourceChannel) { + boolean toTu = false; + + // Can only process a single request directed to the + // transaction at a time. For a given server transaction + // the listener sees only one event at a time. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("processRequest: " + transactionRequest.getFirstLine()); + sipStack.getStackLogger().logDebug("tx state = " + this.getRealState()); + } + + try { + + // If this is the first request for this transaction, + if (getRealState() == null) { + // Save this request as the one this + // transaction is handling + setOriginalRequest(transactionRequest); + this.setState(TransactionState.TRYING); + toTu = true; + this.setPassToListener(); + + // Rsends the TRYING on retransmission of the request. + if (isInviteTransaction() && this.isMapped) { + // JvB: also + // proxies need + // to do this + + // Has side-effect of setting + // state to "Proceeding" + sendMessage(transactionRequest.createResponse(100, "Trying")); + + } + // If an invite transaction is ACK'ed while in + // the completed state, + } else if (isInviteTransaction() && TransactionState.COMPLETED == getRealState() + && transactionRequest.getMethod().equals(Request.ACK)) { + + // @jvB bug fix + this.setState(TransactionState.CONFIRMED); + disableRetransmissionTimer(); + if (!isReliable()) { + enableTimeoutTimer(TIMER_I); + + } else { + + this.setState(TransactionState.TERMINATED); + + } + + // JvB: For the purpose of testing a TI, added a property to + // pass it anyway + if (sipStack.isNon2XXAckPassedToListener()) { + // This is useful for test applications that want to see + // all messages. + requestOf.processRequest(transactionRequest, this); + } else { + // According to RFC3261 Application should not Ack in + // CONFIRMED state + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("ACK received for server Tx " + + this.getTransactionId() + " not delivering to application!"); + + } + + this.semRelease(); + } + return; + + // If we receive a retransmission of the original + // request, + } else if (transactionRequest.getMethod().equals(getOriginalRequest().getMethod())) { + + if (TransactionState.PROCEEDING == getRealState() + || TransactionState.COMPLETED == getRealState()) { + this.semRelease(); + // Resend the last response to + // the client + if (lastResponse != null) { + + // Send the message to the client + super.sendMessage(lastResponse); + + } + } else if (transactionRequest.getMethod().equals(Request.ACK)) { + // This is passed up to the TU to suppress + // retransmission of OK + if (requestOf != null) + requestOf.processRequest(transactionRequest, this); + else + this.semRelease(); + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("completed processing retransmitted request : " + + transactionRequest.getFirstLine() + this + " txState = " + + this.getState() + " lastResponse = " + this.getLastResponse()); + return; + + } + + // Pass message to the TU + if (TransactionState.COMPLETED != getRealState() + && TransactionState.TERMINATED != getRealState() && requestOf != null) { + if (getOriginalRequest().getMethod().equals(transactionRequest.getMethod())) { + // Only send original request to TU once! + if (toTu) { + requestOf.processRequest(transactionRequest, this); + } else + this.semRelease(); + } else { + if (requestOf != null) + requestOf.processRequest(transactionRequest, this); + else + this.semRelease(); + } + } else { + // This seems like a common bug so I am allowing it through! + if (((SIPTransactionStack) getSIPStack()).isDialogCreated(getOriginalRequest() + .getMethod()) + && getRealState() == TransactionState.TERMINATED + && transactionRequest.getMethod().equals(Request.ACK) + && requestOf != null) { + SIPDialog thisDialog = (SIPDialog) this.dialog; + + if (thisDialog == null || !thisDialog.ackProcessed) { + // Filter out duplicate acks + if (thisDialog != null) { + thisDialog.ackReceived(transactionRequest); + thisDialog.ackProcessed = true; + } + requestOf.processRequest(transactionRequest, this); + } else { + this.semRelease(); + } + + } else if (transactionRequest.getMethod().equals(Request.CANCEL)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Too late to cancel Transaction"); + this.semRelease(); + // send OK and just ignore the CANCEL. + try { + this.sendMessage(transactionRequest.createResponse(Response.OK)); + } catch (IOException ex) { + // Transaction is already terminated + // just ignore the IOException. + } + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Dropping request " + getRealState()); + } + + } catch (IOException e) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logError("IOException " ,e); + this.semRelease(); + this.raiseIOExceptionEvent(); + } + + } + + /** + * Send a response message through this transactionand onto the client. The response drives + * the state machine. + * + * @param messageToSend Response to process and send. + */ + public void sendMessage(SIPMessage messageToSend) throws IOException { + try { + // Message typecast as a response + SIPResponse transactionResponse; + // Status code of the response being sent to the client + int statusCode; + + // Get the status code from the response + transactionResponse = (SIPResponse) messageToSend; + statusCode = transactionResponse.getStatusCode(); + + try { + // Provided we have set the banch id for this we set the BID for + // the + // outgoing via. + if (this.getOriginalRequest().getTopmostVia().getBranch() != null) + transactionResponse.getTopmostVia().setBranch(this.getBranch()); + else + transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH); + + // Make the topmost via headers match identically for the + // transaction rsponse. + if (!this.getOriginalRequest().getTopmostVia().hasPort()) + transactionResponse.getTopmostVia().removePort(); + } catch (ParseException ex) { + ex.printStackTrace(); + } + + // Method of the response does not match the request used to + // create the transaction - transaction state does not change. + if (!transactionResponse.getCSeq().getMethod().equals( + getOriginalRequest().getMethod())) { + sendResponse(transactionResponse); + return; + } + + // If the TU sends a provisional response while in the + // trying state, + + if (getRealState() == TransactionState.TRYING) { + if (statusCode / 100 == 1) { + this.setState(TransactionState.PROCEEDING); + } else if (200 <= statusCode && statusCode <= 699) { + // INVITE ST has TRYING as a Pseudo state + // (See issue 76). We are using the TRYING + // pseudo state invite Transactions + // to signal if the application + // has sent trying or not and hence this + // check is necessary. + if (!isInviteTransaction()) { + if (!isReliable()) { + // Linger in the completed state to catch + // retransmissions if the transport is not + // reliable. + this.setState(TransactionState.COMPLETED); + // Note that Timer J is only set for Unreliable + // transports -- see Issue 75. + /* + * From RFC 3261 Section 17.2.2 (non-invite server transaction) + * + * When the server transaction enters the "Completed" state, it MUST + * set Timer J to fire in 64*T1 seconds for unreliable transports, and + * zero seconds for reliable transports. While in the "Completed" + * state, the server transaction MUST pass the final response to the + * transport layer for retransmission whenever a retransmission of the + * request is received. Any other final responses passed by the TU to + * the server transaction MUST be discarded while in the "Completed" + * state. The server transaction remains in this state until Timer J + * fires, at which point it MUST transition to the "Terminated" state. + */ + enableTimeoutTimer(TIMER_J); + } else { + this.setState(TransactionState.TERMINATED); + } + } else { + // This is the case for INVITE server transactions. + // essentially, it duplicates the code in the + // PROCEEDING case below. There is no TRYING state for INVITE + // transactions in the RFC. We are using it to signal whether the + // application has sent a provisional response or not. Hence + // this is treated the same as as Proceeding. + if (statusCode / 100 == 2) { + // Status code is 2xx means that the + // transaction transitions to TERMINATED + // for both Reliable as well as unreliable + // transports. Note that the dialog layer + // takes care of retransmitting 2xx final + // responses. + /* + * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server + * transaction will be destroyed as soon as it receives this final + * response and passes it to the transport. Therefore, it is necessary + * to periodically pass the response directly to the transport until + * the ACK arrives. The 2xx response is passed to the transport with + * an interval that starts at T1 seconds and doubles for each + * retransmission until it reaches T2 seconds (T1 and T2 are defined + * in Section 17). Response retransmissions cease when an ACK request + * for the response is received. This is independent of whatever + * transport protocols are used to send the response. + */ + this.disableRetransmissionTimer(); + this.disableTimeoutTimer(); + this.collectionTime = TIMER_J; + this.setState(TransactionState.TERMINATED); + if (this.dialog != null) + this.dialog.setRetransmissionTicks(); + } else { + // This an error final response. + this.setState(TransactionState.COMPLETED); + if (!isReliable()) { + /* + * RFC 3261 + * + * While in the "Proceeding" state, if the TU passes a response + * with status code from 300 to 699 to the server transaction, the + * response MUST be passed to the transport layer for + * transmission, and the state machine MUST enter the "Completed" + * state. For unreliable transports, timer G is set to fire in T1 + * seconds, and is not set to fire for reliable transports. + */ + + enableRetransmissionTimer(); + + } + enableTimeoutTimer(TIMER_H); + } + } + + } + + // If the transaction is in the proceeding state, + } else if (getRealState() == TransactionState.PROCEEDING) { + + if (isInviteTransaction()) { + + // If the response is a failure message, + if (statusCode / 100 == 2) { + // Set up to catch returning ACKs + // The transaction lingers in the + // terminated state for some time + // to catch retransmitted INVITEs + this.disableRetransmissionTimer(); + this.disableTimeoutTimer(); + this.collectionTime = TIMER_J; + this.setState(TransactionState.TERMINATED); + if (this.dialog != null) + this.dialog.setRetransmissionTicks(); + + } else if (300 <= statusCode && statusCode <= 699) { + + // Set up to catch returning ACKs + this.setState(TransactionState.COMPLETED); + if (!isReliable()) { + /* + * While in the "Proceeding" state, if the TU passes a response with + * status code from 300 to 699 to the server transaction, the response + * MUST be passed to the transport layer for transmission, and the + * state machine MUST enter the "Completed" state. For unreliable + * transports, timer G is set to fire in T1 seconds, and is not set to + * fire for reliable transports. + */ + + enableRetransmissionTimer(); + + } + enableTimeoutTimer(TIMER_H); + + } + + // If the transaction is not an invite transaction + // and this is a final response, + } else if (200 <= statusCode && statusCode <= 699) { + // This is for Non-invite server transactions. + + // Set up to retransmit this response, + // or terminate the transaction + this.setState(TransactionState.COMPLETED); + if (!isReliable()) { + + disableRetransmissionTimer(); + enableTimeoutTimer(TIMER_J); + + } else { + + this.setState(TransactionState.TERMINATED); + + } + + } + + // If the transaction has already completed, + } else if (TransactionState.COMPLETED == this.getRealState()) { + + return; + } + + try { + // Send the message to the client. + // Record the last message sent out. + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "sendMessage : tx = " + this + " getState = " + this.getState()); + } + lastResponse = transactionResponse; + this.sendResponse(transactionResponse); + + } catch (IOException e) { + + this.setState(TransactionState.TERMINATED); + this.collectionTime = 0; + throw e; + + } + } finally { + this.startTransactionTimer(); + } + + } + + public String getViaHost() { + + return getMessageChannel().getViaHost(); + + } + + public int getViaPort() { + + return getMessageChannel().getViaPort(); + + } + + /** + * Called by the transaction stack when a retransmission timer fires. This retransmits the + * last response when the retransmission filter is enabled. + */ + protected void fireRetransmissionTimer() { + + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("fireRetransmissionTimer() -- "); + } + // Resend the last response sent by this transaction + if (isInviteTransaction() && lastResponse != null) { + // null can happen if this is terminating when the timer fires. + if (!this.retransmissionAlertEnabled || sipStack.isTransactionPendingAck(this) ) { + // Retransmit last response until ack. + if (lastResponse.getStatusCode() / 100 > 2 && !this.isAckSeen) + super.sendMessage(lastResponse); + } else { + // alert the application to retransmit the last response + SipProviderImpl sipProvider = (SipProviderImpl) this.getSipProvider(); + TimeoutEvent txTimeout = new TimeoutEvent(sipProvider, this, + Timeout.RETRANSMIT); + sipProvider.handleEvent(txTimeout, this); + } + + } + } catch (IOException e) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(e); + raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); + + } + + } + + private void fireReliableResponseRetransmissionTimer() { + try { + + super.sendMessage(this.pendingReliableResponse); + + } catch (IOException e) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(e); + this.setState(TransactionState.TERMINATED); + raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); + + } + } + + /** + * Called by the transaction stack when a timeout timer fires. + */ + protected void fireTimeoutTimer() { + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("SIPServerTransaction.fireTimeoutTimer this = " + this + + " current state = " + this.getRealState() + " method = " + + this.getOriginalRequest().getMethod()); + + if ( this.getMethod().equals(Request.INVITE) && sipStack.removeTransactionPendingAck(this) ) { + if ( sipStack.isLoggingEnabled() ) { + sipStack.getStackLogger().logDebug("Found tx pending ACK - returning"); + } + return; + + } + SIPDialog dialog = (SIPDialog) this.dialog; + if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this.getOriginalRequest() + .getMethod()) + && (TransactionState.CALLING == this.getRealState() || TransactionState.TRYING == this + .getRealState())) { + dialog.setState(SIPDialog.TERMINATED_STATE); + } else if (getOriginalRequest().getMethod().equals(Request.BYE)) { + if (dialog != null && dialog.isTerminatedOnBye()) + dialog.setState(SIPDialog.TERMINATED_STATE); + } + + if (TransactionState.COMPLETED == this.getRealState() && isInviteTransaction()) { + raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); + this.setState(TransactionState.TERMINATED); + sipStack.removeTransaction(this); + + } else if (TransactionState.COMPLETED == this.getRealState() && !isInviteTransaction()) { + this.setState(TransactionState.TERMINATED); + sipStack.removeTransaction(this); + + } else if (TransactionState.CONFIRMED == this.getRealState() && isInviteTransaction()) { + // TIMER_I should not generate a timeout + // exception to the application when the + // Invite transaction is in Confirmed state. + // Just transition to Terminated state. + this.setState(TransactionState.TERMINATED); + sipStack.removeTransaction(this); + } else if (!isInviteTransaction() + && (TransactionState.COMPLETED == this.getRealState() || TransactionState.CONFIRMED == this + .getRealState())) { + this.setState(TransactionState.TERMINATED); + } else if (isInviteTransaction() && TransactionState.TERMINATED == this.getRealState()) { + // This state could be reached when retransmitting + + raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); + if (dialog != null) + dialog.setState(SIPDialog.TERMINATED_STATE); + } + + } + + /** + * Get the last response. + */ + public SIPResponse getLastResponse() { + return this.lastResponse; + } + + /** + * Set the original request. + */ + public void setOriginalRequest(SIPRequest originalRequest) { + super.setOriginalRequest(originalRequest); + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.ServerTransaction#sendResponse(javax.sip.message.Response) + */ + public void sendResponse(Response response) throws SipException { + SIPResponse sipResponse = (SIPResponse) response; + + SIPDialog dialog = this.dialog; + if (response == null) + throw new NullPointerException("null response"); + + try { + sipResponse.checkHeaders(); + } catch (ParseException ex) { + throw new SipException(ex.getMessage()); + } + + // check for meaningful response. + if (!sipResponse.getCSeq().getMethod().equals(this.getMethod())) { + throw new SipException( + "CSeq method does not match Request method of request that created the tx."); + } + + /* + * 200-class responses to SUBSCRIBE requests also MUST contain an "Expires" header. The + * period of time in the response MAY be shorter but MUST NOT be longer than specified in + * the request. + */ + if (this.getMethod().equals(Request.SUBSCRIBE) && response.getStatusCode() / 100 == 2) { + + if (response.getHeader(ExpiresHeader.NAME) == null) { + throw new SipException("Expires header is mandatory in 2xx response of SUBSCRIBE"); + } else { + Expires requestExpires = (Expires) this.getOriginalRequest().getExpires(); + Expires responseExpires = (Expires) response.getExpires(); + /* + * If no "Expires" header is present in a SUBSCRIBE request, the implied default + * is defined by the event package being used. + */ + if (requestExpires != null + && responseExpires.getExpires() > requestExpires.getExpires()) { + throw new SipException( + "Response Expires time exceeds request Expires time : See RFC 3265 3.1.1"); + } + } + + } + + // Check for mandatory header. + if (sipResponse.getStatusCode() == 200 + && sipResponse.getCSeq().getMethod().equals(Request.INVITE) + && sipResponse.getHeader(ContactHeader.NAME) == null) + throw new SipException("Contact Header is mandatory for the OK to the INVITE"); + + if (!this.isMessagePartOfTransaction((SIPMessage) response)) { + throw new SipException("Response does not belong to this transaction."); + } + + // Fix up the response if the dialog has already been established. + try { + /* + * The UAS MAY send a final response to the initial request before + * having received PRACKs for all unacknowledged reliable provisional responses, + * unless the final response is 2xx and any of the unacknowledged reliable provisional + * responses contained a session description. In that case, it MUST NOT send a final + * response until those provisional responses are acknowledged. + */ + if (this.pendingReliableResponse != null + && this.getDialog() != null + && this.getState() != TransactionState.TERMINATED + && ((SIPResponse)response).getContentTypeHeader() != null + && response.getStatusCode() / 100 == 2 + && ((SIPResponse)response).getContentTypeHeader().getContentType() + .equalsIgnoreCase("application") + && ((SIPResponse)response).getContentTypeHeader().getContentSubType() + .equalsIgnoreCase("sdp")) { + try { + boolean acquired = this.provisionalResponseSem.tryAcquire(1,TimeUnit.SECONDS); + if (!acquired ) { + throw new SipException("cannot send response -- unacked povisional"); + } + } catch (Exception ex) { + this.sipStack.getStackLogger().logError("Could not acquire PRACK sem ", ex); + } + } else { + // Sending the final response cancels the + // pending response task. + if (this.pendingReliableResponse != null && sipResponse.isFinalResponse()) { + this.provisionalResponseTask.cancel(); + this.provisionalResponseTask = null; + } + } + + // Dialog checks. These make sure that the response + // being sent makes sense. + if (dialog != null) { + if (sipResponse.getStatusCode() / 100 == 2 + && sipStack.isDialogCreated(sipResponse.getCSeq().getMethod())) { + if (dialog.getLocalTag() == null && sipResponse.getTo().getTag() == null) { + // Trying to send final response and user forgot to set + // to + // tag on the response -- be nice and assign the tag for + // the user. + sipResponse.getTo().setTag(Utils.getInstance().generateTag()); + } else if (dialog.getLocalTag() != null && sipResponse.getToTag() == null) { + sipResponse.setToTag(dialog.getLocalTag()); + } else if (dialog.getLocalTag() != null && sipResponse.getToTag() != null + && !dialog.getLocalTag().equals(sipResponse.getToTag())) { + throw new SipException("Tag mismatch dialogTag is " + + dialog.getLocalTag() + " responseTag is " + + sipResponse.getToTag()); + } + } + + if (!sipResponse.getCallId().getCallId().equals(dialog.getCallId().getCallId())) { + throw new SipException("Dialog mismatch!"); + } + } + + + + // Backward compatibility slippery slope.... + // Only set the from tag in the response when the + // incoming request has a from tag. + String fromTag = ((SIPRequest) this.getRequest()).getFrom().getTag(); + if (fromTag != null && sipResponse.getFromTag() != null + && !sipResponse.getFromTag().equals(fromTag)) { + throw new SipException("From tag of request does not match response from tag"); + } else if (fromTag != null) { + sipResponse.getFrom().setTag(fromTag); + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("WARNING -- Null From tag in request!!"); + } + + + + // See if the dialog needs to be inserted into the dialog table + // or if the state of the dialog needs to be changed. + if (dialog != null && response.getStatusCode() != 100) { + dialog.setResponseTags(sipResponse); + DialogState oldState = dialog.getState(); + dialog.setLastResponse(this, (SIPResponse) response); + if (oldState == null && dialog.getState() == DialogState.TERMINATED) { + DialogTerminatedEvent event = new DialogTerminatedEvent(dialog + .getSipProvider(), dialog); + + // Provide notification to the listener that the dialog has + // ended. + dialog.getSipProvider().handleEvent(event, this); + + } + + } else if (dialog == null && this.getMethod().equals(Request.INVITE) + && this.retransmissionAlertEnabled + && this.retransmissionAlertTimerTask == null + && response.getStatusCode() / 100 == 2) { + String dialogId = ((SIPResponse) response).getDialogId(true); + + this.retransmissionAlertTimerTask = new RetransmissionAlertTimerTask(dialogId); + sipStack.retransmissionAlertTransactions.put(dialogId, this); + sipStack.getTimer().schedule(this.retransmissionAlertTimerTask, 0, + SIPTransactionStack.BASE_TIMER_INTERVAL); + + } + + // Send message after possibly inserting the Dialog + // into the dialog table to avoid a possible race condition. + + this.sendMessage((SIPResponse) response); + + if ( dialog != null ) { + dialog.startRetransmitTimer(this, (SIPResponse)response); + } + + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + this.setState(TransactionState.TERMINATED); + raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); + throw new SipException(ex.getMessage()); + } catch (java.text.ParseException ex1) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex1); + this.setState(TransactionState.TERMINATED); + throw new SipException(ex1.getMessage()); + } + } + + /** + * Return the book-keeping information that we actually use. + */ + private TransactionState getRealState() { + return super.getState(); + } + + /** + * Return the current transaction state according to the RFC 3261 transaction state machine. + * Invite transactions do not have a trying state. We just use this as a pseudo state for + * processing requests. + * + * @return the state of the transaction. + */ + public TransactionState getState() { + // Trying is a pseudo state for INVITE transactions. + if (this.isInviteTransaction() && TransactionState.TRYING == super.getState()) + return TransactionState.PROCEEDING; + else + return super.getState(); + } + + /** + * Sets a timeout after which the connection is closed (provided the server does not use the + * connection for outgoing requests in this time period) and calls the superclass to set + * state. + */ + public void setState(TransactionState newState) { + // Set this timer for connection caching + // of incoming connections. + if (newState == TransactionState.TERMINATED && this.isReliable() + && (!getSIPStack().cacheServerConnections)) { + // Set a time after which the connection + // is closed. + this.collectionTime = TIMER_J; + } + + super.setState(newState); + + } + + /** + * Start the timer task. + */ + protected void startTransactionTimer() { + if (this.transactionTimerStarted.compareAndSet(false, true)) { + if (sipStack.getTimer() != null) { + // The timer is set to null when the Stack is + // shutting down. + TimerTask myTimer = new TransactionTimer(); + sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL); + } + } + } + + public boolean equals(Object other) { + if (!other.getClass().equals(this.getClass())) { + return false; + } + SIPServerTransaction sst = (SIPServerTransaction) other; + return this.getBranch().equalsIgnoreCase(sst.getBranch()); + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.SIPTransaction#getDialog() + */ + public Dialog getDialog() { + + return this.dialog; + } + + /* + * (non-Javadoc) + * + * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, + * gov.nist.javax.sip.message.SIPMessage) + */ + public void setDialog(SIPDialog sipDialog, String dialogId) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("setDialog " + this + " dialog = " + sipDialog); + this.dialog = sipDialog; + if (dialogId != null) + this.dialog.setAssigned(); + if (this.retransmissionAlertEnabled && this.retransmissionAlertTimerTask != null) { + this.retransmissionAlertTimerTask.cancel(); + if (this.retransmissionAlertTimerTask.dialogId != null) { + sipStack.retransmissionAlertTransactions + .remove(this.retransmissionAlertTimerTask.dialogId); + } + this.retransmissionAlertTimerTask = null; + } + + this.retransmissionAlertEnabled = false; + + } + + /* + * (non-Javadoc) + * + * @see javax.sip.Transaction#terminate() + */ + public void terminate() throws ObjectInUseException { + this.setState(TransactionState.TERMINATED); + if (this.retransmissionAlertTimerTask != null) { + this.retransmissionAlertTimerTask.cancel(); + if (retransmissionAlertTimerTask.dialogId != null) { + this.sipStack.retransmissionAlertTransactions + .remove(retransmissionAlertTimerTask.dialogId); + } + this.retransmissionAlertTimerTask = null; + + } + + } + + protected void sendReliableProvisionalResponse(Response relResponse) throws SipException { + + /* + * After the first reliable provisional response for a request has been acknowledged, the + * UAS MAY send additional reliable provisional responses. The UAS MUST NOT send a second + * reliable provisional response until the first is acknowledged. + */ + if (this.pendingReliableResponse != null) { + throw new SipException("Unacknowledged response"); + + } else + this.pendingReliableResponse = (SIPResponse) relResponse; + /* + * In addition, it MUST contain a Require header field containing the option tag 100rel, + * and MUST include an RSeq header field. + */ + RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME); + if (relResponse.getHeader(RSeqHeader.NAME) == null) { + rseq = new RSeq(); + relResponse.setHeader(rseq); + } + + try { + this.rseqNumber++; + rseq.setSeqNumber(this.rseqNumber); + + // start the timer task which will retransmit the reliable response + // until the PRACK is received + this.lastResponse = (SIPResponse) relResponse; + if ( this.getDialog() != null ) { + boolean acquired = this.provisionalResponseSem.tryAcquire(1, TimeUnit.SECONDS); + if (!acquired) { + throw new SipException("Unacknowledged response"); + } + } + this.sendMessage((SIPMessage) relResponse); + this.provisionalResponseTask = new ProvisionalResponseTask(); + this.sipStack.getTimer().schedule(provisionalResponseTask, 0, + SIPTransactionStack.BASE_TIMER_INTERVAL); + + + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + + } + + public SIPResponse getReliableProvisionalResponse() { + + return this.pendingReliableResponse; + } + + /** + * Cancel the retransmit timer for the provisional response task. + * + * @return true if the tx has seen the prack for the first time and false otherwise. + * + */ + public boolean prackRecieved() { + + if (this.pendingReliableResponse == null) + return false; + if(provisionalResponseTask != null) + this.provisionalResponseTask.cancel(); + this.pendingReliableResponse = null; + this.provisionalResponseSem.release(); + return true; + } + + /* + * (non-Javadoc) + * + * @see javax.sip.ServerTransaction#enableRetransmissionAlerts() + */ + + public void enableRetransmissionAlerts() throws SipException { + if (this.getDialog() != null) + throw new SipException("Dialog associated with tx"); + + else if (!this.getMethod().equals(Request.INVITE)) + throw new SipException("Request Method must be INVITE"); + + this.retransmissionAlertEnabled = true; + + } + + public boolean isRetransmissionAlertEnabled() { + return this.retransmissionAlertEnabled; + } + + /** + * Disable retransmission Alerts and cancel associated timers. + * + */ + public void disableRetransmissionAlerts() { + if (this.retransmissionAlertTimerTask != null && this.retransmissionAlertEnabled) { + this.retransmissionAlertTimerTask.cancel(); + this.retransmissionAlertEnabled = false; + + String dialogId = this.retransmissionAlertTimerTask.dialogId; + if (dialogId != null) { + sipStack.retransmissionAlertTransactions.remove(dialogId); + } + this.retransmissionAlertTimerTask = null; + } + } + + /** + * This is book-keeping for retransmission filter management. + */ + public void setAckSeen() { + this.isAckSeen = true; + } + + /** + * This is book-keeping for retransmission filter management. + */ + public boolean ackSeen() { + return this.isAckSeen; + } + + public void setMapped(boolean b) { + this.isMapped = true; + + } + + public void setPendingSubscribe(SIPClientTransaction pendingSubscribeClientTx) { + this.pendingSubscribeTransaction = pendingSubscribeClientTx; + + } + + public void releaseSem() { + if (this.pendingSubscribeTransaction != null) { + /* + * When a notify is being processed we take a lock on the subscribe to avoid racing + * with the OK of the subscribe. + */ + pendingSubscribeTransaction.releaseSem(); + } else if (this.inviteTransaction != null && this.getMethod().equals(Request.CANCEL)) { + /* + * When a CANCEL is being processed we take a nested lock on the associated INVITE + * server tx. + */ + this.inviteTransaction.releaseSem(); + } + super.releaseSem(); + } + + /** + * The INVITE Server Transaction corresponding to a CANCEL Server Transaction. + * + * @param st -- the invite server tx corresponding to the cancel server transaction. + */ + public void setInviteTransaction(SIPServerTransaction st) { + this.inviteTransaction = st; + + } + + /** + * TODO -- this method has to be added to the api. + * + * @return + */ + public SIPServerTransaction getCanceledInviteTransaction() { + return this.inviteTransaction; + } + + public void scheduleAckRemoval() throws IllegalStateException { + if (this.getMethod() == null || !this.getMethod().equals(Request.ACK)) { + throw new IllegalStateException("Method is null[" + (getMethod() == null) + + "] or method is not ACK[" + this.getMethod() + "]"); + } + + this.startTransactionTimer(); + } + +} diff --git a/java/gov/nist/javax/sip/stack/SIPStackTimerTask.java b/java/gov/nist/javax/sip/stack/SIPStackTimerTask.java new file mode 100644 index 0000000..5e80cdd --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPStackTimerTask.java @@ -0,0 +1,35 @@ +/* + * @author: Brett Buckingham + * @author: Last modified by: $Author: emcho $ + * @version: $Date: 2009/07/17 18:58:14 $ $Revision: 1.3 $ + * + * This source code has been contributed to the public domain. + */ + +package gov.nist.javax.sip.stack; + +import java.util.TimerTask; + +/** + * A subclass of TimerTask which runs TimerTask code within a try/catch block to + * avoid killing the SIPTransactionStack timer thread. Note: subclasses MUST not + * override run(); instead they should override runTask(). + * + * @author Brett Buckingham + * + */ +public abstract class SIPStackTimerTask extends TimerTask { + // / Implements code to be run when the SIPStackTimerTask is executed. + protected abstract void runTask(); + + // / The run() method is final to ensure that all subclasses inherit the + // exception handling. + public final void run() { + try { + runTask(); + } catch (Throwable e) { + System.out.println("SIP stack timer task failed due to exception:"); + e.printStackTrace(); + } + } +} diff --git a/java/gov/nist/javax/sip/stack/SIPTransaction.java b/java/gov/nist/javax/sip/stack/SIPTransaction.java new file mode 100644 index 0000000..1dfb5d0 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPTransaction.java @@ -0,0 +1,1281 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.stack; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.header.Event; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.sip.Dialog; +import javax.sip.IOExceptionEvent; +import javax.sip.ServerTransaction; +import javax.sip.TransactionState; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Modifications for TLS Support added by Daniel J. Martinez Manzano + * <dani@dif.um.es> Bug fixes by Jeroen van Bemmel (JvB) and others. + */ + +/** + * Abstract class to support both client and server transactions. Provides an + * encapsulation of a message channel, handles timer events, and creation of the + * Via header for a message. + * + * @author Jeff Keyser + * @author M. Ranganathan + * + * + * @version 1.2 $Revision: 1.71 $ $Date: 2009/11/29 04:31:29 $ + */ +public abstract class SIPTransaction extends MessageChannel implements + javax.sip.Transaction, gov.nist.javax.sip.TransactionExt { + + protected boolean toListener; // Flag to indicate that the listener gets + + // to see the event. + + protected int BASE_TIMER_INTERVAL = SIPTransactionStack.BASE_TIMER_INTERVAL; + /** + * 5 sec Maximum duration a message will remain in the network + */ + protected int T4 = 5000 / BASE_TIMER_INTERVAL; + + /** + * The maximum retransmit interval for non-INVITE requests and INVITE + * responses + */ + protected int T2 = 4000 / BASE_TIMER_INTERVAL; + protected int TIMER_I = T4; + + protected int TIMER_K = T4; + + protected int TIMER_D = 32000 / BASE_TIMER_INTERVAL; + + // protected static final int TIMER_C = 3 * 60 * 1000 / BASE_TIMER_INTERVAL; + + /** + * One timer tick. + */ + protected static final int T1 = 1; + + /** + * INVITE request retransmit interval, for UDP only + */ + protected static final int TIMER_A = 1; + + /** + * INVITE transaction timeout timer + */ + protected static final int TIMER_B = 64; + + protected static final int TIMER_J = 64; + + protected static final int TIMER_F = 64; + + protected static final int TIMER_H = 64; + + // Proposed feature for next release. + protected transient Object applicationData; + + protected SIPResponse lastResponse; + + // private SIPDialog dialog; + + protected boolean isMapped; + + private Semaphore semaphore; + + protected boolean isSemaphoreAquired; + + // protected boolean eventPending; // indicate that an event is pending + // here. + + protected String transactionId; // Transaction Id. + + // Audit tag used by the SIP Stack audit + public long auditTag = 0; + + /** + * Initialized but no state assigned. + */ + public static final TransactionState INITIAL_STATE = null; + + /** + * Trying state. + */ + public static final TransactionState TRYING_STATE = TransactionState.TRYING; + + /** + * CALLING State. + */ + public static final TransactionState CALLING_STATE = TransactionState.CALLING; + + /** + * Proceeding state. + */ + public static final TransactionState PROCEEDING_STATE = TransactionState.PROCEEDING; + + /** + * Completed state. + */ + public static final TransactionState COMPLETED_STATE = TransactionState.COMPLETED; + + /** + * Confirmed state. + */ + public static final TransactionState CONFIRMED_STATE = TransactionState.CONFIRMED; + + /** + * Terminated state. + */ + public static final TransactionState TERMINATED_STATE = TransactionState.TERMINATED; + + /** + * Maximum number of ticks between retransmissions. + */ + protected static final int MAXIMUM_RETRANSMISSION_TICK_COUNT = 8; + + // Parent stack for this transaction + protected transient SIPTransactionStack sipStack; + + // Original request that is being handled by this transaction + protected SIPRequest originalRequest; + + // Underlying channel being used to send messages for this transaction + private transient MessageChannel encapsulatedChannel; + + // Port of peer + protected int peerPort; + + // Address of peer + protected InetAddress peerInetAddress; + + // Address of peer as a string + protected String peerAddress; + + // Protocol of peer + protected String peerProtocol; + + // @@@ hagai - NAT changes + // Source port extracted from peer packet + protected int peerPacketSourcePort; + + protected InetAddress peerPacketSourceAddress; + + protected AtomicBoolean transactionTimerStarted = new AtomicBoolean(false); + + // Transaction branch ID + private String branch; + + // Method of the Request used to create the transaction. + private String method; + + // Sequence number of request used to create the transaction + private long cSeq; + + // Current transaction state + private TransactionState currentState; + + // Number of ticks the retransmission timer was set to last + private transient int retransmissionTimerLastTickCount; + + // Number of ticks before the message is retransmitted + private transient int retransmissionTimerTicksLeft; + + // Number of ticks before the transaction times out + protected int timeoutTimerTicksLeft; + + // List of event listeners for this transaction + private transient Set<SIPTransactionEventListener> eventListeners; + + // Hang on to these - we clear out the request URI after + // transaction goes to final state. Pointers to these are kept around + // for transaction matching as long as the transaction is in + // the transaction table. + protected From from; + + protected To to; + + protected Event event; + + protected CallID callId; + + // Back ptr to the JAIN layer. + // private Object wrapper; + + // Counter for caching of connections. + // Connection lingers for collectionTime + // after the Transaction goes to terminated state. + protected int collectionTime; + + protected String toTag; + + protected String fromTag; + + private boolean terminatedEventDelivered; + + public String getBranchId() { + return this.branch; + } + + /** + * The linger timer is used to remove the transaction from the transaction + * table after it goes into terminated state. This allows connection caching + * and also takes care of race conditins. + * + * + */ + class LingerTimer extends SIPStackTimerTask { + + public LingerTimer() { + SIPTransaction sipTransaction = SIPTransaction.this; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("LingerTimer : " + + sipTransaction.getTransactionId()); + } + + } + + protected void runTask() { + SIPTransaction transaction = SIPTransaction.this; + // release the connection associated with this transaction. + SIPTransactionStack sipStack = transaction.getSIPStack(); + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("LingerTimer: run() : " + + getTransactionId()); + } + + if (transaction instanceof SIPClientTransaction) { + sipStack.removeTransaction(transaction); + transaction.close(); + + } else if (transaction instanceof ServerTransaction) { + // Remove it from the set + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("removing" + transaction); + sipStack.removeTransaction(transaction); + if ((!sipStack.cacheServerConnections) + && --transaction.encapsulatedChannel.useCount <= 0) { + // Close the encapsulated socket if stack is configured + transaction.close(); + } else { + if (sipStack.isLoggingEnabled() + && (!sipStack.cacheServerConnections) + && transaction.isReliable()) { + int useCount = transaction.encapsulatedChannel.useCount; + sipStack.getStackLogger().logDebug("Use Count = " + useCount); + } + } + } + + } + } + + /** + * Transaction constructor. + * + * @param newParentStack + * Parent stack for this transaction. + * @param newEncapsulatedChannel + * Underlying channel for this transaction. + */ + protected SIPTransaction(SIPTransactionStack newParentStack, + MessageChannel newEncapsulatedChannel) { + + sipStack = newParentStack; + this.semaphore = new Semaphore(1,true); + + encapsulatedChannel = newEncapsulatedChannel; + // Record this to check if the address has changed before sending + // message to avoid possible race condition. + this.peerPort = newEncapsulatedChannel.getPeerPort(); + this.peerAddress = newEncapsulatedChannel.getPeerAddress(); + this.peerInetAddress = newEncapsulatedChannel.getPeerInetAddress(); + // @@@ hagai + this.peerPacketSourcePort = newEncapsulatedChannel + .getPeerPacketSourcePort(); + this.peerPacketSourceAddress = newEncapsulatedChannel + .getPeerPacketSourceAddress(); + this.peerProtocol = newEncapsulatedChannel.getPeerProtocol(); + if (this.isReliable()) { + encapsulatedChannel.useCount++; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logDebug("use count for encapsulated channel" + + this + + " " + + encapsulatedChannel.useCount ); + } + + this.currentState = null; + + disableRetransmissionTimer(); + disableTimeoutTimer(); + eventListeners = Collections.synchronizedSet(new HashSet<SIPTransactionEventListener>()); + + // Always add the parent stack as a listener + // of this transaction + addEventListener(newParentStack); + + } + + /** + * Sets the request message that this transaction handles. + * + * @param newOriginalRequest + * Request being handled. + */ + public void setOriginalRequest(SIPRequest newOriginalRequest) { + + // Branch value of topmost Via header + String newBranch; + + if (this.originalRequest != null + && (!this.originalRequest.getTransactionId().equals( + newOriginalRequest.getTransactionId()))) { + sipStack.removeTransactionHash(this); + } + // This will be cleared later. + + this.originalRequest = newOriginalRequest; + + // just cache the control information so the + // original request can be released later. + this.method = newOriginalRequest.getMethod(); + this.from = (From) newOriginalRequest.getFrom(); + this.to = (To) newOriginalRequest.getTo(); + // Save these to avoid concurrent modification exceptions! + this.toTag = this.to.getTag(); + this.fromTag = this.from.getTag(); + this.callId = (CallID) newOriginalRequest.getCallId(); + this.cSeq = newOriginalRequest.getCSeq().getSeqNumber(); + this.event = (Event) newOriginalRequest.getHeader("Event"); + this.transactionId = newOriginalRequest.getTransactionId(); + + originalRequest.setTransaction(this); + + // If the message has an explicit branch value set, + newBranch = ((Via) newOriginalRequest.getViaHeaders().getFirst()) + .getBranch(); + if (newBranch != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Setting Branch id : " + newBranch); + + // Override the default branch with the one + // set by the message + setBranch(newBranch); + + } else { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Branch id is null - compute TID!" + + newOriginalRequest.encode()); + setBranch(newOriginalRequest.getTransactionId()); + } + } + + /** + * Gets the request being handled by this transaction. + * + * @return -- the original Request associated with this transaction. + */ + public SIPRequest getOriginalRequest() { + return originalRequest; + } + + /** + * Get the original request but cast to a Request structure. + * + * @return the request that generated this transaction. + */ + public Request getRequest() { + return (Request) originalRequest; + } + + /** + * Returns a flag stating whether this transaction is for an INVITE request + * or not. + * + * @return -- true if this is an INVITE request, false if not. + */ + public final boolean isInviteTransaction() { + return getMethod().equals(Request.INVITE); + } + + /** + * Return true if the transaction corresponds to a CANCEL message. + * + * @return -- true if the transaciton is a CANCEL transaction. + */ + public final boolean isCancelTransaction() { + return getMethod().equals(Request.CANCEL); + } + + /** + * Return a flag that states if this is a BYE transaction. + * + * @return true if the transaciton is a BYE transaction. + */ + public final boolean isByeTransaction() { + return getMethod().equals(Request.BYE); + } + + /** + * Returns the message channel used for transmitting/receiving messages for + * this transaction. Made public in support of JAIN dual transaction model. + * + * @return Encapsulated MessageChannel. + * + */ + public MessageChannel getMessageChannel() { + return encapsulatedChannel; + } + + /** + * Sets the Via header branch parameter used to identify this transaction. + * + * @param newBranch + * New string used as the branch for this transaction. + */ + public final void setBranch(String newBranch) { + branch = newBranch; + } + + /** + * Gets the current setting for the branch parameter of this transaction. + * + * @return Branch parameter for this transaction. + */ + public final String getBranch() { + if (this.branch == null) { + this.branch = getOriginalRequest().getTopmostVia().getBranch(); + } + return branch; + } + + /** + * Get the method of the request used to create this transaction. + * + * @return the method of the request for the transaction. + */ + public final String getMethod() { + return this.method; + } + + /** + * Get the Sequence number of the request used to create the transaction. + * + * @return the cseq of the request used to create the transaction. + */ + public final long getCSeq() { + return this.cSeq; + } + + /** + * Changes the state of this transaction. + * + * @param newState + * New state of this transaction. + */ + public void setState(TransactionState newState) { + // PATCH submitted by sribeyron + if (currentState == TransactionState.COMPLETED) { + if (newState != TransactionState.TERMINATED + && newState != TransactionState.CONFIRMED) + newState = TransactionState.COMPLETED; + } + if (currentState == TransactionState.CONFIRMED) { + if (newState != TransactionState.TERMINATED) + newState = TransactionState.CONFIRMED; + } + if (currentState != TransactionState.TERMINATED) + currentState = newState; + else + newState = currentState; + // END OF PATCH + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Transaction:setState " + newState + + " " + this + " branchID = " + this.getBranch() + + " isClient = " + (this instanceof SIPClientTransaction)); + sipStack.getStackLogger().logStackTrace(); + } + } + + /** + * Gets the current state of this transaction. + * + * @return Current state of this transaction. + */ + public TransactionState getState() { + return this.currentState; + } + + /** + * Enables retransmission timer events for this transaction to begin in one + * tick. + */ + protected final void enableRetransmissionTimer() { + enableRetransmissionTimer(1); + } + + /** + * Enables retransmission timer events for this transaction to begin after + * the number of ticks passed to this routine. + * + * @param tickCount + * Number of ticks before the next retransmission timer event + * occurs. + */ + protected final void enableRetransmissionTimer(int tickCount) { + // For INVITE Client transactions, double interval each time + if (isInviteTransaction() && (this instanceof SIPClientTransaction)) { + retransmissionTimerTicksLeft = tickCount; + } else { + // non-INVITE transactions and 3xx-6xx responses are capped at T2 + retransmissionTimerTicksLeft = Math.min(tickCount, + MAXIMUM_RETRANSMISSION_TICK_COUNT); + } + retransmissionTimerLastTickCount = retransmissionTimerTicksLeft; + } + + /** + * Turns off retransmission events for this transaction. + */ + protected final void disableRetransmissionTimer() { + retransmissionTimerTicksLeft = -1; + } + + /** + * Enables a timeout event to occur for this transaction after the number of + * ticks passed to this method. + * + * @param tickCount + * Number of ticks before this transaction times out. + */ + protected final void enableTimeoutTimer(int tickCount) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("enableTimeoutTimer " + this + + " tickCount " + tickCount + " currentTickCount = " + + timeoutTimerTicksLeft); + + timeoutTimerTicksLeft = tickCount; + } + + /** + * Disabled the timeout timer. + */ + protected final void disableTimeoutTimer() { + timeoutTimerTicksLeft = -1; + } + + /** + * Fired after each timer tick. Checks the retransmission and timeout timers + * of this transaction, and fired these events if necessary. + */ + final void fireTimer() { + // If the timeout timer is enabled, + + if (timeoutTimerTicksLeft != -1) { + // Count down the timer, and if it has run out, + if (--timeoutTimerTicksLeft == 0) { + // Fire the timeout timer + fireTimeoutTimer(); + } + } + + // If the retransmission timer is enabled, + if (retransmissionTimerTicksLeft != -1) { + // Count down the timer, and if it has run out, + if (--retransmissionTimerTicksLeft == 0) { + // Enable this timer to fire again after + // twice the original time + enableRetransmissionTimer(retransmissionTimerLastTickCount * 2); + // Fire the timeout timer + fireRetransmissionTimer(); + } + } + } + + /** + * Tests if this transaction has terminated. + * + * @return Trus if this transaction is terminated, false if not. + */ + public final boolean isTerminated() { + return getState() == TERMINATED_STATE; + } + + public String getHost() { + return encapsulatedChannel.getHost(); + } + + public String getKey() { + return encapsulatedChannel.getKey(); + } + + public int getPort() { + return encapsulatedChannel.getPort(); + } + + public SIPTransactionStack getSIPStack() { + return (SIPTransactionStack) sipStack; + } + + public String getPeerAddress() { + return this.peerAddress; + } + + public int getPeerPort() { + return this.peerPort; + } + + // @@@ hagai + public int getPeerPacketSourcePort() { + return this.peerPacketSourcePort; + } + + public InetAddress getPeerPacketSourceAddress() { + return this.peerPacketSourceAddress; + } + + protected InetAddress getPeerInetAddress() { + return this.peerInetAddress; + } + + protected String getPeerProtocol() { + return this.peerProtocol; + } + + public String getTransport() { + return encapsulatedChannel.getTransport(); + } + + public boolean isReliable() { + return encapsulatedChannel.isReliable(); + } + + /** + * Returns the Via header for this channel. Gets the Via header of the + * underlying message channel, and adds a branch parameter to it for this + * transaction. + */ + public Via getViaHeader() { + // Via header of the encapulated channel + Via channelViaHeader; + + // Add the branch parameter to the underlying + // channel's Via header + channelViaHeader = super.getViaHeader(); + try { + channelViaHeader.setBranch(branch); + } catch (java.text.ParseException ex) { + } + return channelViaHeader; + + } + + /** + * Process the message through the transaction and sends it to the SIP peer. + * + * @param messageToSend + * Message to send to the SIP peer. + */ + public void sendMessage(SIPMessage messageToSend) throws IOException { + // Use the peer address, port and transport + // that was specified when the transaction was + // created. Bug was noted by Bruce Evangelder + // soleo communications. + try { + encapsulatedChannel.sendMessage(messageToSend, + this.peerInetAddress, this.peerPort); + } finally { + this.startTransactionTimer(); + } + } + + /** + * Parse the byte array as a message, process it through the transaction, + * and send it to the SIP peer. This is just a placeholder method -- calling + * it will result in an IO exception. + * + * @param messageBytes + * Bytes of the message to send. + * @param receiverAddress + * Address of the target peer. + * @param receiverPort + * Network port of the target peer. + * + * @throws IOException + * If called. + */ + protected void sendMessage(byte[] messageBytes, + InetAddress receiverAddress, int receiverPort, boolean retry) + throws IOException { + throw new IOException( + "Cannot send unparsed message through Transaction Channel!"); + } + + /** + * Adds a new event listener to this transaction. + * + * @param newListener + * Listener to add. + */ + public void addEventListener(SIPTransactionEventListener newListener) { + eventListeners.add(newListener); + } + + /** + * Removed an event listener from this transaction. + * + * @param oldListener + * Listener to remove. + */ + public void removeEventListener(SIPTransactionEventListener oldListener) { + eventListeners.remove(oldListener); + } + + /** + * Creates a SIPTransactionErrorEvent and sends it to all of the listeners + * of this transaction. This method also flags the transaction as + * terminated. + * + * @param errorEventID + * ID of the error to raise. + */ + protected void raiseErrorEvent(int errorEventID) { + + // Error event to send to all listeners + SIPTransactionErrorEvent newErrorEvent; + // Iterator through the list of listeners + Iterator<SIPTransactionEventListener> listenerIterator; + // Next listener in the list + SIPTransactionEventListener nextListener; + + // Create the error event + newErrorEvent = new SIPTransactionErrorEvent(this, errorEventID); + + // Loop through all listeners of this transaction + synchronized (eventListeners) { + listenerIterator = eventListeners.iterator(); + while (listenerIterator.hasNext()) { + // Send the event to the next listener + nextListener = (SIPTransactionEventListener) listenerIterator + .next(); + nextListener.transactionErrorEvent(newErrorEvent); + } + } + // Clear the event listeners after propagating the error. + // Retransmit notifications are just an alert to the + // application (they are not an error). + if (errorEventID != SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) { + eventListeners.clear(); + + // Errors always terminate a transaction + this.setState(TransactionState.TERMINATED); + + if (this instanceof SIPServerTransaction && this.isByeTransaction() + && this.getDialog() != null) + ((SIPDialog) this.getDialog()) + .setState(SIPDialog.TERMINATED_STATE); + } + } + + /** + * A shortcut way of telling if we are a server transaction. + */ + protected boolean isServerTransaction() { + return this instanceof SIPServerTransaction; + } + + /** + * Gets the dialog object of this Transaction object. This object returns + * null if no dialog exists. A dialog only exists for a transaction when a + * session is setup between a User Agent Client and a User Agent Server, + * either by a 1xx Provisional Response for an early dialog or a 200OK + * Response for a committed dialog. + * + * @return the Dialog Object of this Transaction object. + * @see Dialog + */ + public abstract Dialog getDialog(); + + /** + * set the dialog object. + * + * @param sipDialog -- + * the dialog to set. + * @param dialogId -- + * the dialog id ot associate with the dialog.s + */ + public abstract void setDialog(SIPDialog sipDialog, String dialogId); + + /** + * Returns the current value of the retransmit timer in milliseconds used to + * retransmit messages over unreliable transports. + * + * @return the integer value of the retransmit timer in milliseconds. + */ + public int getRetransmitTimer() { + return SIPTransactionStack.BASE_TIMER_INTERVAL; + } + + /** + * Get the host to assign for an outgoing Request via header. + */ + public String getViaHost() { + return this.getViaHeader().getHost(); + + } + + /** + * Get the last response. This is used internally by the implementation. + * Dont rely on it. + * + * @return the last response received (for client transactions) or sent (for + * server transactions). + */ + public SIPResponse getLastResponse() { + return this.lastResponse; + } + + /** + * Get the JAIN interface response + */ + public Response getResponse() { + return (Response) this.lastResponse; + } + + /** + * Get the transaction Id. + */ + public String getTransactionId() { + return this.transactionId; + } + + /** + * Hashcode method for fast hashtable lookup. + */ + public int hashCode() { + if (this.transactionId == null) + return -1; + else + return this.transactionId.hashCode(); + } + + /** + * Get the port to assign for the via header of an outgoing message. + */ + public int getViaPort() { + return this.getViaHeader().getPort(); + } + + /** + * A method that can be used to test if an incoming request belongs to this + * transction. This does not take the transaction state into account when + * doing the check otherwise it is identical to isMessagePartOfTransaction. + * This is useful for checking if a CANCEL belongs to this transaction. + * + * @param requestToTest + * is the request to test. + * @return true if the the request belongs to the transaction. + * + */ + public boolean doesCancelMatchTransaction(SIPRequest requestToTest) { + + // List of Via headers in the message to test + ViaList viaHeaders; + // Topmost Via header in the list + Via topViaHeader; + // Branch code in the topmost Via header + String messageBranch; + // Flags whether the select message is part of this transaction + boolean transactionMatches; + + transactionMatches = false; + + if (this.getOriginalRequest() == null + || this.getOriginalRequest().getMethod().equals(Request.CANCEL)) + return false; + // Get the topmost Via header and its branch parameter + viaHeaders = requestToTest.getViaHeaders(); + if (viaHeaders != null) { + + topViaHeader = (Via) viaHeaders.getFirst(); + messageBranch = topViaHeader.getBranch(); + if (messageBranch != null) { + + // If the branch parameter exists but + // does not start with the magic cookie, + if (!messageBranch.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { + + // Flags this as old + // (RFC2543-compatible) client + // version + messageBranch = null; + + } + + } + + // If a new branch parameter exists, + if (messageBranch != null && this.getBranch() != null) { + + // If the branch equals the branch in + // this message, + if (getBranch().equalsIgnoreCase(messageBranch) + && topViaHeader.getSentBy().equals( + ((Via) getOriginalRequest().getViaHeaders() + .getFirst()).getSentBy())) { + transactionMatches = true; + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("returning true"); + } + + } else { + // If this is an RFC2543-compliant message, + // If RequestURI, To tag, From tag, + // CallID, CSeq number, and top Via + // headers are the same, + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("testing against " + + getOriginalRequest()); + + if (getOriginalRequest().getRequestURI().equals( + requestToTest.getRequestURI()) + && getOriginalRequest().getTo().equals( + requestToTest.getTo()) + && getOriginalRequest().getFrom().equals( + requestToTest.getFrom()) + && getOriginalRequest().getCallId().getCallId().equals( + requestToTest.getCallId().getCallId()) + && getOriginalRequest().getCSeq().getSeqNumber() == requestToTest + .getCSeq().getSeqNumber() + && topViaHeader.equals(getOriginalRequest() + .getViaHeaders().getFirst())) { + + transactionMatches = true; + } + + } + + } + + // JvB: Need to pass the CANCEL to the listener! Retransmitted INVITEs + // set it to false + if (transactionMatches) { + this.setPassToListener(); + } + return transactionMatches; + } + + /** + * Sets the value of the retransmit timer to the newly supplied timer value. + * The retransmit timer is expressed in milliseconds and its default value + * is 500ms. This method allows the application to change the transaction + * retransmit behavior for different networks. Take the gateway proxy as an + * example. The internal intranet is likely to be reatively uncongested and + * the endpoints will be relatively close. The external network is the + * general Internet. This functionality allows different retransmit times + * for either side. + * + * @param retransmitTimer - + * the new integer value of the retransmit timer in milliseconds. + */ + public void setRetransmitTimer(int retransmitTimer) { + + if (retransmitTimer <= 0) + throw new IllegalArgumentException( + "Retransmit timer must be positive!"); + if (this.transactionTimerStarted.get()) + throw new IllegalStateException( + "Transaction timer is already started"); + BASE_TIMER_INTERVAL = retransmitTimer; + T4 = 5000 / BASE_TIMER_INTERVAL; + + T2 = 4000 / BASE_TIMER_INTERVAL; + TIMER_I = T4; + + TIMER_K = T4; + + TIMER_D = 32000 / BASE_TIMER_INTERVAL; + + } + + /** + * Close the encapsulated channel. + */ + public void close() { + this.encapsulatedChannel.close(); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Closing " + this.encapsulatedChannel); + + } + + public boolean isSecure() { + return encapsulatedChannel.isSecure(); + } + + public MessageProcessor getMessageProcessor() { + return this.encapsulatedChannel.getMessageProcessor(); + } + + /** + * Set the application data pointer. This is un-interpreted by the stack. + * This is provided as a conveniant way of keeping book-keeping data for + * applications. Note that null clears the application data pointer + * (releases it). + * + * @param applicationData -- + * application data pointer to set. null clears the applicationd + * data pointer. + * + */ + + public void setApplicationData(Object applicationData) { + this.applicationData = applicationData; + } + + /** + * Get the application data associated with this transaction. + * + * @return stored application data. + */ + public Object getApplicationData() { + return this.applicationData; + } + + /** + * Set the encapsuated channel. The peer inet address and port are set equal + * to the message channel. + */ + public void setEncapsulatedChannel(MessageChannel messageChannel) { + this.encapsulatedChannel = messageChannel; + this.peerInetAddress = messageChannel.getPeerInetAddress(); + this.peerPort = messageChannel.getPeerPort(); + } + + /** + * Return the SipProvider for which the transaction is assigned. + * + * @return the SipProvider for the transaction. + */ + public SipProviderImpl getSipProvider() { + + return this.getMessageProcessor().getListeningPoint().getProvider(); + } + + /** + * Raise an IO Exception event - this is used for reporting asynchronous IO + * Exceptions that are attributable to this transaction. + * + */ + public void raiseIOExceptionEvent() { + setState(TransactionState.TERMINATED); + String host = getPeerAddress(); + int port = getPeerPort(); + String transport = getTransport(); + IOExceptionEvent exceptionEvent = new IOExceptionEvent(this, host, + port, transport); + getSipProvider().handleEvent(exceptionEvent, this); + } + + /** + * A given tx can process only a single outstanding event at a time. This + * semaphore gaurds re-entrancy to the transaction. + * + */ + public boolean acquireSem() { + boolean retval = false; + try { + if (sipStack.getStackLogger().isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("acquireSem [[[[" + this); + sipStack.getStackLogger().logStackTrace(); + } + retval = this.semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS); + if ( sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug( + "acquireSem() returning : " + retval); + return retval; + } catch (Exception ex) { + sipStack.getStackLogger().logError("Unexpected exception acquiring sem", + ex); + InternalErrorHandler.handleException(ex); + return false; + } finally { + this.isSemaphoreAquired = retval; + } + + } + + /** + * Release the transaction semaphore. + * + */ + public void releaseSem() { + try { + + this.toListener = false; + this.semRelease(); + + } catch (Exception ex) { + sipStack.getStackLogger().logError("Unexpected exception releasing sem", + ex); + + } + + } + + protected void semRelease() { + try { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("semRelease ]]]]" + this); + sipStack.getStackLogger().logStackTrace(); + } + this.isSemaphoreAquired = false; + this.semaphore.release(); + + } catch (Exception ex) { + sipStack.getStackLogger().logError("Unexpected exception releasing sem", + ex); + + } + } + + /** + * Set true to pass the request up to the listener. False otherwise. + * + */ + + public boolean passToListener() { + return toListener; + } + + /** + * Set the passToListener flag to true. + */ + public void setPassToListener() { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("setPassToListener()"); + } + this.toListener = true; + + } + + /** + * Flag to test if the terminated event is delivered. + * + * @return + */ + protected synchronized boolean testAndSetTransactionTerminatedEvent() { + boolean retval = !this.terminatedEventDelivered; + this.terminatedEventDelivered = true; + return retval; + } + + public String getCipherSuite() throws UnsupportedOperationException { + if (this.getMessageChannel() instanceof TLSMessageChannel ) { + if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) + return null; + else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) + return null; + else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getCipherSuite(); + } else throw new UnsupportedOperationException("Not a TLS channel"); + + } + + + public java.security.cert.Certificate[] getLocalCertificates() throws UnsupportedOperationException { + if (this.getMessageChannel() instanceof TLSMessageChannel ) { + if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) + return null; + else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) + return null; + else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getLocalCertificates(); + } else throw new UnsupportedOperationException("Not a TLS channel"); + } + + + public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { + if (this.getMessageChannel() instanceof TLSMessageChannel ) { + if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) + return null; + else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) + return null; + else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getPeerCertificates(); + } else throw new UnsupportedOperationException("Not a TLS channel"); + + } + + + /** + * Start the timer that runs the transaction state machine. + * + */ + + protected abstract void startTransactionTimer(); + + /** + * Tests a message to see if it is part of this transaction. + * + * @return True if the message is part of this transaction, false if not. + */ + public abstract boolean isMessagePartOfTransaction(SIPMessage messageToTest); + + /** + * This method is called when this transaction's retransmission timer has + * fired. + */ + protected abstract void fireRetransmissionTimer(); + + /** + * This method is called when this transaction's timeout timer has fired. + */ + protected abstract void fireTimeoutTimer(); + +} diff --git a/java/gov/nist/javax/sip/stack/SIPTransactionErrorEvent.java b/java/gov/nist/javax/sip/stack/SIPTransactionErrorEvent.java new file mode 100644 index 0000000..a96cd01 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPTransactionErrorEvent.java @@ -0,0 +1,93 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.stack; + + +import java.util.EventObject; + +/** + * An event that indicates that a transaction has encountered an error. + * + * + * @author Jeff Keyser + * @author M. Ranganathan + * + * + * + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:15 $ + */ +public class SIPTransactionErrorEvent extends EventObject { + + /** + * Comment for <code>serialVersionUID</code> + */ + private static final long serialVersionUID = -2713188471978065031L; + + /** + * This event ID indicates that the transaction has timed out. + */ + public static final int TIMEOUT_ERROR = 1; + + /** + * This event ID indicates that there was an error sending a message using + * the underlying transport. + */ + public static final int TRANSPORT_ERROR = 2; + + /** + * Retransmit signal to application layer. + */ + public static final int TIMEOUT_RETRANSMIT = 3; + + + + // ID of this error event + private int errorID; + + /** + * Creates a transaction error event. + * + * @param sourceTransaction Transaction which is raising the error. + * @param transactionErrorID ID of the error that has ocurred. + */ + SIPTransactionErrorEvent( + SIPTransaction sourceTransaction, + int transactionErrorID) { + + super(sourceTransaction); + errorID = transactionErrorID; + + } + + /** + * Returns the ID of the error. + * + * @return Error ID. + */ + public int getErrorID() { + return errorID; + } +} diff --git a/java/gov/nist/javax/sip/stack/SIPTransactionEventListener.java b/java/gov/nist/javax/sip/stack/SIPTransactionEventListener.java new file mode 100644 index 0000000..04f156e --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPTransactionEventListener.java @@ -0,0 +1,45 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +package gov.nist.javax.sip.stack; + +import java.util.EventListener; + +/** + * Interface implemented by classes that want to be notified of asynchronous + * transacion events. + * + * @author Jeff Keyser + * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:15 $ + */ +public interface SIPTransactionEventListener extends EventListener { + + /** + * Invoked when an error has ocurred with a transaction. + * + * @param transactionErrorEvent Error event. + */ + public void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent); +} diff --git a/java/gov/nist/javax/sip/stack/SIPTransactionStack.java b/java/gov/nist/javax/sip/stack/SIPTransactionStack.java new file mode 100644 index 0000000..1788bbe --- /dev/null +++ b/java/gov/nist/javax/sip/stack/SIPTransactionStack.java @@ -0,0 +1,2492 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +package gov.nist.javax.sip.stack; + +import gov.nist.core.Host; +import gov.nist.core.HostPort; +import gov.nist.core.ServerLogger; +import gov.nist.core.StackLogger; +import gov.nist.core.ThreadAuditor; +import gov.nist.core.net.AddressResolver; +import gov.nist.core.net.DefaultNetworkLayer; +import gov.nist.core.net.NetworkLayer; +import gov.nist.javax.sip.DefaultAddressResolver; +import gov.nist.javax.sip.ListeningPointImpl; +import gov.nist.javax.sip.LogRecordFactory; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.SipListenerExt; +import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.SipStackImpl; +import gov.nist.javax.sip.header.Event; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.extensions.JoinHeader; +import gov.nist.javax.sip.header.extensions.ReplacesHeader; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.Timer; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.sip.ClientTransaction; +import javax.sip.Dialog; +import javax.sip.DialogState; +import javax.sip.DialogTerminatedEvent; +import javax.sip.ServerTransaction; +import javax.sip.SipException; +import javax.sip.SipListener; +import javax.sip.TransactionState; +import javax.sip.TransactionTerminatedEvent; +import javax.sip.address.Hop; +import javax.sip.address.Router; +import javax.sip.header.CallIdHeader; +import javax.sip.header.EventHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +/* + * Jeff Keyser : architectural suggestions and contributions. Pierre De Rop and Thomas Froment : + * Bug reports. Jeyashankher < jai@lucent.com > : bug reports. Jeroen van Bemmel : Bug fixes. + * + * + */ + +/** + * + * This is the sip stack. It is essentially a management interface. It manages the resources for + * the JAIN-SIP implementation. This is the structure that is wrapped by the SipStackImpl. + * + * @see gov.nist.javax.sip.SipStackImpl + * + * @author M. Ranganathan <br/> + * + * @version 1.2 $Revision: 1.141 $ $Date: 2009/12/17 23:38:27 $ + */ +public abstract class SIPTransactionStack implements SIPTransactionEventListener, SIPDialogEventListener { + + /* + * Number of milliseconds between timer ticks (500). + */ + public static final int BASE_TIMER_INTERVAL = 500; + + /* + * Connection linger time (seconds) this is the time (in seconds) for which we linger the TCP + * connection before closing it. + */ + public static final int CONNECTION_LINGER_TIME = 8; + + /* + * Table of retransmission Alert timers. + */ + protected ConcurrentHashMap<String, SIPServerTransaction> retransmissionAlertTransactions; + + // Table of early dialogs ( to keep identity mapping ) + protected ConcurrentHashMap<String, SIPDialog> earlyDialogTable; + + // Table of dialogs. + protected ConcurrentHashMap<String, SIPDialog> dialogTable; + + // A set of methods that result in dialog creations. + protected static final Set<String> dialogCreatingMethods = new HashSet<String>(); + + // Global timer. Use this for all timer tasks. + + private Timer timer; + + // List of pending server transactions + private ConcurrentHashMap<String, SIPServerTransaction> pendingTransactions; + + // hashtable for fast lookup + private ConcurrentHashMap<String, SIPClientTransaction> clientTransactionTable; + + // Set to false if you want hiwat and lowat to be consulted. + protected boolean unlimitedServerTransactionTableSize = true; + + // Set to false if you want unlimited size of client trnansactin table. + protected boolean unlimitedClientTransactionTableSize = true; + + // High water mark for ServerTransaction Table + // after which requests are dropped. + protected int serverTransactionTableHighwaterMark = 5000; + + // Low water mark for Server Tx table size after which + // requests are selectively dropped + protected int serverTransactionTableLowaterMark = 4000; + + // Hiwater mark for client transaction table. These defaults can be + // overriden by stack + // configuration. + protected int clientTransactionTableHiwaterMark = 1000; + + // Low water mark for client tx table. + protected int clientTransactionTableLowaterMark = 800; + + private AtomicInteger activeClientTransactionCount = new AtomicInteger(0); + + // Hashtable for server transactions. + private ConcurrentHashMap<String, SIPServerTransaction> serverTransactionTable; + + // A table of ongoing transactions indexed by mergeId ( for detecting merged + // requests. + private ConcurrentHashMap<String, SIPServerTransaction> mergeTable; + + private ConcurrentHashMap<String,SIPServerTransaction> terminatedServerTransactionsPendingAck; + + private ConcurrentHashMap<String,SIPClientTransaction> forkedClientTransactionTable; + + /* + * A wrapper around differnt logging implementations (log4j, commons logging, slf4j, ...) to help log debug. + */ + private StackLogger stackLogger; + + /* + * ServerLog is used just for logging stack message tracecs. + */ + protected ServerLogger serverLogger; + + /* + * We support UDP on this stack. + */ + boolean udpFlag; + + /* + * Internal router. Use this for all sip: request routing. + * + */ + protected DefaultRouter defaultRouter; + + /* + * Global flag that turns logging off + */ + protected boolean needsLogging; + + /* + * Flag used for testing TI, bypasses filtering of ACK to non-2xx + */ + private boolean non2XXAckPassedToListener; + + /* + * Class that handles caching of TCP/TLS connections. + */ + protected IOHandler ioHandler; + + /* + * Flag that indicates that the stack is active. + */ + protected boolean toExit; + + /* + * Name of the stack. + */ + protected String stackName; + + /* + * IP address of stack -- this can be re-written by stun. + * + * @deprecated + */ + protected String stackAddress; + + /* + * INET address of stack (cached to avoid repeated lookup) + * + * @deprecated + */ + protected InetAddress stackInetAddress; + + /* + * Request factory interface (to be provided by the application) + */ + protected StackMessageFactory sipMessageFactory; + + /* + * Router to determine where to forward the request. + */ + protected javax.sip.address.Router router; + + /* + * Number of pre-allocated threads for processing udp messages. -1 means no preallocated + * threads ( dynamically allocated threads). + */ + protected int threadPoolSize; + + /* + * max number of simultaneous connections. + */ + protected int maxConnections; + + /* + * Close accept socket on completion. + */ + protected boolean cacheServerConnections; + + /* + * Close connect socket on Tx termination. + */ + protected boolean cacheClientConnections; + + /* + * Use the user supplied router for all out of dialog requests. + */ + protected boolean useRouterForAll; + + /* + * Max size of message that can be read from a TCP connection. + */ + protected int maxContentLength; + + /* + * Max # of headers that a SIP message can contain. + */ + protected int maxMessageSize; + + /* + * A collection of message processors. + */ + private Collection<MessageProcessor> messageProcessors; + + /* + * Read timeout on TCP incoming sockets -- defines the time between reads for after delivery + * of first byte of message. + */ + protected int readTimeout; + + /* + * The socket factory. Can be overriden by applications that want direct access to the + * underlying socket. + */ + + protected NetworkLayer networkLayer; + + /* + * Outbound proxy String ( to be handed to the outbound proxy class on creation). + */ + protected String outboundProxy; + + protected String routerPath; + + // Flag to indicate whether the stack will provide dialog + // support. + protected boolean isAutomaticDialogSupportEnabled; + + // The set of events for which subscriptions can be forked. + + protected HashSet<String> forkedEvents; + + // Generate a timestamp header for retransmitted requests. + protected boolean generateTimeStampHeader; + + protected AddressResolver addressResolver; + + // Max time that the listener is allowed to take to respond to a + // request. Default is "infinity". This property allows + // containers to defend against buggy clients (that do not + // want to respond to requests). + protected int maxListenerResponseTime; + + + // A flag that indicates whether or not RFC 2543 clients are fully supported. + // If this is set to true, then To tag checking on the Dialog layer is + // disabled in a few places - resulting in possible breakage of forked dialogs. + protected boolean rfc2543Supported = true; + + // / Provides a mechanism for applications to check the health of threads in + // the stack + protected ThreadAuditor threadAuditor = new ThreadAuditor(); + + protected LogRecordFactory logRecordFactory; + + // Set to true if the client CANCEL transaction should be checked before sending + // it out. + protected boolean cancelClientTransactionChecked = true; + + // Is to tag reassignment allowed. + protected boolean remoteTagReassignmentAllowed = true; + + protected boolean logStackTraceOnMessageSend = true; + + // Receive UDP buffer size + protected int receiveUdpBufferSize; + + // Send UDP buffer size + protected int sendUdpBufferSize; + + protected boolean stackDoesCongestionControl = true; + + protected boolean isBackToBackUserAgent = false; + + protected boolean checkBranchId; + + protected boolean isAutomaticDialogErrorHandlingEnabled = true; + + protected boolean isDialogTerminatedEventDeliveredForNullDialog = false; + + // Max time for a forked response to arrive. After this time, the original dialog + // is not tracked. If you want to track the original transaction you need to specify + // the max fork time with a stack init property. + protected int maxForkTime = 0; + + + // / Timer to regularly ping the thread auditor (on behalf of the timer + // thread) + class PingTimer extends SIPStackTimerTask { + // / Timer thread handle + ThreadAuditor.ThreadHandle threadHandle; + + // / Constructor + public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) { + threadHandle = a_oThreadHandle; + } + + protected void runTask() { + // Check if we still have a timer (it may be null after shutdown) + if (getTimer() != null) { + // Register the timer task if we haven't done so + if (threadHandle == null) { + // This happens only once since the thread handle is passed + // to the next scheduled ping timer + threadHandle = getThreadAuditor().addCurrentThread(); + } + + // Let the thread auditor know that the timer task is alive + threadHandle.ping(); + + // Schedule the next ping + getTimer().schedule(new PingTimer(threadHandle), + threadHandle.getPingIntervalInMillisecs()); + } + } + + } + + + class RemoveForkedTransactionTimerTask extends SIPStackTimerTask { + + private SIPClientTransaction clientTransaction; + + public RemoveForkedTransactionTimerTask(SIPClientTransaction sipClientTransaction ) { + this.clientTransaction = sipClientTransaction; + } + + @Override + protected void runTask() { + forkedClientTransactionTable.remove(clientTransaction.getTransactionId()); + } + + } + + static { + // Standard set of methods that create dialogs. + dialogCreatingMethods.add(Request.REFER); + dialogCreatingMethods.add(Request.INVITE); + dialogCreatingMethods.add(Request.SUBSCRIBE); + } + + /** + * Default constructor. + */ + protected SIPTransactionStack() { + this.toExit = false; + this.forkedEvents = new HashSet<String>(); + // set of events for which subscriptions can be forked. + // Set an infinite thread pool size. + this.threadPoolSize = -1; + // Close response socket after infinte time. + // for max performance + this.cacheServerConnections = true; + // Close the request socket after infinite time. + // for max performance + this.cacheClientConnections = true; + // Max number of simultaneous connections. + this.maxConnections = -1; + // Array of message processors. + messageProcessors = new ArrayList<MessageProcessor>(); + // Handle IO for this process. + this.ioHandler = new IOHandler(this); + + // The read time out is infinite. + this.readTimeout = -1; + + this.maxListenerResponseTime = -1; + + // The default (identity) address lookup scheme + + this.addressResolver = new DefaultAddressResolver(); + + // Notify may or may not create a dialog. This is handled in + // the code. + // Create the transaction collections + + // Dialog dable. + this.dialogTable = new ConcurrentHashMap<String, SIPDialog>(); + this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>(); + + clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>(); + serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>(); + this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String, SIPServerTransaction>(); + mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>(); + retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>(); + + // Start the timer event thread. + + this.timer = new Timer(); + this.pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>(); + + + this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>(); + + if (getThreadAuditor().isEnabled()) { + // Start monitoring the timer thread + timer.schedule(new PingTimer(null), 0); + } + } + + /** + * Re Initialize the stack instance. + */ + protected void reInit() { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("Re-initializing !"); + + // Array of message processors. + messageProcessors = new ArrayList<MessageProcessor>(); + // Handle IO for this process. + this.ioHandler = new IOHandler(this); + // clientTransactions = new ConcurrentLinkedQueue(); + // serverTransactions = new ConcurrentLinkedQueue(); + pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>(); + clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>(); + serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>(); + retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>(); + mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>(); + // Dialog dable. + this.dialogTable = new ConcurrentHashMap<String, SIPDialog>(); + this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>(); + this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String,SIPServerTransaction>(); + this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>(); + + this.timer = new Timer(); + + this.activeClientTransactionCount = new AtomicInteger(0); + + } + + /** + * Creates and binds, if necessary, a socket connected to the specified + * destination address and port and then returns its local address. + * + * @param dst the destination address that the socket would need to connect + * to. + * @param dstPort the port number that the connection would be established + * with. + * @param localAddress the address that we would like to bind on + * (null for the "any" address). + * @param localPort the port that we'd like our socket to bind to (0 for a + * random port). + * + * @return the SocketAddress that this handler would use when connecting to + * the specified destination address and port. + * + * @throws IOException + */ + public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort, + InetAddress localAddress, int localPort) + throws IOException + { + return this.ioHandler.obtainLocalAddress( + dst, dstPort, localAddress, localPort); + + } + + /** + * For debugging -- allows you to disable logging or enable logging selectively. + * + * + */ + public void disableLogging() { + this.getStackLogger().disableLogging(); + } + + /** + * Globally enable message logging ( for debugging) + * + */ + public void enableLogging() { + this.getStackLogger().enableLogging(); + } + + /** + * Print the dialog table. + * + */ + public void printDialogTable() { + if (isLoggingEnabled()) { + this.getStackLogger().logDebug("dialog table = " + this.dialogTable); + System.out.println("dialog table = " + this.dialogTable); + } + } + + /** + * Retrieve a transaction from our table of transactions with pending retransmission alerts. + * + * @param dialogId + * @return -- the RetransmissionAlert enabled transaction corresponding to the given dialog + * ID. + */ + public SIPServerTransaction getRetransmissionAlertTransaction(String dialogId) { + return (SIPServerTransaction) this.retransmissionAlertTransactions.get(dialogId); + } + + /** + * Return true if extension is supported. + * + * @return true if extension is supported and false otherwise. + */ + public static boolean isDialogCreated(String method) { + return dialogCreatingMethods.contains(method); + } + + /** + * Add an extension method. + * + * @param extensionMethod -- extension method to support for dialog creation + */ + public void addExtensionMethod(String extensionMethod) { + if (extensionMethod.equals(Request.NOTIFY)) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("NOTIFY Supported Natively"); + } else { + dialogCreatingMethods.add(extensionMethod.trim().toUpperCase()); + } + } + + /** + * Put a dialog into the dialog table. + * + * @param dialog -- dialog to put into the dialog table. + * + */ + public void putDialog(SIPDialog dialog) { + String dialogId = dialog.getDialogId(); + if (dialogTable.containsKey(dialogId)) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("putDialog: dialog already exists" + dialogId + " in table = " + + dialogTable.get(dialogId)); + } + return; + } + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("putDialog dialogId=" + dialogId + " dialog = " + dialog); + } + dialog.setStack(this); + if (stackLogger.isLoggingEnabled()) + stackLogger.logStackTrace(); + dialogTable.put(dialogId, dialog); + + } + + /** + * Create a dialog and add this transaction to it. + * + * @param transaction -- tx to add to the dialog. + * @return the newly created Dialog. + */ + public SIPDialog createDialog(SIPTransaction transaction) { + + SIPDialog retval = null; + + if (transaction instanceof SIPClientTransaction) { + String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false); + if (this.earlyDialogTable.get(dialogId) != null) { + SIPDialog dialog = this.earlyDialogTable.get(dialogId); + if (dialog.getState() == null || dialog.getState() == DialogState.EARLY) { + retval = dialog; + } else { + retval = new SIPDialog(transaction); + this.earlyDialogTable.put(dialogId, retval); + } + } else { + retval = new SIPDialog(transaction); + this.earlyDialogTable.put(dialogId, retval); + } + } else { + retval = new SIPDialog(transaction); + } + + return retval; + + } + + /** + * Create a Dialog given a client tx and response. + * + * @param transaction + * @param sipResponse + * @return + */ + + public SIPDialog createDialog(SIPClientTransaction transaction, SIPResponse sipResponse) { + String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false); + SIPDialog retval = null; + if (this.earlyDialogTable.get(dialogId) != null) { + retval = this.earlyDialogTable.get(dialogId); + if (sipResponse.isFinalResponse()) { + this.earlyDialogTable.remove(dialogId); + } + + } else { + retval = new SIPDialog(transaction, sipResponse); + } + return retval; + + } + /** + * Create a Dialog given a sip provider and response. + * + * @param sipProvider + * @param sipResponse + * @return + */ + public SIPDialog createDialog(SipProviderImpl sipProvider, + SIPResponse sipResponse) { + return new SIPDialog(sipProvider, sipResponse); + } + + /** + * Remove the dialog from the dialog table. + * + * @param dialog -- dialog to remove. + */ + public void removeDialog(SIPDialog dialog) { + + String id = dialog.getDialogId(); + + String earlyId = dialog.getEarlyDialogId(); + + if (earlyId != null) { + this.earlyDialogTable.remove(earlyId); + this.dialogTable.remove(earlyId); + } + + if (id != null) { + + // FHT: Remove dialog from table only if its associated dialog is the same as the one + // specified + + Object old = this.dialogTable.get(id); + + if (old == dialog) { + this.dialogTable.remove(id); + } + + // We now deliver DTE even when the dialog is not originally present in the Dialog + // Table + // This happens before the dialog state is assigned. + + if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) { + DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(), + dialog); + + // Provide notification to the listener that the dialog has + // ended. + dialog.getSipProvider().handleEvent(event, null); + + } + + } else if ( this.isDialogTerminatedEventDeliveredForNullDialog ) { + if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) { + DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(), + dialog); + + // Provide notification to the listener that the dialog has + // ended. + dialog.getSipProvider().handleEvent(event, null); + + } + } + + } + + /** + * Return the dialog for a given dialog ID. If compatibility is enabled then we do not assume + * the presence of tags and hence need to add a flag to indicate whether this is a server or + * client transaction. + * + * @param dialogId is the dialog id to check. + */ + + public SIPDialog getDialog(String dialogId) { + + SIPDialog sipDialog = (SIPDialog) dialogTable.get(dialogId); + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("getDialog(" + dialogId + ") : returning " + sipDialog); + } + return sipDialog; + + } + + /** + * Remove the dialog given its dialog id. This is used for dialog id re-assignment only. + * + * @param dialogId is the dialog Id to remove. + */ + public void removeDialog(String dialogId) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logWarning("Silently removing dialog from table"); + } + dialogTable.remove(dialogId); + } + + /** + * Find a matching client SUBSCRIBE to the incoming notify. NOTIFY requests are matched to + * such SUBSCRIBE requests if they contain the same "Call-ID", a "To" header "tag" parameter + * which matches the "From" header "tag" parameter of the SUBSCRIBE, and the same "Event" + * header field. Rules for comparisons of the "Event" headers are described in section 7.2.1. + * If a matching NOTIFY request contains a "Subscription-State" of "active" or "pending", it + * creates a new subscription and a new dialog (unless they have already been created by a + * matching response, as described above). + * + * @param notifyMessage + * @return -- the matching ClientTransaction with semaphore aquired or null if no such client + * transaction can be found. + */ + public SIPClientTransaction findSubscribeTransaction(SIPRequest notifyMessage, + ListeningPointImpl listeningPoint) { + SIPClientTransaction retval = null; + try { + Iterator it = clientTransactionTable.values().iterator(); + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("ct table size = " + clientTransactionTable.size()); + String thisToTag = notifyMessage.getTo().getTag(); + if (thisToTag == null) { + return retval; + } + Event eventHdr = (Event) notifyMessage.getHeader(EventHeader.NAME); + if (eventHdr == null) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("event Header is null -- returning null"); + } + + return retval; + } + while (it.hasNext()) { + SIPClientTransaction ct = (SIPClientTransaction) it.next(); + if (!ct.getMethod().equals(Request.SUBSCRIBE)) + continue; + + // if ( sipProvider.getListeningPoint(transport) == null) + String fromTag = ct.from.getTag(); + Event hisEvent = ct.event; + // Event header is mandatory but some slopply clients + // dont include it. + if (hisEvent == null) + continue; + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("ct.fromTag = " + fromTag); + stackLogger.logDebug("thisToTag = " + thisToTag); + stackLogger.logDebug("hisEvent = " + hisEvent); + stackLogger.logDebug("eventHdr " + eventHdr); + } + + if ( fromTag.equalsIgnoreCase(thisToTag) + && hisEvent != null + && eventHdr.match(hisEvent) + && notifyMessage.getCallId().getCallId().equalsIgnoreCase( + ct.callId.getCallId())) { + if (ct.acquireSem()) + retval = ct; + return retval; + } + } + + return retval; + } finally { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("findSubscribeTransaction : returning " + retval); + + } + + } + + /** + * Add entry to "Transaction Pending ACK" table. + * + * @param serverTransaction + */ + public void addTransactionPendingAck(SIPServerTransaction serverTransaction) { + String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch(); + if ( branchId != null ) { + this.terminatedServerTransactionsPendingAck.put(branchId, serverTransaction); + } + + } + + /** + * Get entry in the server transaction pending ACK table corresponding to an ACK. + * + * @param ackMessage + * @return + */ + public SIPServerTransaction findTransactionPendingAck(SIPRequest ackMessage) { + return this.terminatedServerTransactionsPendingAck.get(ackMessage.getTopmostVia().getBranch()); + } + + /** + * Remove entry from "Transaction Pending ACK" table. + * + * @param serverTransaction + * @return + */ + + public boolean removeTransactionPendingAck(SIPServerTransaction serverTransaction) { + String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch(); + if ( branchId != null && this.terminatedServerTransactionsPendingAck.containsKey(branchId) ) { + this.terminatedServerTransactionsPendingAck.remove(branchId); + return true; + } else { + return false; + } + } + + /** + * Check if this entry exists in the "Transaction Pending ACK" table. + * + * @param serverTransaction + * @return + */ + public boolean isTransactionPendingAck(SIPServerTransaction serverTransaction) { + String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch(); + return this.terminatedServerTransactionsPendingAck.contains(branchId); + } + + /** + * Find the transaction corresponding to a given request. + * + * @param sipMessage request for which to retrieve the transaction. + * + * @param isServer search the server transaction table if true. + * + * @return the transaction object corresponding to the request or null if no such mapping + * exists. + */ + public SIPTransaction findTransaction(SIPMessage sipMessage, boolean isServer) { + SIPTransaction retval = null; + try { + if (isServer) { + Via via = sipMessage.getTopmostVia(); + if (via.getBranch() != null) { + String key = sipMessage.getTransactionId(); + + retval = (SIPTransaction) serverTransactionTable.get(key); + if (stackLogger.isLoggingEnabled()) + getStackLogger().logDebug( + "serverTx: looking for key " + key + " existing=" + + serverTransactionTable); + if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { + return retval; + } + + } + // Need to scan the table for old style transactions (RFC 2543 + // style) + Iterator<SIPServerTransaction> it = serverTransactionTable.values().iterator(); + while (it.hasNext()) { + SIPServerTransaction sipServerTransaction = (SIPServerTransaction) it.next(); + if (sipServerTransaction.isMessagePartOfTransaction(sipMessage)) { + retval = sipServerTransaction; + return retval; + } + } + + } else { + Via via = sipMessage.getTopmostVia(); + if (via.getBranch() != null) { + String key = sipMessage.getTransactionId(); + if (stackLogger.isLoggingEnabled()) + getStackLogger().logDebug("clientTx: looking for key " + key); + retval = (SIPTransaction) clientTransactionTable.get(key); + if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { + return retval; + } + + } + // Need to scan the table for old style transactions (RFC 2543 + // style). This is terribly slow but we need to do this + // for backasswords compatibility. + Iterator<SIPClientTransaction> it = clientTransactionTable.values().iterator(); + while (it.hasNext()) { + SIPClientTransaction clientTransaction = (SIPClientTransaction) it.next(); + if (clientTransaction.isMessagePartOfTransaction(sipMessage)) { + retval = clientTransaction; + return retval; + } + } + + } + } finally { + if ( this.getStackLogger().isLoggingEnabled()) { + this.getStackLogger().logDebug("findTransaction: returning : " + retval); + } + } + return retval; + + } + + /** + * Get the transaction to cancel. Search the server transaction table for a transaction that + * matches the given transaction. + */ + public SIPTransaction findCancelTransaction(SIPRequest cancelRequest, boolean isServer) { + + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("findCancelTransaction request= \n" + cancelRequest + + "\nfindCancelRequest isServer=" + isServer); + } + + if (isServer) { + Iterator<SIPServerTransaction> li = this.serverTransactionTable.values().iterator(); + while (li.hasNext()) { + SIPTransaction transaction = (SIPTransaction) li.next(); + + SIPServerTransaction sipServerTransaction = (SIPServerTransaction) transaction; + if (sipServerTransaction.doesCancelMatchTransaction(cancelRequest)) + return sipServerTransaction; + } + + } else { + Iterator<SIPClientTransaction> li = this.clientTransactionTable.values().iterator(); + while (li.hasNext()) { + SIPTransaction transaction = (SIPTransaction) li.next(); + + SIPClientTransaction sipClientTransaction = (SIPClientTransaction) transaction; + if (sipClientTransaction.doesCancelMatchTransaction(cancelRequest)) + return sipClientTransaction; + + } + + } + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("Could not find transaction for cancel request"); + return null; + } + + /** + * Construcor for the stack. Registers the request and response factories for the stack. + * + * @param messageFactory User-implemented factory for processing messages. + */ + protected SIPTransactionStack(StackMessageFactory messageFactory) { + this(); + this.sipMessageFactory = messageFactory; + } + + /** + * Finds a pending server transaction. Since each request may be handled either statefully or + * statelessly, we keep a map of pending transactions so that a duplicate transaction is not + * created if a second request is recieved while the first one is being processed. + * + * @param requestReceived + * @return -- the pending transaction or null if no such transaction exists. + */ + public SIPServerTransaction findPendingTransaction(SIPRequest requestReceived) { + if (this.stackLogger.isLoggingEnabled()) { + this.stackLogger.logDebug("looking for pending tx for :" + + requestReceived.getTransactionId()); + } + return (SIPServerTransaction) pendingTransactions.get(requestReceived.getTransactionId()); + + } + + /** + * See if there is a pending transaction with the same Merge ID as the Merge ID obtained from + * the SIP Request. The Merge table is for handling the following condition: If the request + * has no tag in the To header field, the UAS core MUST check the request against ongoing + * transactions. If the From tag, Call-ID, and CSeq exactly match those associated with an + * ongoing transaction, but the request does not match that transaction (based on the matching + * rules in Section 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and + * pass it to the server transaction. + */ + public SIPServerTransaction findMergedTransaction(SIPRequest sipRequest) { + if (! sipRequest.getMethod().equals(Request.INVITE)) { + /* + * Dont need to worry about request merging for Non-INVITE transactions. + */ + return null; + } + String mergeId = sipRequest.getMergeId(); + SIPServerTransaction mergedTransaction = (SIPServerTransaction) this.mergeTable.get(mergeId); + if (mergeId == null ) { + return null; + } else if (mergedTransaction != null && !mergedTransaction.isMessagePartOfTransaction(sipRequest) ) { + return mergedTransaction; + } else { + /* + * Check the server transactions that have resulted in dialogs. + */ + for (Dialog dialog: this.dialogTable.values() ) { + SIPDialog sipDialog = (SIPDialog) dialog ; + if (sipDialog.getFirstTransaction() != null && + sipDialog.getFirstTransaction() instanceof ServerTransaction) { + SIPServerTransaction serverTransaction = ((SIPServerTransaction) sipDialog.getFirstTransaction()); + SIPRequest transactionRequest = ((SIPServerTransaction) sipDialog.getFirstTransaction()).getOriginalRequest(); + if ( (! serverTransaction.isMessagePartOfTransaction(sipRequest)) + && sipRequest.getMergeId().equals(transactionRequest.getMergeId())) { + return (SIPServerTransaction) sipDialog.getFirstTransaction(); + } + } + } + return null; + } + } + + /** + * Remove a pending Server transaction from the stack. This is called after the user code has + * completed execution in the listener. + * + * @param tr -- pending transaction to remove. + */ + public void removePendingTransaction(SIPServerTransaction tr) { + if (this.stackLogger.isLoggingEnabled()) { + this.stackLogger.logDebug("removePendingTx: " + tr.getTransactionId()); + } + this.pendingTransactions.remove(tr.getTransactionId()); + + } + + /** + * Remove a transaction from the merge table. + * + * @param tr -- the server transaction to remove from the merge table. + * + */ + public void removeFromMergeTable(SIPServerTransaction tr) { + if (stackLogger.isLoggingEnabled()) { + this.stackLogger.logDebug("Removing tx from merge table "); + } + String key = ((SIPRequest) tr.getRequest()).getMergeId(); + if (key != null) { + this.mergeTable.remove(key); + } + } + + /** + * Put this into the merge request table. + * + * @param sipTransaction -- transaction to put into the merge table. + * + */ + public void putInMergeTable(SIPServerTransaction sipTransaction, SIPRequest sipRequest) { + String mergeKey = sipRequest.getMergeId(); + if (mergeKey != null) { + this.mergeTable.put(mergeKey, sipTransaction); + } + } + + /** + * Map a Server transaction (possibly sending out a 100 if the server tx is an INVITE). This + * actually places it in the hash table and makes it known to the stack. + * + * @param transaction -- the server transaction to map. + */ + public void mapTransaction(SIPServerTransaction transaction) { + if (transaction.isMapped) + return; + addTransactionHash(transaction); + // transaction.startTransactionTimer(); + transaction.isMapped = true; + } + + /** + * Handles a new SIP request. It finds a server transaction to handle this message. If none + * exists, it creates a new transaction. + * + * @param requestReceived Request to handle. + * @param requestMessageChannel Channel that received message. + * + * @return A server transaction. + */ + public ServerRequestInterface newSIPServerRequest(SIPRequest requestReceived, + MessageChannel requestMessageChannel) { + // Iterator through all server transactions + Iterator<SIPServerTransaction> transactionIterator; + // Next transaction in the set + SIPServerTransaction nextTransaction; + // Transaction to handle this request + SIPServerTransaction currentTransaction; + + String key = requestReceived.getTransactionId(); + + requestReceived.setMessageChannel(requestMessageChannel); + + currentTransaction = (SIPServerTransaction) serverTransactionTable.get(key); + + // Got to do this for bacasswards compatibility. + if (currentTransaction == null + || !currentTransaction.isMessagePartOfTransaction(requestReceived)) { + + // Loop through all server transactions + transactionIterator = serverTransactionTable.values().iterator(); + currentTransaction = null; + if (!key.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { + while (transactionIterator.hasNext() && currentTransaction == null) { + + nextTransaction = (SIPServerTransaction) transactionIterator.next(); + + // If this transaction should handle this request, + if (nextTransaction.isMessagePartOfTransaction(requestReceived)) { + // Mark this transaction as the one + // to handle this message + currentTransaction = nextTransaction; + } + } + } + + // If no transaction exists to handle this message + if (currentTransaction == null) { + currentTransaction = findPendingTransaction(requestReceived); + if (currentTransaction != null) { + // Associate the tx with the received request. + requestReceived.setTransaction(currentTransaction); + if (currentTransaction != null && currentTransaction.acquireSem()) + return currentTransaction; + else + return null; + + } + // Creating a new server tx. May fail under heavy load. + currentTransaction = createServerTransaction(requestMessageChannel); + if (currentTransaction != null) { + // currentTransaction.setPassToListener(); + currentTransaction.setOriginalRequest(requestReceived); + // Associate the tx with the received request. + requestReceived.setTransaction(currentTransaction); + } + + } + + } + + // Set ths transaction's encapsulated request + // interface from the superclass + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("newSIPServerRequest( " + requestReceived.getMethod() + ":" + + requestReceived.getTopmostVia().getBranch() + "):" + currentTransaction); + } + + if (currentTransaction != null) + currentTransaction.setRequestInterface(sipMessageFactory.newSIPServerRequest( + requestReceived, currentTransaction)); + + if (currentTransaction != null && currentTransaction.acquireSem()) { + return currentTransaction; + } else if (currentTransaction != null) { + try { + /* + * Already processing a message for this transaction. + * SEND a trying ( message already being processed ). + */ + if (currentTransaction.isMessagePartOfTransaction(requestReceived) && + currentTransaction.getMethod().equals(requestReceived.getMethod())) { + SIPResponse trying = requestReceived.createResponse(Response.TRYING); + trying.removeContent(); + currentTransaction.getMessageChannel().sendMessage(trying); + } + } catch (Exception ex) { + if (isLoggingEnabled()) + stackLogger.logError("Exception occured sending TRYING"); + } + return null; + } else { + return null; + } + } + + /** + * Handles a new SIP response. It finds a client transaction to handle this message. If none + * exists, it sends the message directly to the superclass. + * + * @param responseReceived Response to handle. + * @param responseMessageChannel Channel that received message. + * + * @return A client transaction. + */ + public ServerResponseInterface newSIPServerResponse(SIPResponse responseReceived, + MessageChannel responseMessageChannel) { + + // Iterator through all client transactions + Iterator<SIPClientTransaction> transactionIterator; + // Next transaction in the set + SIPClientTransaction nextTransaction; + // Transaction to handle this request + SIPClientTransaction currentTransaction; + + String key = responseReceived.getTransactionId(); + + // Note that for RFC 3261 compliant operation, this lookup will + // return a tx if one exists and hence no need to search through + // the table. + currentTransaction = (SIPClientTransaction) clientTransactionTable.get(key); + + if (currentTransaction == null + || (!currentTransaction.isMessagePartOfTransaction(responseReceived) && !key + .startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE))) { + // Loop through all client transactions + + transactionIterator = clientTransactionTable.values().iterator(); + currentTransaction = null; + while (transactionIterator.hasNext() && currentTransaction == null) { + + nextTransaction = (SIPClientTransaction) transactionIterator.next(); + + // If this transaction should handle this request, + if (nextTransaction.isMessagePartOfTransaction(responseReceived)) { + + // Mark this transaction as the one to + // handle this message + currentTransaction = nextTransaction; + + } + + } + + // If no transaction exists to handle this message, + if (currentTransaction == null) { + // JvB: Need to log before passing the response to the client + // app, it + // gets modified! + if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) { + responseMessageChannel.logResponse(responseReceived, System + .currentTimeMillis(), "before processing"); + } + + // Pass the message directly to the TU + return sipMessageFactory.newSIPServerResponse(responseReceived, + responseMessageChannel); + + } + } + + // Aquire the sem -- previous request may still be processing. + boolean acquired = currentTransaction.acquireSem(); + // Set ths transaction's encapsulated response interface + // from the superclass + if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) { + currentTransaction.logResponse(responseReceived, System.currentTimeMillis(), + "before processing"); + } + + if (acquired) { + ServerResponseInterface sri = sipMessageFactory.newSIPServerResponse( + responseReceived, currentTransaction); + if (sri != null) { + currentTransaction.setResponseInterface(sri); + } else { + if (this.stackLogger.isLoggingEnabled()) { + this.stackLogger.logDebug("returning null - serverResponseInterface is null!"); + } + currentTransaction.releaseSem(); + return null; + } + } else { + if (stackLogger.isLoggingEnabled()) + this.stackLogger.logDebug("Could not aquire semaphore !!"); + } + + if (acquired) + return currentTransaction; + else + return null; + + } + + /** + * Creates a client transaction to handle a new request. Gets the real message channel from + * the superclass, and then creates a new client transaction wrapped around this channel. + * + * @param nextHop Hop to create a channel to contact. + */ + public MessageChannel createMessageChannel(SIPRequest request, MessageProcessor mp, + Hop nextHop) throws IOException { + // New client transaction to return + SIPTransaction returnChannel; + + // Create a new client transaction around the + // superclass' message channel + // Create the host/port of the target hop + Host targetHost = new Host(); + targetHost.setHostname(nextHop.getHost()); + HostPort targetHostPort = new HostPort(); + targetHostPort.setHost(targetHost); + targetHostPort.setPort(nextHop.getPort()); + MessageChannel mc = mp.createMessageChannel(targetHostPort); + + // Superclass will return null if no message processor + // available for the transport. + if (mc == null) + return null; + + returnChannel = createClientTransaction(request, mc); + + ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort()); + ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost()); + addTransactionHash(returnChannel); + // clientTransactionTable.put(returnChannel.getTransactionId(), + // returnChannel); + // Add the transaction timer for the state machine. + // returnChannel.startTransactionTimer(); + return returnChannel; + + } + + /** + * Creates a client transaction that encapsulates a MessageChannel. Useful for implementations + * that want to subclass the standard + * + * @param encapsulatedMessageChannel Message channel of the transport layer. + */ + public SIPClientTransaction createClientTransaction(SIPRequest sipRequest, + MessageChannel encapsulatedMessageChannel) { + SIPClientTransaction ct = new SIPClientTransaction(this, encapsulatedMessageChannel); + ct.setOriginalRequest(sipRequest); + return ct; + } + + /** + * Creates a server transaction that encapsulates a MessageChannel. Useful for implementations + * that want to subclass the standard + * + * @param encapsulatedMessageChannel Message channel of the transport layer. + */ + public SIPServerTransaction createServerTransaction(MessageChannel encapsulatedMessageChannel) { + // Issue 256 : be consistent with createClientTransaction, if unlimitedServerTransactionTableSize is true, + // a new Server Transaction is created no matter what + if (unlimitedServerTransactionTableSize) { + return new SIPServerTransaction(this, encapsulatedMessageChannel); + } else { + float threshold = ((float) (serverTransactionTable.size() - serverTransactionTableLowaterMark)) + / ((float) (serverTransactionTableHighwaterMark - serverTransactionTableLowaterMark)); + boolean decision = Math.random() > 1.0 - threshold; + if (decision) { + return null; + } else { + return new SIPServerTransaction(this, encapsulatedMessageChannel); + } + + } + + } + + /** + * Get the size of the client transaction table. + * + * @return -- size of the ct table. + */ + public int getClientTransactionTableSize() { + return this.clientTransactionTable.size(); + } + + /** + * Get the size of the server transaction table. + * + * @return -- size of the server table. + */ + public int getServerTransactionTableSize() { + return this.serverTransactionTable.size(); + } + + /** + * Add a new client transaction to the set of existing transactions. Add it to the top of the + * list so an incoming response has less work to do in order to find the transaction. + * + * @param clientTransaction -- client transaction to add to the set. + */ + public void addTransaction(SIPClientTransaction clientTransaction) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("added transaction " + clientTransaction); + addTransactionHash(clientTransaction); + + } + + /** + * Remove transaction. This actually gets the tx out of the search structures which the stack + * keeps around. When the tx + */ + public void removeTransaction(SIPTransaction sipTransaction) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("Removing Transaction = " + sipTransaction.getTransactionId() + + " transaction = " + sipTransaction); + } + if (sipTransaction instanceof SIPServerTransaction) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logStackTrace(); + String key = sipTransaction.getTransactionId(); + Object removed = serverTransactionTable.remove(key); + String method = sipTransaction.getMethod(); + this.removePendingTransaction((SIPServerTransaction) sipTransaction); + this.removeTransactionPendingAck((SIPServerTransaction) sipTransaction); + if (method.equalsIgnoreCase(Request.INVITE)) { + this.removeFromMergeTable((SIPServerTransaction) sipTransaction); + } + // Send a notification to the listener. + SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider(); + if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) { + TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider, + (ServerTransaction) sipTransaction); + + sipProvider.handleEvent(event, sipTransaction); + + } + } else { + + String key = sipTransaction.getTransactionId(); + Object removed = clientTransactionTable.remove(key); + + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("REMOVED client tx " + removed + " KEY = " + key); + if ( removed != null ) { + SIPClientTransaction clientTx = (SIPClientTransaction)removed; + if ( clientTx.getMethod().equals(Request.INVITE) && this.maxForkTime != 0 ) { + RemoveForkedTransactionTimerTask ttask = new RemoveForkedTransactionTimerTask(clientTx); + this.timer.schedule(ttask, this.maxForkTime * 1000); + } + } + } + + // Send a notification to the listener. + if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) { + SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider(); + TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider, + (ClientTransaction) sipTransaction); + + sipProvider.handleEvent(event, sipTransaction); + } + + } + } + + /** + * Add a new server transaction to the set of existing transactions. Add it to the top of the + * list so an incoming ack has less work to do in order to find the transaction. + * + * @param serverTransaction -- server transaction to add to the set. + */ + public void addTransaction(SIPServerTransaction serverTransaction) throws IOException { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("added transaction " + serverTransaction); + serverTransaction.map(); + + addTransactionHash(serverTransaction); + + } + + /** + * Hash table for quick lookup of transactions. Here we wait for room if needed. + */ + private void addTransactionHash(SIPTransaction sipTransaction) { + SIPRequest sipRequest = sipTransaction.getOriginalRequest(); + if (sipTransaction instanceof SIPClientTransaction) { + if (!this.unlimitedClientTransactionTableSize) { + if (this.activeClientTransactionCount.get() > clientTransactionTableHiwaterMark) { + try { + synchronized (this.clientTransactionTable) { + this.clientTransactionTable.wait(); + this.activeClientTransactionCount.incrementAndGet(); + } + + } catch (Exception ex) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logError("Exception occured while waiting for room", ex); + } + + } + } + } else { + this.activeClientTransactionCount.incrementAndGet(); + } + String key = sipRequest.getTransactionId(); + clientTransactionTable.put(key, (SIPClientTransaction) sipTransaction); + + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug(" putTransactionHash : " + " key = " + key); + } + } else { + String key = sipRequest.getTransactionId(); + + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug(" putTransactionHash : " + " key = " + key); + } + serverTransactionTable.put(key, (SIPServerTransaction) sipTransaction); + + } + + } + + /** + * This method is called when a client tx transitions to the Completed or Terminated state. + * + */ + protected void decrementActiveClientTransactionCount() { + + if (this.activeClientTransactionCount.decrementAndGet() <= this.clientTransactionTableLowaterMark + && !this.unlimitedClientTransactionTableSize) { + synchronized (this.clientTransactionTable) { + + clientTransactionTable.notify(); + + } + } + } + + /** + * Remove the transaction from transaction hash. + */ + protected void removeTransactionHash(SIPTransaction sipTransaction) { + SIPRequest sipRequest = sipTransaction.getOriginalRequest(); + if (sipRequest == null) + return; + if (sipTransaction instanceof SIPClientTransaction) { + String key = sipTransaction.getTransactionId(); + if (stackLogger.isLoggingEnabled()) { + stackLogger.logStackTrace(); + stackLogger.logDebug("removing client Tx : " + key); + } + clientTransactionTable.remove(key); + + } else if (sipTransaction instanceof SIPServerTransaction) { + String key = sipTransaction.getTransactionId(); + serverTransactionTable.remove(key); + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("removing server Tx : " + key); + } + } + } + + /** + * Invoked when an error has ocurred with a transaction. + * + * @param transactionErrorEvent Error event. + */ + public synchronized void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent) { + SIPTransaction transaction = (SIPTransaction) transactionErrorEvent.getSource(); + + if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) { + // Kill scanning of this transaction. + transaction.setState(SIPTransaction.TERMINATED_STATE); + if (transaction instanceof SIPServerTransaction) { + // let the reaper get him + ((SIPServerTransaction) transaction).collectionTime = 0; + } + transaction.disableTimeoutTimer(); + transaction.disableRetransmissionTimer(); + // Send a IO Exception to the Listener. + } + } + + /* + * (non-Javadoc) + * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent) + */ + public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) { + SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource(); + SipListener sipListener = ((SipStackImpl)this).getSipListener(); + // if the app is not implementing the SipListenerExt interface we delete the dialog to avoid leaks + if(sipDialog != null && !(sipListener instanceof SipListenerExt)) { + sipDialog.delete(); + } + } + + /** + * Stop stack. Clear all the timer stuff. Make the stack close all accept connections and + * return. This is useful if you want to start/stop the stack several times from your + * application. Caution : use of this function could cause peculiar bugs as messages are + * prcessed asynchronously by the stack. + */ + public void stopStack() { + // Prevent NPE on two concurrent stops + if (this.timer != null) + this.timer.cancel(); + + // JvB: set it to null, SIPDialog tries to schedule things after stop + timer = null; + this.pendingTransactions.clear(); + this.toExit = true; + synchronized (this) { + this.notifyAll(); + } + synchronized (this.clientTransactionTable) { + clientTransactionTable.notifyAll(); + } + + synchronized (this.messageProcessors) { + // Threads must periodically check this flag. + MessageProcessor[] processorList; + processorList = getMessageProcessors(); + for (int processorIndex = 0; processorIndex < processorList.length; processorIndex++) { + removeMessageProcessor(processorList[processorIndex]); + } + this.ioHandler.closeAll(); + // Let the processing complete. + + } + try { + + Thread.sleep(1000); + + } catch (InterruptedException ex) { + } + this.clientTransactionTable.clear(); + this.serverTransactionTable.clear(); + + this.dialogTable.clear(); + this.serverLogger.closeLogFile(); + + } + + /** + * Put a transaction in the pending transaction list. This is to avoid a race condition when a + * duplicate may arrive when the application is deciding whether to create a transaction or + * not. + */ + public void putPendingTransaction(SIPServerTransaction tr) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("putPendingTransaction: " + tr); + + this.pendingTransactions.put(tr.getTransactionId(), tr); + + } + + /** + * Return the network layer (i.e. the interface for socket creation or the socket factory for + * the stack). + * + * @return -- the registered Network Layer. + */ + public NetworkLayer getNetworkLayer() { + if (networkLayer == null) { + return DefaultNetworkLayer.SINGLETON; + } else { + return networkLayer; + } + } + + /** + * Return true if logging is enabled for this stack. + * + * @return true if logging is enabled for this stack instance. + */ + public boolean isLoggingEnabled() { + return this.stackLogger == null ? false : this.stackLogger.isLoggingEnabled(); + } + + /** + * Get the logger. + * + * @return --the logger for the sip stack. Each stack has its own logger instance. + */ + public StackLogger getStackLogger() { + return this.stackLogger; + } + + /** + * Server log is the place where we log messages for the signaling trace viewer. + * + * @return -- the log file where messages are logged for viewing by the trace viewer. + */ + public ServerLogger getServerLogger() { + return this.serverLogger; + } + + /** + * Maximum size of a single TCP message. Limiting the size of a single TCP message prevents + * flooding attacks. + * + * @return the size of a single TCP message. + */ + public int getMaxMessageSize() { + return this.maxMessageSize; + } + + /** + * Set the flag that instructs the stack to only start a single thread for sequentially + * processing incoming udp messages (thus serializing the processing). Same as setting thread + * pool size to 1. + */ + public void setSingleThreaded() { + this.threadPoolSize = 1; + } + + /** + * Set the thread pool size for processing incoming UDP messages. Limit the total number of + * threads for processing udp messages. + * + * @param size -- the thread pool size. + * + */ + public void setThreadPoolSize(int size) { + this.threadPoolSize = size; + } + + /** + * Set the max # of simultaneously handled TCP connections. + * + * @param nconnections -- the number of connections to handle. + */ + public void setMaxConnections(int nconnections) { + this.maxConnections = nconnections; + } + + /** + * Get the default route string. + * + * @param sipRequest is the request for which we want to compute the next hop. + * @throws SipException + */ + public Hop getNextHop(SIPRequest sipRequest) throws SipException { + if (this.useRouterForAll) { + // Use custom router to route all messages. + if (router != null) + return router.getNextHop(sipRequest); + else + return null; + } else { + // Also non-SIP request containing Route headers goes to the default + // router + if (sipRequest.getRequestURI().isSipURI() || sipRequest.getRouteHeaders() != null) { + return defaultRouter.getNextHop(sipRequest); + } else if (router != null) { + return router.getNextHop(sipRequest); + } else + return null; + } + } + + /** + * Set the descriptive name of the stack. + * + * @param stackName -- descriptive name of the stack. + */ + public void setStackName(String stackName) { + this.stackName = stackName; + } + + + + /** + * Set my address. + * + * @param stackAddress -- A string containing the stack address. + */ + protected void setHostAddress(String stackAddress) throws UnknownHostException { + if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':') + && stackAddress.trim().charAt(0) != '[') + this.stackAddress = '[' + stackAddress + ']'; + else + this.stackAddress = stackAddress; + this.stackInetAddress = InetAddress.getByName(stackAddress); + } + + /** + * Get my address. + * + * @return hostAddress - my host address or null if no host address is defined. + * @deprecated + */ + public String getHostAddress() { + + // JvB: for 1.2 this may return null... + return this.stackAddress; + } + + /** + * Set the router algorithm. This is meant for routing messages out of dialog or for non-sip + * uri's. + * + * @param router A class that implements the Router interface. + */ + protected void setRouter(Router router) { + this.router = router; + } + + /** + * Get the router algorithm. + * + * @return Router router + */ + public Router getRouter(SIPRequest request) { + if (request.getRequestLine() == null) { + return this.defaultRouter; + } else if (this.useRouterForAll) { + return this.router; + } else { + if (request.getRequestURI().getScheme().equals("sip") + || request.getRequestURI().getScheme().equals("sips")) { + return this.defaultRouter; + } else { + if (this.router != null) + return this.router; + else + return defaultRouter; + } + } + } + + /* + * (non-Javadoc) + * + * @see javax.sip.SipStack#getRouter() + */ + public Router getRouter() { + return this.router; + } + + /** + * return the status of the toExit flag. + * + * @return true if the stack object is alive and false otherwise. + */ + public boolean isAlive() { + return !toExit; + } + + /** + * Adds a new MessageProcessor to the list of running processors for this SIPStack and starts + * it. You can use this method for dynamic stack configuration. + */ + protected void addMessageProcessor(MessageProcessor newMessageProcessor) throws IOException { + synchronized (messageProcessors) { + // Suggested changes by Jeyashankher, jai@lucent.com + // newMessageProcessor.start() can fail + // because a local port is not available + // This throws an IOException. + // We should not add the message processor to the + // local list of processors unless the start() + // call is successful. + // newMessageProcessor.start(); + messageProcessors.add(newMessageProcessor); + + } + } + + /** + * Removes a MessageProcessor from this SIPStack. + * + * @param oldMessageProcessor + */ + protected void removeMessageProcessor(MessageProcessor oldMessageProcessor) { + synchronized (messageProcessors) { + if (messageProcessors.remove(oldMessageProcessor)) { + oldMessageProcessor.stop(); + } + } + } + + /** + * Gets an array of running MessageProcessors on this SIPStack. Acknowledgement: Jeff Keyser + * suggested that applications should have access to the running message processors and + * contributed this code. + * + * @return an array of running message processors. + */ + protected MessageProcessor[] getMessageProcessors() { + synchronized (messageProcessors) { + return (MessageProcessor[]) messageProcessors.toArray(new MessageProcessor[0]); + } + } + + /** + * Creates the equivalent of a JAIN listening point and attaches to the stack. + * + * @param ipAddress -- ip address for the listening point. + * @param port -- port for the listening point. + * @param transport -- transport for the listening point. + */ + protected MessageProcessor createMessageProcessor(InetAddress ipAddress, int port, + String transport) throws java.io.IOException { + if (transport.equalsIgnoreCase("udp")) { + UDPMessageProcessor udpMessageProcessor = new UDPMessageProcessor(ipAddress, this, + port); + this.addMessageProcessor(udpMessageProcessor); + this.udpFlag = true; + return udpMessageProcessor; + } else if (transport.equalsIgnoreCase("tcp")) { + TCPMessageProcessor tcpMessageProcessor = new TCPMessageProcessor(ipAddress, this, + port); + this.addMessageProcessor(tcpMessageProcessor); + // this.tcpFlag = true; + return tcpMessageProcessor; + } else if (transport.equalsIgnoreCase("tls")) { + TLSMessageProcessor tlsMessageProcessor = new TLSMessageProcessor(ipAddress, this, + port); + this.addMessageProcessor(tlsMessageProcessor); + // this.tlsFlag = true; + return tlsMessageProcessor; + } else if (transport.equalsIgnoreCase("sctp")) { + + // Need Java 7 for this, so these classes are packaged in a separate jar + // Try to load it indirectly, if fails report an error + try { + Class<?> mpc = ClassLoader.getSystemClassLoader().loadClass( "gov.nist.javax.sip.stack.sctp.SCTPMessageProcessor" ); + MessageProcessor mp = (MessageProcessor) mpc.newInstance(); + mp.initialize( ipAddress, port, this ); + this.addMessageProcessor(mp); + return mp; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("SCTP not supported (needs Java 7 and SCTP jar in classpath)"); + } catch ( InstantiationException ie ) { + throw new IllegalArgumentException("Error initializing SCTP", ie); + } catch ( IllegalAccessException ie ) { + throw new IllegalArgumentException("Error initializing SCTP", ie); + } + } else { + throw new IllegalArgumentException("bad transport"); + } + + } + + /** + * Set the message factory. + * + * @param messageFactory -- messageFactory to set. + */ + protected void setMessageFactory(StackMessageFactory messageFactory) { + this.sipMessageFactory = messageFactory; + } + + /** + * Creates a new MessageChannel for a given Hop. + * + * @param sourceIpAddress - Ip address of the source of this message. + * + * @param sourcePort - source port of the message channel to be created. + * + * @param nextHop Hop to create a MessageChannel to. + * + * @return A MessageChannel to the specified Hop, or null if no MessageProcessors support + * contacting that Hop. + * + * @throws UnknownHostException If the host in the Hop doesn't exist. + */ + public MessageChannel createRawMessageChannel(String sourceIpAddress, int sourcePort, + Hop nextHop) throws UnknownHostException { + Host targetHost; + HostPort targetHostPort; + Iterator processorIterator; + MessageProcessor nextProcessor; + MessageChannel newChannel; + + // Create the host/port of the target hop + targetHost = new Host(); + targetHost.setHostname(nextHop.getHost()); + targetHostPort = new HostPort(); + targetHostPort.setHost(targetHost); + targetHostPort.setPort(nextHop.getPort()); + + // Search each processor for the correct transport + newChannel = null; + processorIterator = messageProcessors.iterator(); + while (processorIterator.hasNext() && newChannel == null) { + nextProcessor = (MessageProcessor) processorIterator.next(); + // If a processor that supports the correct + // transport is found, + if (nextHop.getTransport().equalsIgnoreCase(nextProcessor.getTransport()) + && sourceIpAddress.equals(nextProcessor.getIpAddress().getHostAddress()) + && sourcePort == nextProcessor.getPort()) { + try { + // Create a channel to the target + // host/port + newChannel = nextProcessor.createMessageChannel(targetHostPort); + } catch (UnknownHostException ex) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logException(ex); + throw ex; + } catch (IOException e) { + if (stackLogger.isLoggingEnabled()) + stackLogger.logException(e); + // Ignore channel creation error - + // try next processor + } + } + } + // Return the newly-created channel + return newChannel; + } + + /** + * Return true if a given event can result in a forked subscription. The stack is configured + * with a set of event names that can result in forked subscriptions. + * + * @param ename -- event name to check. + * + */ + public boolean isEventForked(String ename) { + if (stackLogger.isLoggingEnabled()) { + stackLogger.logDebug("isEventForked: " + ename + " returning " + + this.forkedEvents.contains(ename)); + } + return this.forkedEvents.contains(ename); + } + + /** + * get the address resolver interface. + * + * @return -- the registered address resolver. + */ + public AddressResolver getAddressResolver() { + return this.addressResolver; + } + + /** + * Set the address resolution interface + * + * @param addressResolver -- the address resolver to set. + */ + public void setAddressResolver(AddressResolver addressResolver) { + this.addressResolver = addressResolver; + } + + /** + * Set the logger factory. + * + * @param logRecordFactory -- the log record factory to set. + */ + public void setLogRecordFactory(LogRecordFactory logRecordFactory) { + this.logRecordFactory = logRecordFactory; + } + + /** + * get the thread auditor object + * + * @return -- the thread auditor of the stack + */ + public ThreadAuditor getThreadAuditor() { + return this.threadAuditor; + } + + // / + // / Stack Audit methods + // / + + /** + * Audits the SIP Stack for leaks + * + * @return Audit report, null if no leaks were found + */ + public String auditStack(Set activeCallIDs, long leakedDialogTimer, + long leakedTransactionTimer) { + String auditReport = null; + String leakedDialogs = auditDialogs(activeCallIDs, leakedDialogTimer); + String leakedServerTransactions = auditTransactions(serverTransactionTable, + leakedTransactionTimer); + String leakedClientTransactions = auditTransactions(clientTransactionTable, + leakedTransactionTimer); + if (leakedDialogs != null || leakedServerTransactions != null + || leakedClientTransactions != null) { + auditReport = "SIP Stack Audit:\n" + (leakedDialogs != null ? leakedDialogs : "") + + (leakedServerTransactions != null ? leakedServerTransactions : "") + + (leakedClientTransactions != null ? leakedClientTransactions : ""); + } + return auditReport; + } + + /** + * Audits SIP dialogs for leaks - Compares the dialogs in the dialogTable with a list of Call + * IDs passed by the application. - Dialogs that are not known by the application are leak + * suspects. - Kill the dialogs that are still around after the timer specified. + * + * @return Audit report, null if no dialog leaks were found + */ + private String auditDialogs(Set activeCallIDs, long leakedDialogTimer) { + String auditReport = " Leaked dialogs:\n"; + int leakedDialogs = 0; + long currentTime = System.currentTimeMillis(); + + // Make a shallow copy of the dialog list. + // This copy will remain intact as leaked dialogs are removed by the + // stack. + LinkedList dialogs; + synchronized (dialogTable) { + dialogs = new LinkedList(dialogTable.values()); + } + + // Iterate through the dialogDialog, get the callID of each dialog and + // check if it's in the + // list of active calls passed by the application. If it isn't, start + // the timer on it. + // If the timer has expired, kill the dialog. + Iterator it = dialogs.iterator(); + while (it.hasNext()) { + // Get the next dialog + SIPDialog itDialog = (SIPDialog) it.next(); + + // Get the call id associated with this dialog + CallIdHeader callIdHeader = (itDialog != null ? itDialog.getCallId() : null); + String callID = (callIdHeader != null ? callIdHeader.getCallId() : null); + + // Check if the application knows about this call id + if (itDialog != null && callID != null && !activeCallIDs.contains(callID)) { + // Application doesn't know anything about this dialog... + if (itDialog.auditTag == 0) { + // Mark this dialog as suspect + itDialog.auditTag = currentTime; + } else { + // We already audited this dialog before. Check if his + // time's up. + if (currentTime - itDialog.auditTag >= leakedDialogTimer) { + // Leaked dialog found + leakedDialogs++; + + // Generate report + DialogState dialogState = itDialog.getState(); + String dialogReport = "dialog id: " + itDialog.getDialogId() + + ", dialog state: " + + (dialogState != null ? dialogState.toString() : "null"); + auditReport += " " + dialogReport + "\n"; + + // Kill it + itDialog.setState(SIPDialog.TERMINATED_STATE); + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("auditDialogs: leaked " + dialogReport); + } + } + } + } + + // Return final report + if (leakedDialogs > 0) { + auditReport += " Total: " + Integer.toString(leakedDialogs) + + " leaked dialogs detected and removed.\n"; + } else { + auditReport = null; + } + return auditReport; + } + + /** + * Audits SIP transactions for leaks + * + * @return Audit report, null if no transaction leaks were found + */ + private String auditTransactions(ConcurrentHashMap transactionsMap, + long a_nLeakedTransactionTimer) { + String auditReport = " Leaked transactions:\n"; + int leakedTransactions = 0; + long currentTime = System.currentTimeMillis(); + + // Make a shallow copy of the transaction list. + // This copy will remain intact as leaked transactions are removed by + // the stack. + LinkedList transactionsList = new LinkedList(transactionsMap.values()); + + // Iterate through our copy + Iterator it = transactionsList.iterator(); + while (it.hasNext()) { + SIPTransaction sipTransaction = (SIPTransaction) it.next(); + if (sipTransaction != null) { + if (sipTransaction.auditTag == 0) { + // First time we see this transaction. Mark it as audited. + sipTransaction.auditTag = currentTime; + } else { + // We've seen this transaction before. Check if his time's + // up. + if (currentTime - sipTransaction.auditTag >= a_nLeakedTransactionTimer) { + // Leaked transaction found + leakedTransactions++; + + // Generate some report + TransactionState transactionState = sipTransaction.getState(); + SIPRequest origRequest = sipTransaction.getOriginalRequest(); + String origRequestMethod = (origRequest != null ? origRequest.getMethod() + : null); + String transactionReport = sipTransaction.getClass().getName() + + ", state: " + + (transactionState != null ? transactionState.toString() + : "null") + ", OR: " + + (origRequestMethod != null ? origRequestMethod : "null"); + auditReport += " " + transactionReport + "\n"; + + // Kill it + removeTransaction(sipTransaction); + if (isLoggingEnabled()) + stackLogger.logDebug("auditTransactions: leaked " + transactionReport); + } + } + } + } + + // Return final report + if (leakedTransactions > 0) { + auditReport += " Total: " + Integer.toString(leakedTransactions) + + " leaked transactions detected and removed.\n"; + } else { + auditReport = null; + } + return auditReport; + } + + public void setNon2XXAckPassedToListener(boolean passToListener) { + this.non2XXAckPassedToListener = passToListener; + } + + /** + * @return the non2XXAckPassedToListener + */ + public boolean isNon2XXAckPassedToListener() { + return non2XXAckPassedToListener; + } + + /** + * Get the count of client transactions that is not in the completed or terminated state. + * + * @return the activeClientTransactionCount + */ + public int getActiveClientTransactionCount() { + return activeClientTransactionCount.get(); + } + + public boolean isRfc2543Supported() { + + return this.rfc2543Supported; + } + + public boolean isCancelClientTransactionChecked() { + return this.cancelClientTransactionChecked; + } + + public boolean isRemoteTagReassignmentAllowed() { + return this.remoteTagReassignmentAllowed; + } + + /** + * This method is slated for addition to the next spec revision. + * + * + * @return -- the collection of dialogs that is being managed by the stack. + */ + public Collection<Dialog> getDialogs() { + HashSet<Dialog> dialogs = new HashSet<Dialog>(); + dialogs.addAll(this.dialogTable.values()); + dialogs.addAll(this.earlyDialogTable.values()); + return dialogs; + } + + /** + * + * @return -- the collection of dialogs matching the state that is being managed by the stack. + */ + public Collection<Dialog> getDialogs(DialogState state) { + HashSet<Dialog> matchingDialogs = new HashSet<Dialog>(); + if (DialogState.EARLY.equals(state)) { + matchingDialogs.addAll(this.earlyDialogTable.values()); + } else { + Collection<SIPDialog> dialogs = dialogTable.values(); + for (SIPDialog dialog : dialogs) { + if (dialog.getState() != null && dialog.getState().equals(state)) { + matchingDialogs.add(dialog); + } + } + } + return matchingDialogs; + } + + /** + * Get the Replaced Dialog from the stack. + * + * @param replacesHeader -- the header that references the dialog being replaced. + */ + public Dialog getReplacesDialog(ReplacesHeader replacesHeader) { + String cid = replacesHeader.getCallId(); + String fromTag = replacesHeader.getFromTag(); + String toTag = replacesHeader.getToTag(); + + StringBuffer dialogId = new StringBuffer(cid); + + // retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + dialogId.append(":"); + dialogId.append(toTag); + } + // retval.append(COLON).append(from.getUserAtHostPort()); + if (fromTag != null) { + dialogId.append(":"); + dialogId.append(fromTag); + } + String did = dialogId.toString().toLowerCase(); + if (stackLogger.isLoggingEnabled()) + stackLogger.logDebug("Looking for dialog " + did); + /* + * Check if we can find this dialog in our dialog table. + */ + Dialog replacesDialog = this.dialogTable.get(did); + /* + * This could be a forked dialog. Search for it. + */ + if ( replacesDialog == null ) { + for ( SIPClientTransaction ctx : this.clientTransactionTable.values()) { + if ( ctx.getDialog(did) != null ) { + replacesDialog = ctx.getDialog(did); + break; + } + } + } + + return replacesDialog; + } + + /** + * Get the Join Dialog from the stack. + * + * @param joinHeader -- the header that references the dialog being joined. + */ + public Dialog getJoinDialog(JoinHeader joinHeader) { + String cid = joinHeader.getCallId(); + String fromTag = joinHeader.getFromTag(); + String toTag = joinHeader.getToTag(); + + StringBuffer retval = new StringBuffer(cid); + + // retval.append(COLON).append(to.getUserAtHostPort()); + if (toTag != null) { + retval.append(":"); + retval.append(toTag); + } + // retval.append(COLON).append(from.getUserAtHostPort()); + if (fromTag != null) { + retval.append(":"); + retval.append(fromTag); + } + return this.dialogTable.get(retval.toString().toLowerCase()); + } + + /** + * @param timer the timer to set + */ + public void setTimer(Timer timer) { + this.timer = timer; + } + + /** + * @return the timer + */ + public Timer getTimer() { + return timer; + } + + + /** + * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer + * is better under load. + * + * @return + */ + public int getReceiveUdpBufferSize() { + return receiveUdpBufferSize; + } + + /** + * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer + * is better under load. + * + * @return + */ + public void setReceiveUdpBufferSize(int receiveUdpBufferSize) { + this.receiveUdpBufferSize = receiveUdpBufferSize; + } + + /** + * Size of the send UDP buffer. This property affects performance under load. Bigger buffer + * is better under load. + * + * @return + */ + public int getSendUdpBufferSize() { + return sendUdpBufferSize; + } + + /** + * Size of the send UDP buffer. This property affects performance under load. Bigger buffer + * is better under load. + * + * @return + */ + public void setSendUdpBufferSize(int sendUdpBufferSize) { + this.sendUdpBufferSize = sendUdpBufferSize; + } + + /** + * @param stackLogger the stackLogger to set + */ + public void setStackLogger(StackLogger stackLogger) { + this.stackLogger = stackLogger; + } + + /** + * Flag that reqests checking of branch IDs on responses. + * + * @return + */ + public boolean checkBranchId() { + return this.checkBranchId; + } + + /** + * @param logStackTraceOnMessageSend the logStackTraceOnMessageSend to set + */ + public void setLogStackTraceOnMessageSend(boolean logStackTraceOnMessageSend) { + this.logStackTraceOnMessageSend = logStackTraceOnMessageSend; + } + + /** + * @return the logStackTraceOnMessageSend + */ + public boolean isLogStackTraceOnMessageSend() { + return logStackTraceOnMessageSend; + } + + public void setDeliverDialogTerminatedEventForNullDialog() { + this.isDialogTerminatedEventDeliveredForNullDialog = true; + } + + public void addForkedClientTransaction(SIPClientTransaction clientTransaction) { + this.forkedClientTransactionTable.put(clientTransaction.getTransactionId(), clientTransaction ); + } + + public SIPClientTransaction getForkedTransaction(String transactionId) { + return this.forkedClientTransactionTable.get(transactionId); + } + + +} diff --git a/java/gov/nist/javax/sip/stack/ServerLog.java b/java/gov/nist/javax/sip/stack/ServerLog.java new file mode 100644 index 0000000..4576ddf --- /dev/null +++ b/java/gov/nist/javax/sip/stack/ServerLog.java @@ -0,0 +1,466 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ + +package gov.nist.javax.sip.stack; + +import gov.nist.core.ServerLogger; +import gov.nist.core.StackLogger; +import gov.nist.javax.sip.LogRecord; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.message.SIPMessage; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; + +import javax.sip.SipStack; +import javax.sip.header.TimeStampHeader; + +// BEGIN android-deleted +// import org.apache.log4j.Level; +// import org.apache.log4j.Logger; +// END android-deleted + +/** + * Log file wrapper class. Log messages into the message trace file and also write the log into + * the debug file if needed. This class keeps an XML formatted trace around for later access via + * RMI. The trace can be viewed with a trace viewer (see tools.traceviewerapp). + * + * @version 1.2 $Revision: 1.39 $ $Date: 2009/11/11 14:00:58 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class ServerLog implements ServerLogger { + + private boolean logContent; + + protected StackLogger stackLogger; + + /** + * Name of the log file in which the trace is written out (default is null) + */ + private String logFileName; + + /** + * Print writer that is used to write out the log file. + */ + private PrintWriter printWriter; + + /** + * Set auxililary information to log with this trace. + */ + private String auxInfo; + + private String description; + + private String stackIpAddress; + + private SIPTransactionStack sipStack; + + private Properties configurationProperties; + + public ServerLog() { + // Debug log file. Whatever gets logged by us also makes its way into debug log. + } + + private void setProperties(Properties configurationProperties) { + this.configurationProperties = configurationProperties; + // Set a descriptive name for the message trace logger. + this.description = configurationProperties.getProperty("javax.sip.STACK_NAME"); + this.stackIpAddress = configurationProperties.getProperty("javax.sip.IP_ADDRESS"); + this.logFileName = configurationProperties.getProperty("gov.nist.javax.sip.SERVER_LOG"); + String logLevel = configurationProperties.getProperty("gov.nist.javax.sip.TRACE_LEVEL"); + String logContent = configurationProperties + .getProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT"); + + this.logContent = (logContent != null && logContent.equals("true")); + + if (logLevel != null) { + if (logLevel.equals("LOG4J")) { + // if TRACE_LEVEL property is specified as + // "LOG4J" then, set the traceLevel based on + // the log4j effective log level. + + // check whether a Log4j logger name has been + // specified. if not, use the stack name as the default + // logger name. + + // BEGIN android-deleted + /* + Logger logger = Logger.getLogger(configurationProperties.getProperty( + "gov.nist.javax.sip.LOG4J_LOGGER_NAME", this.description)); + Level level = logger.getEffectiveLevel(); + if (level == Level.OFF) { + this.setTraceLevel(0); + } else if (level.isGreaterOrEqual(Level.DEBUG)) { + this.setTraceLevel(TRACE_DEBUG); + } else if (level.isGreaterOrEqual(Level.INFO)) { + this.setTraceLevel(TRACE_MESSAGES); + } else if (level.isGreaterOrEqual(Level.WARN)) { + this.setTraceLevel(TRACE_EXCEPTION); + } + */ + // END android-deleted + } else { + try { + int ll; + if (logLevel.equals("DEBUG")) { + ll = TRACE_DEBUG; + } else if (logLevel.equals("INFO")) { + ll = TRACE_MESSAGES; + } else if (logLevel.equals("ERROR")) { + ll = TRACE_EXCEPTION; + } else if (logLevel.equals("NONE") || logLevel.equals("OFF")) { + ll = TRACE_NONE; + } else { + ll = Integer.parseInt(logLevel); + } + + this.setTraceLevel(ll); + } catch (NumberFormatException ex) { + System.out.println("ServerLog: WARNING Bad integer " + logLevel); + System.out.println("logging dislabled "); + this.setTraceLevel(0); + } + } + } + checkLogFile(); + + } + + public void setStackIpAddress(String ipAddress) { + this.stackIpAddress = ipAddress; + } + + // public static boolean isWebTesterCatchException=false; + // public static String webTesterLogFile=null; + + /** + * default trace level + */ + protected int traceLevel = TRACE_MESSAGES; + + public synchronized void closeLogFile() { + if (printWriter != null) { + printWriter.close(); + printWriter = null; + } + } + + public void checkLogFile() { + if (logFileName == null || traceLevel < TRACE_MESSAGES) { + // Dont create a log file if tracing is + // disabled. + return; + } + try { + File logFile = new File(logFileName); + if (!logFile.exists()) { + logFile.createNewFile(); + printWriter = null; + } + // Append buffer to the end of the file unless otherwise specified + // by the user. + if (printWriter == null) { + boolean overwrite = Boolean.valueOf( + configurationProperties.getProperty( + "gov.nist.javax.sip.SERVER_LOG_OVERWRITE")); + + FileWriter fw = new FileWriter(logFileName, !overwrite); + + printWriter = new PrintWriter(fw, true); + printWriter.println("<!-- " + + "Use the Trace Viewer in src/tools/tracesviewer to" + + " view this trace \n" + + "Here are the stack configuration properties \n" + + "javax.sip.IP_ADDRESS= " + + configurationProperties.getProperty("javax.sip.IP_ADDRESS") + "\n" + + "javax.sip.STACK_NAME= " + + configurationProperties.getProperty("javax.sip.STACK_NAME") + "\n" + + "javax.sip.ROUTER_PATH= " + + configurationProperties.getProperty("javax.sip.ROUTER_PATH") + "\n" + + "javax.sip.OUTBOUND_PROXY= " + + configurationProperties.getProperty("javax.sip.OUTBOUND_PROXY") + "\n" + + "-->"); + printWriter.println("<description\n logDescription=\"" + description + + "\"\n name=\"" + + configurationProperties.getProperty("javax.sip.STACK_NAME") + + "\"\n auxInfo=\"" + auxInfo + "\"/>\n "); + if (auxInfo != null) { + + if (sipStack.isLoggingEnabled()) { + stackLogger + .logDebug("Here are the stack configuration properties \n" + + "javax.sip.IP_ADDRESS= " + + configurationProperties + .getProperty("javax.sip.IP_ADDRESS") + + "\n" + + "javax.sip.ROUTER_PATH= " + + configurationProperties + .getProperty("javax.sip.ROUTER_PATH") + + "\n" + + "javax.sip.OUTBOUND_PROXY= " + + configurationProperties + .getProperty("javax.sip.OUTBOUND_PROXY") + + "\n" + + "gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS= " + + configurationProperties + .getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS") + + "\n" + + "gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS= " + + configurationProperties + .getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS") + + "\n" + + "gov.nist.javax.sip.REENTRANT_LISTENER= " + + configurationProperties + .getProperty("gov.nist.javax.sip.REENTRANT_LISTENER") + + "gov.nist.javax.sip.THREAD_POOL_SIZE= " + + configurationProperties + .getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE") + + "\n"); + stackLogger.logDebug(" ]]> "); + stackLogger.logDebug("</debug>"); + stackLogger.logDebug("<description\n logDescription=\"" + description + + "\"\n name=\"" + stackIpAddress + "\"\n auxInfo=\"" + auxInfo + + "\"/>\n "); + stackLogger.logDebug("<debug>"); + stackLogger.logDebug("<![CDATA[ "); + } + } else { + + if (sipStack.isLoggingEnabled()) { + stackLogger.logDebug("Here are the stack configuration properties \n" + + configurationProperties + "\n"); + stackLogger.logDebug(" ]]>"); + stackLogger.logDebug("</debug>"); + stackLogger.logDebug("<description\n logDescription=\"" + description + + "\"\n name=\"" + stackIpAddress + "\" />\n"); + stackLogger.logDebug("<debug>"); + stackLogger.logDebug("<![CDATA[ "); + } + } + } + } catch (IOException ex) { + + } + } + + /** + * Global check for whether to log or not. To minimize the time return false here. + * + * @return true -- if logging is globally enabled and false otherwise. + * + */ + public boolean needsLogging() { + return logFileName != null; + } + + /** + * Set the log file name + * + * @param name is the name of the log file to set. + */ + public void setLogFileName(String name) { + logFileName = name; + } + + /** + * return the name of the log file. + */ + public String getLogFileName() { + return logFileName; + } + + /** + * Log a message into the log file. + * + * @param message message to log into the log file. + */ + private void logMessage(String message) { + // String tname = Thread.currentThread().getName(); + checkLogFile(); + String logInfo = message; + if (printWriter != null) { + printWriter.println(logInfo); + } + if (sipStack.isLoggingEnabled()) { + stackLogger.logInfo(logInfo); + + } + } + + private void logMessage(String message, String from, String to, boolean sender, + String callId, String firstLine, String status, String tid, long time, + long timestampVal) { + + LogRecord log = this.sipStack.logRecordFactory.createLogRecord(message, from, to, time, + sender, firstLine, tid, callId, timestampVal); + if (log != null) + logMessage(log.toString()); + } + + /** + * Log a message into the log directory. + * + * @param message a SIPMessage to log + * @param from from header of the message to log into the log directory + * @param to to header of the message to log into the log directory + * @param sender is the server the sender + * @param time is the time to associate with the message. + */ + public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) { + checkLogFile(); + if (message.getFirstLine() == null) + return; + CallID cid = (CallID) message.getCallId(); + String callId = null; + if (cid != null) + callId = cid.getCallId(); + String firstLine = message.getFirstLine().trim(); + String inputText = (logContent ? message.encode() : message.encodeMessage()); + String tid = message.getTransactionId(); + TimeStampHeader tsHdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME); + long tsval = tsHdr == null ? 0 : tsHdr.getTime(); + logMessage(inputText, from, to, sender, callId, firstLine, null, tid, time, tsval); + } + + /** + * Log a message into the log directory. + * + * @param message a SIPMessage to log + * @param from from header of the message to log into the log directory + * @param to to header of the message to log into the log directory + * @param status the status to log. + * @param sender is the server the sender or receiver (true if sender). + * @param time is the reception time. + */ + public void logMessage(SIPMessage message, String from, String to, String status, + boolean sender, long time) { + checkLogFile(); + CallID cid = (CallID) message.getCallId(); + String callId = null; + if (cid != null) + callId = cid.getCallId(); + String firstLine = message.getFirstLine().trim(); + String encoded = (logContent ? message.encode() : message.encodeMessage()); + String tid = message.getTransactionId(); + TimeStampHeader tshdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME); + long tsval = tshdr == null ? 0 : tshdr.getTime(); + logMessage(encoded, from, to, sender, callId, firstLine, status, tid, time, tsval); + } + + /** + * Log a message into the log directory. Time stamp associated with the message is the current + * time. + * + * @param message a SIPMessage to log + * @param from from header of the message to log into the log directory + * @param to to header of the message to log into the log directory + * @param status the status to log. + * @param sender is the server the sender or receiver (true if sender). + */ + public void logMessage(SIPMessage message, String from, String to, String status, + boolean sender) { + logMessage(message, from, to, status, sender, System.currentTimeMillis()); + } + + /** + * Log an exception stack trace. + * + * @param ex Exception to log into the log file + */ + + public void logException(Exception ex) { + if (traceLevel >= TRACE_EXCEPTION) { + checkLogFile(); + ex.printStackTrace(); + if (printWriter != null) + ex.printStackTrace(printWriter); + + } + } + + /** + * Set the trace level for the stack. + * + * @param level -- the trace level to set. The following trace levels are supported: + * <ul> + * <li> 0 -- no tracing </li> + * + * <li> 16 -- trace messages only </li> + * + * <li> 32 Full tracing including debug messages. </li> + * + * </ul> + */ + public void setTraceLevel(int level) { + traceLevel = level; + } + + /** + * Get the trace level for the stack. + * + * @return the trace level + */ + public int getTraceLevel() { + return traceLevel; + } + + /** + * Set aux information. Auxiliary information may be associated with the log file. This is + * useful for remote logs. + * + * @param auxInfo -- auxiliary information. + */ + public void setAuxInfo(String auxInfo) { + this.auxInfo = auxInfo; + } + + public void setSipStack(SipStack sipStack) { + if(sipStack instanceof SIPTransactionStack) { + this.sipStack = (SIPTransactionStack)sipStack; + this.stackLogger = this.sipStack.getStackLogger(); + } + else + throw new IllegalArgumentException("sipStack must be a SIPTransactionStack"); + } + + public void setStackProperties(Properties stackProperties) { + setProperties(stackProperties); + } + + public void setLevel(int jsipLoggingLevel) { + + } + +} diff --git a/java/gov/nist/javax/sip/stack/ServerRequestInterface.java b/java/gov/nist/javax/sip/stack/ServerRequestInterface.java new file mode 100644 index 0000000..7d46677 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/ServerRequestInterface.java @@ -0,0 +1,62 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.message.*; + +/** + * An interface for a genereic message processor for SIP Request messages. + * This is implemented by the application. The stack calls the message + * factory with a pointer to the parsed structure to create one of these + * and then calls processRequest on the newly created SIPServerRequest + * It is the applications responsibility to take care of what needs to be + * done to actually process the request. + * + * @version 1.2 $Revision: 1.4 $ $Date: 2009/07/17 18:58:15 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public interface ServerRequestInterface { + + /** + * Process the message. This incorporates a feature request + * by Salvador Rey Calatayud <salreyca@TELECO.UPV.ES> + * @param sipRequest is the incoming SIP Request. + * @param incomingChannel is the incoming message channel (parameter + * added in response to a request by Salvador Rey Calatayud.) + */ + public void processRequest( + SIPRequest sipRequest, + MessageChannel incomingChannel); + + +} diff --git a/java/gov/nist/javax/sip/stack/ServerResponseInterface.java b/java/gov/nist/javax/sip/stack/ServerResponseInterface.java new file mode 100644 index 0000000..7ea923d --- /dev/null +++ b/java/gov/nist/javax/sip/stack/ServerResponseInterface.java @@ -0,0 +1,78 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.stack; +import gov.nist.javax.sip.message.*; + +/* + * Salvador Rey Calatayud suggested adding a parameter to the processRequest/processResponse + * methods. + */ + +/** + * An interface for a genereic message processor for SIP Response messages. + * This is implemented by the application. The stack calls the message + * factory with a pointer to the parsed structure to create one of these + * and then calls processResponse on the newly created SIPServerResponse + * It is the applications responsibility to take care of what needs to be + * done to actually process the response. + * + * @version 1.2 $Revision: 1.4 $ $Date: 2009/07/17 18:58:15 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public interface ServerResponseInterface { + /** + * Process the Response. + * @param incomingChannel is the incoming message channel + * @param sipResponse is the responseto process. + * @param sipDialog -- dialog for this response + */ + public void processResponse( + SIPResponse sipResponse, + MessageChannel incomingChannel, + SIPDialog sipDialog); + + + + + /** + * This method is called prior to dialog assignment. + * @param sipResponse + * @param incomingChannel + */ + public void processResponse( + SIPResponse sipResponse, + MessageChannel incomingChannel); + + + +} diff --git a/java/gov/nist/javax/sip/stack/StackMessageFactory.java b/java/gov/nist/javax/sip/stack/StackMessageFactory.java new file mode 100644 index 0000000..70cef66 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/StackMessageFactory.java @@ -0,0 +1,70 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* +* Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * +*******************************************************************************/ +package gov.nist.javax.sip.stack; +import gov.nist.javax.sip.message.*; + +/** + * An interface for generating new requests and responses. This is implemented + * by the application and called by the stack for processing requests + * and responses. When a Request comes in off the wire, the stack calls + * newSIPServerRequest which is then responsible for processing the request. + * When a response comes off the wire, the stack calls newSIPServerResponse + * to process the response. + * + * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:58:15 $ + * + * @author M. Ranganathan <br/> + * + * + * + */ +public interface StackMessageFactory { + /** + * Make a new SIPServerResponse given a SIPRequest and a message + * channel. + * + * @param sipRequest is the incoming request. + * @param msgChan is the message channel on which this request was + * received. + */ + public ServerRequestInterface newSIPServerRequest( + SIPRequest sipRequest, + MessageChannel msgChan); + + /** + * Generate a new server response for the stack. + * + * @param sipResponse is the incoming response. + * @param msgChan is the message channel on which the response was + * received. + */ + public ServerResponseInterface newSIPServerResponse( + SIPResponse sipResponse, + MessageChannel msgChan); +} diff --git a/java/gov/nist/javax/sip/stack/TCPMessageChannel.java b/java/gov/nist/javax/sip/stack/TCPMessageChannel.java new file mode 100644 index 0000000..8b91956 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/TCPMessageChannel.java @@ -0,0 +1,747 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.message.*; +import gov.nist.javax.sip.parser.*; +import gov.nist.core.*; +import java.net.*; +import java.io.*; +import java.text.ParseException; +import java.util.TimerTask; + +import javax.sip.address.Hop; + +/* + * Ahmet Uyar <auyar@csit.fsu.edu>sent in a bug report for TCP operation of the JAIN sipStack. + * Niklas Uhrberg suggested that a mechanism be added to limit the number of simultaneous open + * connections. The TLS Adaptations were contributed by Daniel Martinez. Hagai Sela contributed a + * bug fix for symmetric nat. Jeroen van Bemmel added compensation for buggy clients ( Microsoft + * RTC clients ). Bug fixes by viswashanti.kadiyala@antepo.com, Joost Yervante Damand + */ + +/** + * This is a stack abstraction for TCP connections. This abstracts a stream of parsed messages. + * The SIP sipStack starts this from the main SIPStack class for each connection that it accepts. + * It starts a message parser in its own thread and talks to the message parser via a pipe. The + * message parser calls back via the parseError or processMessage functions that are defined as + * part of the SIPMessageListener interface. + * + * @see gov.nist.javax.sip.parser.PipelinedMsgParser + * + * + * @author M. Ranganathan <br/> + * + * @version 1.2 $Revision: 1.59 $ $Date: 2009/11/20 04:45:53 $ + */ +public class TCPMessageChannel extends MessageChannel implements SIPMessageListener, Runnable, + RawMessageChannel { + + private Socket mySock; + + private PipelinedMsgParser myParser; + + protected InputStream myClientInputStream; // just to pass to thread. + + protected OutputStream myClientOutputStream; + + protected String key; + + protected boolean isCached; + + protected boolean isRunning; + + private Thread mythread; + + protected SIPTransactionStack sipStack; + + protected String myAddress; + + protected int myPort; + + protected InetAddress peerAddress; + + protected int peerPort; + + protected String peerProtocol; + + // Incremented whenever a transaction gets assigned + // to the message channel and decremented when + // a transaction gets freed from the message channel. + // protected int useCount; + + private TCPMessageProcessor tcpMessageProcessor; + + protected TCPMessageChannel(SIPTransactionStack sipStack) { + this.sipStack = sipStack; + + } + + /** + * Constructor - gets called from the SIPStack class with a socket on accepting a new client. + * All the processing of the message is done here with the sipStack being freed up to handle + * new connections. The sock input is the socket that is returned from the accept. Global data + * that is shared by all threads is accessible in the Server structure. + * + * @param sock Socket from which to read and write messages. The socket is already connected + * (was created as a result of an accept). + * + * @param sipStack Ptr to SIP Stack + */ + + protected TCPMessageChannel(Socket sock, SIPTransactionStack sipStack, + TCPMessageProcessor msgProcessor) throws IOException { + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("creating new TCPMessageChannel "); + sipStack.getStackLogger().logStackTrace(); + } + mySock = sock; + peerAddress = mySock.getInetAddress(); + myAddress = msgProcessor.getIpAddress().getHostAddress(); + myClientInputStream = mySock.getInputStream(); + myClientOutputStream = mySock.getOutputStream(); + mythread = new Thread(this); + mythread.setDaemon(true); + mythread.setName("TCPMessageChannelThread"); + // Stash away a pointer to our sipStack structure. + this.sipStack = sipStack; + this.peerPort = mySock.getPort(); + + this.tcpMessageProcessor = msgProcessor; + this.myPort = this.tcpMessageProcessor.getPort(); + // Bug report by Vishwashanti Raj Kadiayl + super.messageProcessor = msgProcessor; + // Can drop this after response is sent potentially. + mythread.start(); + } + + /** + * Constructor - connects to the given inet address. Acknowledgement -- Lamine Brahimi (IBM + * Zurich) sent in a bug fix for this method. A thread was being uncessarily created. + * + * @param inetAddr inet address to connect to. + * @param sipStack is the sip sipStack from which we are created. + * @throws IOException if we cannot connect. + */ + protected TCPMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack, + TCPMessageProcessor messageProcessor) throws IOException { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("creating new TCPMessageChannel "); + sipStack.getStackLogger().logStackTrace(); + } + this.peerAddress = inetAddr; + this.peerPort = port; + this.myPort = messageProcessor.getPort(); + this.peerProtocol = "TCP"; + this.sipStack = sipStack; + this.tcpMessageProcessor = messageProcessor; + this.myAddress = messageProcessor.getIpAddress().getHostAddress(); + // Bug report by Vishwashanti Raj Kadiayl + this.key = MessageChannel.getKey(peerAddress, peerPort, "TCP"); + super.messageProcessor = messageProcessor; + + } + + /** + * Returns "true" as this is a reliable transport. + */ + public boolean isReliable() { + return true; + } + + /** + * Close the message channel. + */ + public void close() { + try { + if (mySock != null) { + mySock.close(); + mySock = null; + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Closing message Channel " + this); + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Error closing socket " + ex); + } + } + + /** + * Get my SIP Stack. + * + * @return The SIP Stack for this message channel. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * get the transport string. + * + * @return "tcp" in this case. + */ + public String getTransport() { + return "TCP"; + } + + /** + * get the address of the client that sent the data to us. + * + * @return Address of the client that sent us data that resulted in this channel being + * created. + */ + public String getPeerAddress() { + if (peerAddress != null) { + return peerAddress.getHostAddress(); + } else + return getHost(); + } + + protected InetAddress getPeerInetAddress() { + return peerAddress; + } + + public String getPeerProtocol() { + return this.peerProtocol; + } + + /** + * Send message to whoever is connected to us. Uses the topmost via address to send to. + * + * @param msg is the message to send. + * @param retry + */ + private void sendMessage(byte[] msg, boolean retry) throws IOException { + + /* + * Patch from kircuv@dev.java.net (Issue 119 ) This patch avoids the case where two + * TCPMessageChannels are now pointing to the same socket.getInputStream(). + * + * JvB 22/5 removed + */ + // Socket s = this.sipStack.ioHandler.getSocket(IOHandler.makeKey( + // this.peerAddress, this.peerPort)); + Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(), + this.peerAddress, this.peerPort, this.peerProtocol, msg, retry, this); + + // Created a new socket so close the old one and stick the new + // one in its place but dont do this if it is a datagram socket. + // (could have replied via udp but received via tcp!). + // if (mySock == null && s != null) { + // this.uncache(); + // } else + if (sock != mySock && sock != null) { + try { + if (mySock != null) + mySock.close(); + } catch (IOException ex) { + } + mySock = sock; + this.myClientInputStream = mySock.getInputStream(); + this.myClientOutputStream = mySock.getOutputStream(); + Thread thread = new Thread(this); + thread.setDaemon(true); + thread.setName("TCPMessageChannelThread"); + thread.start(); + } + + } + + /** + * Return a formatted message to the client. We try to re-connect with the peer on the other + * end if possible. + * + * @param sipMessage Message to send. + * @throws IOException If there is an error sending the message + */ + public void sendMessage(SIPMessage sipMessage) throws IOException { + byte[] msg = sipMessage.encodeAsBytes(this.getTransport()); + + long time = System.currentTimeMillis(); + + // JvB: also retry for responses, if the connection is gone we should + // try to reconnect + this.sendMessage(msg, /* sipMessage instanceof SIPRequest */true); + + if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) + logMessage(sipMessage, peerAddress, peerPort, time); + } + + /** + * Send a message to a specified address. + * + * @param message Pre-formatted message to send. + * @param receiverAddress Address to send it to. + * @param receiverPort Receiver port. + * @throws IOException If there is a problem connecting or sending. + */ + public void sendMessage(byte message[], InetAddress receiverAddress, int receiverPort, + boolean retry) throws IOException { + if (message == null || receiverAddress == null) + throw new IllegalArgumentException("Null argument"); + Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(), + receiverAddress, receiverPort, "TCP", message, retry, this); + if (sock != mySock && sock != null) { + if (mySock != null) { + /* + * Delay the close of the socket for some time in case it is being used. + */ + sipStack.getTimer().schedule(new TimerTask() { + @Override + public boolean cancel() { + try { + mySock.close(); + super.cancel(); + } catch (IOException ex) { + + } + return true; + } + + @Override + public void run() { + try { + mySock.close(); + } catch (IOException ex) { + + } + } + }, 8000); + } + + mySock = sock; + this.myClientInputStream = mySock.getInputStream(); + this.myClientOutputStream = mySock.getOutputStream(); + // start a new reader on this end of the pipe. + Thread mythread = new Thread(this); + mythread.setDaemon(true); + mythread.setName("TCPMessageChannelThread"); + mythread.start(); + } + + } + + /** + * Exception processor for exceptions detected from the parser. (This is invoked by the parser + * when an error is detected). + * + * @param sipMessage -- the message that incurred the error. + * @param ex -- parse exception detected by the parser. + * @param header -- header that caused the error. + * @throws ParseException Thrown if we want to reject the message. + */ + public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass, + String header, String message) throws ParseException { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + // Log the bad message for later reference. + if ((hdrClass != null) + && (hdrClass.equals(From.class) || hdrClass.equals(To.class) + || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class) + || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass + .equals(StatusLine.class))) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Encountered Bad Message \n" + sipMessage.toString()); + } + + // JvB: send a 400 response for requests (except ACK) + // Currently only UDP, @todo also other transports + String msgString = sipMessage.toString(); + if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { + + String badReqRes = createBadReqRes(msgString, ex); + if (badReqRes != null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:"); + sipStack.getStackLogger().logDebug(badReqRes); + } + try { + this.sendMessage(badReqRes.getBytes(), this.getPeerInetAddress(), this + .getPeerPort(), false); + } catch (IOException e) { + this.sipStack.getStackLogger().logException(e); + } + } else { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Could not formulate automatic 400 Bad Request"); + } + } + } + + throw ex; + } else { + sipMessage.addUnparsed(header); + } + } + + /** + * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser + * errors). + * + * @param sipMessage Mesage to process (this calls the application for processing the + * message). + */ + public void processMessage(SIPMessage sipMessage) throws Exception { + try { + if (sipMessage.getFrom() == null + || // sipMessage.getFrom().getTag() + // == null || + sipMessage.getTo() == null || sipMessage.getCallId() == null + || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) { + String badmsg = sipMessage.encode(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug(">>> Dropped Bad Msg"); + sipStack.getStackLogger().logDebug(badmsg); + } + + return; + } + + ViaList viaList = sipMessage.getViaHeaders(); + // For a request + // first via header tells where the message is coming from. + // For response, this has already been recorded in the outgoing + // message. + if (sipMessage instanceof SIPRequest) { + Via v = (Via) viaList.getFirst(); + Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); + this.peerProtocol = v.getTransport(); + try { + this.peerAddress = mySock.getInetAddress(); + // Check to see if the received parameter matches + // the peer address and tag it appropriately. + + // JvB: dont do this. It is both costly and incorrect + // Must set received also when it is a FQDN, regardless + // whether + // it resolves to the correct IP address + // InetAddress sentByAddress = + // InetAddress.getByName(hop.getHost()); + // JvB: if sender added 'rport', must always set received + if (v.hasParameter(Via.RPORT) + || !hop.getHost().equals(this.peerAddress.getHostAddress())) { + v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); + } + // @@@ hagai + // JvB: technically, may only do this when Via already + // contains + // rport + v.setParameter(Via.RPORT, Integer.toString(this.peerPort)); + } catch (java.text.ParseException ex) { + InternalErrorHandler.handleException(ex, sipStack.getStackLogger()); + } + // Use this for outgoing messages as well. + if (!this.isCached) { + ((TCPMessageProcessor) this.messageProcessor).cacheMessageChannel(this); + this.isCached = true; + int remotePort = ((java.net.InetSocketAddress) mySock.getRemoteSocketAddress()).getPort(); + String key = IOHandler.makeKey(mySock.getInetAddress(), remotePort); + sipStack.ioHandler.putSocket(key, mySock); + } + } + + + // Foreach part of the request header, fetch it and process it + + long receptionTime = System.currentTimeMillis(); + + if (sipMessage instanceof SIPRequest) { + // This is a request - process the request. + SIPRequest sipRequest = (SIPRequest) sipMessage; + // Create a new sever side request processor for this + // message and let it handle the rest. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("----Processing Message---"); + } + + // Check for reasonable size - reject message + // if it is too long. + if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { + sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(), + this.getMessageProcessor().getIpAddress().getHostAddress() + ":" + + this.getMessageProcessor().getPort(), false, receptionTime); + + } + + if (sipStack.getMaxMessageSize() > 0 + && sipRequest.getSize() + + (sipRequest.getContentLength() == null ? 0 : sipRequest + .getContentLength().getContentLength()) > sipStack + .getMaxMessageSize()) { + SIPResponse sipResponse = sipRequest + .createResponse(SIPResponse.MESSAGE_TOO_LARGE); + byte[] resp = sipResponse.encodeAsBytes(this.getTransport()); + this.sendMessage(resp, false); + throw new Exception("Message size exceeded"); + } + + ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest( + sipRequest, this); + + if (sipServerRequest != null) { + try { + sipServerRequest.processRequest(sipRequest, this); + } finally { + if (sipServerRequest instanceof SIPTransaction) { + SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; + if (!sipServerTx.passToListener()) + ((SIPTransaction) sipServerRequest).releaseSem(); + } + } + } else { + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger() + .logWarning("Dropping request -- could not acquire semaphore in 10 sec"); + } + + } else { + SIPResponse sipResponse = (SIPResponse) sipMessage; + // JvB: dont do this + // if (sipResponse.getStatusCode() == 100) + // sipResponse.getTo().removeParameter("tag"); + try { + sipResponse.checkHeaders(); + } catch (ParseException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping Badly formatted response message >>> " + + sipResponse); + return; + } + // This is a response message - process it. + // Check the size of the response. + // If it is too large dump it silently. + if (sipStack.getMaxMessageSize() > 0 + && sipResponse.getSize() + + (sipResponse.getContentLength() == null ? 0 : sipResponse + .getContentLength().getContentLength()) > sipStack + .getMaxMessageSize()) { + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logDebug("Message size exceeded"); + return; + + } + ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse( + sipResponse, this); + if (sipServerResponse != null) { + try { + if (sipServerResponse instanceof SIPClientTransaction + && !((SIPClientTransaction) sipServerResponse) + .checkFromTag(sipResponse)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping response message with invalid tag >>> " + + sipResponse); + return; + } + + sipServerResponse.processResponse(sipResponse, this); + } finally { + if (sipServerResponse instanceof SIPTransaction + && !((SIPTransaction) sipServerResponse).passToListener()) + ((SIPTransaction) sipServerResponse).releaseSem(); + } + } else { + sipStack + .getStackLogger() + .logWarning( + "Application is blocked -- could not acquire semaphore -- dropping response"); + } + } + } finally { + } + } + + /** + * This gets invoked when thread.start is called from the constructor. Implements a message + * loop - reading the tcp connection and processing messages until we are done or the other + * end has closed. + */ + public void run() { + Pipeline hispipe = null; + // Create a pipeline to connect to our message parser. + hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout, + ((SIPTransactionStack) sipStack).getTimer()); + // Create a pipelined message parser to read and parse + // messages that we write out to him. + myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize()); + // Start running the parser thread. + myParser.processInput(); + // bug fix by Emmanuel Proulx + int bufferSize = 4096; + this.tcpMessageProcessor.useCount++; + this.isRunning = true; + try { + while (true) { + try { + byte[] msg = new byte[bufferSize]; + int nbytes = myClientInputStream.read(msg, 0, bufferSize); + // no more bytes to read... + if (nbytes == -1) { + hispipe.write("\r\n\r\n".getBytes("UTF-8")); + try { + if (sipStack.maxConnections != -1) { + synchronized (tcpMessageProcessor) { + tcpMessageProcessor.nConnections--; + tcpMessageProcessor.notify(); + } + } + hispipe.close(); + mySock.close(); + } catch (IOException ioex) { + } + return; + } + hispipe.write(msg, 0, nbytes); + + } catch (IOException ex) { + // Terminate the message. + try { + hispipe.write("\r\n\r\n".getBytes("UTF-8")); + } catch (Exception e) { + // InternalErrorHandler.handleException(e); + } + + try { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("IOException closing sock " + ex); + try { + if (sipStack.maxConnections != -1) { + synchronized (tcpMessageProcessor) { + tcpMessageProcessor.nConnections--; + // System.out.println("Notifying!"); + tcpMessageProcessor.notify(); + } + } + mySock.close(); + hispipe.close(); + } catch (IOException ioex) { + } + } catch (Exception ex1) { + // Do nothing. + } + return; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex, sipStack.getStackLogger()); + } + } + } finally { + this.isRunning = false; + this.tcpMessageProcessor.remove(this); + this.tcpMessageProcessor.useCount--; + myParser.close(); + } + + } + + protected void uncache() { + if (isCached && !isRunning) { + this.tcpMessageProcessor.remove(this); + } + } + + /** + * Equals predicate. + * + * @param other is the other object to compare ourselves to for equals + */ + + public boolean equals(Object other) { + + if (!this.getClass().equals(other.getClass())) + return false; + else { + TCPMessageChannel that = (TCPMessageChannel) other; + if (this.mySock != that.mySock) + return false; + else + return true; + } + } + + /** + * Get an identifying key. This key is used to cache the connection and re-use it if + * necessary. + */ + public String getKey() { + if (this.key != null) { + return this.key; + } else { + this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, "TCP"); + return this.key; + } + } + + /** + * Get the host to assign to outgoing messages. + * + * @return the host to assign to the via header. + */ + public String getViaHost() { + return myAddress; + } + + /** + * Get the port for outgoing messages sent from the channel. + * + * @return the port to assign to the via header. + */ + public int getViaPort() { + return myPort; + } + + /** + * Get the port of the peer to whom we are sending messages. + * + * @return the peer port. + */ + public int getPeerPort() { + return peerPort; + } + + public int getPeerPacketSourcePort() { + return this.peerPort; + } + + public InetAddress getPeerPacketSourceAddress() { + return this.peerAddress; + } + + /** + * TCP Is not a secure protocol. + */ + public boolean isSecure() { + return false; + } +} diff --git a/java/gov/nist/javax/sip/stack/TCPMessageProcessor.java b/java/gov/nist/javax/sip/stack/TCPMessageProcessor.java new file mode 100644 index 0000000..60c0eb5 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/TCPMessageProcessor.java @@ -0,0 +1,291 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.stack; + +import java.net.Socket; +import java.net.ServerSocket; +import java.io.IOException; +import java.net.SocketException; +import gov.nist.core.*; +import java.net.*; +import java.util.*; + +/* + * Acknowledgement: Jeff Keyser suggested that a Stop mechanism be added to this. Niklas Uhrberg + * suggested that a means to limit the number of simultaneous active connections should be added. + * Mike Andrews suggested that the thread be accessible so as to implement clean stop using + * Thread.join(). Roger M. Persson contributed a bug fix for cleanup on stop(). + * + */ + +/** + * Sit in a loop waiting for incoming tcp connections and start a new thread to handle each new + * connection. This is the active object that creates new TCP MessageChannels (one for each new + * accept socket). + * + * @version 1.2 $Revision: 1.31 $ $Date: 2009/08/31 16:18:00 $ + * + * @author M. Ranganathan <br/> + * + * + */ +public class TCPMessageProcessor extends MessageProcessor { + + protected int nConnections; + + private boolean isRunning; + + private Hashtable tcpMessageChannels; + + private ArrayList<TCPMessageChannel> incomingTcpMessageChannels; + + private ServerSocket sock; + + protected int useCount; + + /** + * Constructor. + * + * @param sipStack SIPStack structure. + * @param port port where this message processor listens. + */ + protected TCPMessageProcessor(InetAddress ipAddress, SIPTransactionStack sipStack, int port) { + super(ipAddress, port, "tcp",sipStack); + + this.sipStack = sipStack; + + this.tcpMessageChannels = new Hashtable(); + this.incomingTcpMessageChannels = new ArrayList<TCPMessageChannel>(); + } + + /** + * Start the processor. + */ + public void start() throws IOException { + Thread thread = new Thread(this); + thread.setName("TCPMessageProcessorThread"); + thread.setPriority(Thread.MAX_PRIORITY); + thread.setDaemon(true); + this.sock = sipStack.getNetworkLayer().createServerSocket(getPort(), 0, getIpAddress()); + if (getIpAddress().getHostAddress().equals(IN_ADDR_ANY) + || getIpAddress().getHostAddress().equals(IN6_ADDR_ANY)) { + // Store the address to which we are actually bound + super.setIpAddress(sock.getInetAddress()); + + } + this.isRunning = true; + thread.start(); + + } + + /** + * Run method for the thread that gets created for each accept socket. + */ + public void run() { + // Accept new connectins on our socket. + while (this.isRunning) { + try { + synchronized (this) { + // sipStack.maxConnections == -1 means we are + // willing to handle an "infinite" number of + // simultaneous connections (no resource limitation). + // This is the default behavior. + while (sipStack.maxConnections != -1 + && this.nConnections >= sipStack.maxConnections) { + try { + this.wait(); + + if (!this.isRunning) + return; + } catch (InterruptedException ex) { + break; + } + } + this.nConnections++; + } + + Socket newsock = sock.accept(); + if (sipStack.isLoggingEnabled()) { + getSIPStack().getStackLogger().logDebug("Accepting new connection!"); + } + // Note that for an incoming message channel, the + // thread is already running + + incomingTcpMessageChannels.add(new TCPMessageChannel(newsock, sipStack, this)); + } catch (SocketException ex) { + this.isRunning = false; + } catch (IOException ex) { + // Problem accepting connection. + if (sipStack.isLoggingEnabled()) + getSIPStack().getStackLogger().logException(ex); + continue; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + } + + /** + * Return the transport string. + * + * @return the transport string + */ + public String getTransport() { + return "tcp"; + } + + /** + * Returns the stack. + * + * @return my sip stack. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * Stop the message processor. Feature suggested by Jeff Keyser. + */ + public synchronized void stop() { + isRunning = false; + // this.listeningPoint = null; + try { + sock.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + Collection en = tcpMessageChannels.values(); + for (Iterator it = en.iterator(); it.hasNext();) { + TCPMessageChannel next = (TCPMessageChannel) it.next(); + next.close(); + } + // RRPN: fix + for (Iterator incomingMCIterator = incomingTcpMessageChannels.iterator(); incomingMCIterator + .hasNext();) { + TCPMessageChannel next = (TCPMessageChannel) incomingMCIterator.next(); + next.close(); + } + + this.notify(); + } + + protected synchronized void remove(TCPMessageChannel tcpMessageChannel) { + + String key = tcpMessageChannel.getKey(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug(Thread.currentThread() + " removing " + key); + } + + /** May have been removed already */ + if (tcpMessageChannels.get(key) == tcpMessageChannel) { + this.tcpMessageChannels.remove(key); + } + + incomingTcpMessageChannels.remove(tcpMessageChannel); + } + + public synchronized MessageChannel createMessageChannel(HostPort targetHostPort) + throws IOException { + String key = MessageChannel.getKey(targetHostPort, "TCP"); + if (tcpMessageChannels.get(key) != null) { + return (TCPMessageChannel) this.tcpMessageChannels.get(key); + } else { + TCPMessageChannel retval = new TCPMessageChannel(targetHostPort.getInetAddress(), + targetHostPort.getPort(), sipStack, this); + this.tcpMessageChannels.put(key, retval); + retval.isCached = true; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("key " + key); + sipStack.getStackLogger().logDebug("Creating " + retval); + } + return retval; + } + } + + protected synchronized void cacheMessageChannel(TCPMessageChannel messageChannel) { + String key = messageChannel.getKey(); + TCPMessageChannel currentChannel = (TCPMessageChannel) tcpMessageChannels.get(key); + if (currentChannel != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Closing " + key); + currentChannel.close(); + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Caching " + key); + this.tcpMessageChannels.put(key, messageChannel); + + } + + public synchronized MessageChannel createMessageChannel(InetAddress host, int port) + throws IOException { + try { + String key = MessageChannel.getKey(host, port, "TCP"); + if (tcpMessageChannels.get(key) != null) { + return (TCPMessageChannel) this.tcpMessageChannels.get(key); + } else { + TCPMessageChannel retval = new TCPMessageChannel(host, port, sipStack, this); + this.tcpMessageChannels.put(key, retval); + retval.isCached = true; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("key " + key); + sipStack.getStackLogger().logDebug("Creating " + retval); + } + return retval; + } + } catch (UnknownHostException ex) { + throw new IOException(ex.getMessage()); + } + } + + /** + * TCP can handle an unlimited number of bytes. + */ + public int getMaximumMessageSize() { + return Integer.MAX_VALUE; + } + + public boolean inUse() { + return this.useCount != 0; + } + + /** + * Default target port for TCP + */ + public int getDefaultTargetPort() { + return 5060; + } + + /** + * TCP is not a secure protocol. + */ + public boolean isSecure() { + return false; + } +} diff --git a/java/gov/nist/javax/sip/stack/TLSMessageChannel.java b/java/gov/nist/javax/sip/stack/TLSMessageChannel.java new file mode 100644 index 0000000..5d357ef --- /dev/null +++ b/java/gov/nist/javax/sip/stack/TLSMessageChannel.java @@ -0,0 +1,738 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/* This class is entirely derived from TCPMessageChannel, + * by making some minor changes. Daniel J. Martinez Manzano <dani@dif.um.es> + * made these changes. Ahmet Uyar + * <auyar@csit.fsu.edu>sent in a bug report for TCP operation of the + * JAIN sipStack. Niklas Uhrberg suggested that a mechanism be added to + * limit the number of simultaneous open connections. The TLS + * Adaptations were contributed by Daniel Martinez. Hagai Sela + * contributed a bug fix for symmetric nat. Jeroen van Bemmel + * added compensation for buggy clients ( Microsoft RTC clients ). + * Bug fixes by viswashanti.kadiyala@antepo.com, Joost Yervante Damand + * Lamine Brahimi (IBM Zurich) sent in a bug fix - a thread was being uncessarily created. + */ + +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.javax.sip.header.*; +import gov.nist.javax.sip.message.*; +import gov.nist.javax.sip.parser.*; +import gov.nist.core.*; +import java.net.*; +import java.io.*; +import java.text.ParseException; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; +import javax.sip.address.Hop; +import javax.sip.message.Response; + +/** + * This is sipStack for TLS connections. This abstracts a stream of parsed messages. The SIP + * sipStack starts this from the main SIPStack class for each connection that it accepts. It + * starts a message parser in its own thread and talks to the message parser via a pipe. The + * message parser calls back via the parseError or processMessage functions that are defined as + * part of the SIPMessageListener interface. + * + * @see gov.nist.javax.sip.parser.PipelinedMsgParser + * + * + * @author M. Ranganathan + * + * + * @version 1.2 $Revision: 1.27 $ $Date: 2010/01/10 00:13:14 $ + */ +public final class TLSMessageChannel extends MessageChannel implements SIPMessageListener, + Runnable, RawMessageChannel { + + private Socket mySock; + + private PipelinedMsgParser myParser; + + private InputStream myClientInputStream; // just to pass to thread. + + private String key; + + protected boolean isCached; + + protected boolean isRunning; + + private Thread mythread; + + private String myAddress; + + private int myPort; + + private InetAddress peerAddress; + + private int peerPort; + + private String peerProtocol; + + // Incremented whenever a transaction gets assigned + // to the message channel and decremented when + // a transaction gets freed from the message channel. + // protected int useCount = 0; + + private TLSMessageProcessor tlsMessageProcessor; + + private SIPTransactionStack sipStack; + + private HandshakeCompletedListener handshakeCompletedListener; + + /** + * Constructor - gets called from the SIPStack class with a socket on accepting a new client. + * All the processing of the message is done here with the sipStack being freed up to handle + * new connections. The sock input is the socket that is returned from the accept. Global data + * that is shared by all threads is accessible in the Server structure. + * + * @param sock Socket from which to read and write messages. The socket is already connected + * (was created as a result of an accept). + * + * @param sipStack Ptr to SIP Stack + * + * @param msgProcessor -- the message processor that created us. + */ + + protected TLSMessageChannel(Socket sock, SIPTransactionStack sipStack, + TLSMessageProcessor msgProcessor) throws IOException { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (incoming)"); + sipStack.getStackLogger().logStackTrace(); + } + + mySock = (SSLSocket) sock; + if ( sock instanceof SSLSocket ) { + + SSLSocket sslSock = (SSLSocket) sock; + sslSock.setNeedClientAuth(true); + this.handshakeCompletedListener = new HandshakeCompletedListenerImpl(this); + sslSock.addHandshakeCompletedListener(this.handshakeCompletedListener); + sslSock.startHandshake(); + + } + + peerAddress = mySock.getInetAddress(); + myAddress = msgProcessor.getIpAddress().getHostAddress(); + myClientInputStream = mySock.getInputStream(); + + mythread = new Thread(this); + mythread.setDaemon(true); + mythread.setName("TLSMessageChannelThread"); + // Stash away a pointer to our sipStack structure. + this.sipStack = sipStack; + + this.tlsMessageProcessor = msgProcessor; + this.myPort = this.tlsMessageProcessor.getPort(); + this.peerPort = mySock.getPort(); + // Bug report by Vishwashanti Raj Kadiayl + super.messageProcessor = msgProcessor; + // Can drop this after response is sent potentially. + mythread.start(); + } + + /** + * Constructor - connects to the given inet address. + * + * @param inetAddr inet address to connect to. + * @param sipStack is the sip sipStack from which we are created. + * @param messageProcessor -- the message processor that created us. + * @throws IOException if we cannot connect. + */ + protected TLSMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack, + TLSMessageProcessor messageProcessor) throws IOException { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("creating new TLSMessageChannel (outgoing)"); + sipStack.getStackLogger().logStackTrace(); + } + this.peerAddress = inetAddr; + this.peerPort = port; + this.myPort = messageProcessor.getPort(); + this.peerProtocol = "TLS"; + this.sipStack = sipStack; + this.tlsMessageProcessor = messageProcessor; + this.myAddress = messageProcessor.getIpAddress().getHostAddress(); + this.key = MessageChannel.getKey(peerAddress, peerPort, "TLS"); + super.messageProcessor = messageProcessor; + + } + + /** + * Returns "true" as this is a reliable transport. + */ + public boolean isReliable() { + return true; + } + + /** + * Close the message channel. + */ + public void close() { + try { + if (mySock != null) + mySock.close(); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Closing message Channel " + this); + } catch (IOException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Error closing socket " + ex); + } + } + + /** + * Get my SIP Stack. + * + * @return The SIP Stack for this message channel. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * get the transport string. + * + * @return "tcp" in this case. + */ + public String getTransport() { + return "tls"; + } + + /** + * get the address of the client that sent the data to us. + * + * @return Address of the client that sent us data that resulted in this channel being + * created. + */ + public String getPeerAddress() { + if (peerAddress != null) { + return peerAddress.getHostAddress(); + } else + return getHost(); + } + + protected InetAddress getPeerInetAddress() { + return peerAddress; + } + + public String getPeerProtocol() { + return this.peerProtocol; + } + + /** + * Send message to whoever is connected to us. Uses the topmost via address to send to. + * + * @param msg is the message to send. + * @param retry + */ + private void sendMessage(byte[] msg, boolean retry) throws IOException { + Socket sock = this.sipStack.ioHandler.sendBytes( + this.getMessageProcessor().getIpAddress(), this.peerAddress, this.peerPort, + this.peerProtocol, msg, retry,this); + // Created a new socket so close the old one and stick the new + // one in its place but dont do this if it is a datagram socket. + // (could have replied via udp but received via tcp!). + if (sock != mySock && sock != null) { + try { + if (mySock != null) + mySock.close(); + } catch (IOException ex) { + } + mySock = sock; + this.myClientInputStream = mySock.getInputStream(); + + Thread thread = new Thread(this); + thread.setDaemon(true); + thread.setName("TLSMessageChannelThread"); + thread.start(); + } + + } + + /** + * Return a formatted message to the client. We try to re-connect with the peer on the other + * end if possible. + * + * @param sipMessage Message to send. + * @throws IOException If there is an error sending the message + */ + public void sendMessage(SIPMessage sipMessage) throws IOException { + byte[] msg = sipMessage.encodeAsBytes(this.getTransport()); + + long time = System.currentTimeMillis(); + + this.sendMessage(msg, sipMessage instanceof SIPRequest); + + if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) + logMessage(sipMessage, peerAddress, peerPort, time); + } + + /** + * Send a message to a specified address. + * + * @param message Pre-formatted message to send. + * @param receiverAddress Address to send it to. + * @param receiverPort Receiver port. + * @throws IOException If there is a problem connecting or sending. + */ + public void sendMessage(byte message[], InetAddress receiverAddress, int receiverPort, + boolean retry) throws IOException { + if (message == null || receiverAddress == null) + throw new IllegalArgumentException("Null argument"); + Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(), + receiverAddress, receiverPort, "TLS", message, retry, this); + // + // Created a new socket so close the old one and s + // Check for null (bug fix sent in by Christophe) + if (sock != mySock && sock != null) { + try { + if (mySock != null) + mySock.close(); + } catch (IOException ex) { + /* ignore */ + } + mySock = sock; + this.myClientInputStream = mySock.getInputStream(); + + // start a new reader on this end of the pipe. + Thread mythread = new Thread(this); + mythread.setDaemon(true); + mythread.setName("TLSMessageChannelThread"); + mythread.start(); + } + + } + + /** + * Exception processor for exceptions detected from the parser. (This is invoked by the parser + * when an error is detected). + * + * @param sipMessage -- the message that incurred the error. + * @param ex -- parse exception detected by the parser. + * @param header -- header that caused the error. + * @throws ParseException Thrown if we want to reject the message. + */ + public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass, + String header, String message) throws ParseException { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logException(ex); + // Log the bad message for later reference. + if ((hdrClass != null) + && (hdrClass.equals(From.class) || hdrClass.equals(To.class) + || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class) + || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass + .equals(StatusLine.class))) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Encountered bad message \n" + message); + // JvB: send a 400 response for requests (except ACK) + String msgString = sipMessage.toString(); + if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { + + String badReqRes = createBadReqRes(msgString, ex); + if (badReqRes != null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Sending automatic 400 Bad Request:"); + sipStack.getStackLogger().logDebug(badReqRes); + } + try { + this.sendMessage(badReqRes.getBytes(), this.getPeerInetAddress(), this + .getPeerPort(), false); + } catch (IOException e) { + this.sipStack.getStackLogger().logException(e); + } + } else { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Could not formulate automatic 400 Bad Request"); + } + } + } + throw ex; + } else { + sipMessage.addUnparsed(header); + } + } + + /** + * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser + * errors). + * + * @param sipMessage Message to process (this calls the application for processing the + * message). + * + * Jvb: note that this code is identical to TCPMessageChannel, refactor some day + */ + public void processMessage(SIPMessage sipMessage) throws Exception { + try { + if (sipMessage.getFrom() == null || sipMessage.getTo() == null + || sipMessage.getCallId() == null || sipMessage.getCSeq() == null + || sipMessage.getViaHeaders() == null) { + String badmsg = sipMessage.encode(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("bad message " + badmsg); + sipStack.getStackLogger().logError(">>> Dropped Bad Msg"); + } + return; + } + + ViaList viaList = sipMessage.getViaHeaders(); + // For a request + // first via header tells where the message is coming from. + // For response, this has already been recorded in the outgoing + // message. + + if (sipMessage instanceof SIPRequest) { + Via v = (Via) viaList.getFirst(); + // the peer address and tag it appropriately. + Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); + this.peerProtocol = v.getTransport(); + try { + this.peerAddress = mySock.getInetAddress(); + // Check to see if the received parameter matches + // JvB: dont do this. It is both costly and incorrect + // Must set received also when it is a FQDN, regardless whether + // it resolves to the correct IP address + // InetAddress sentByAddress = InetAddress.getByName(hop.getHost()); + // JvB: if sender added 'rport', must always set received + if (v.hasParameter(Via.RPORT) + || !hop.getHost().equals(this.peerAddress.getHostAddress())) { + v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress()); + } + // @@@ hagai + // JvB: technically, may only do this when Via already contains + // rport + v.setParameter(Via.RPORT, Integer.toString(this.peerPort)); + } catch (java.text.ParseException ex) { + InternalErrorHandler.handleException(ex); + } + // Use this for outgoing messages as well. + if (!this.isCached) { + ((TLSMessageProcessor) this.messageProcessor).cacheMessageChannel(this); + this.isCached = true; + String key = IOHandler.makeKey(mySock.getInetAddress(), this.peerPort); + sipStack.ioHandler.putSocket(key, mySock); + } + } + + // Foreach part of the request header, fetch it and process it + + long receptionTime = System.currentTimeMillis(); + // + + if (sipMessage instanceof SIPRequest) { + // This is a request - process the request. + SIPRequest sipRequest = (SIPRequest) sipMessage; + // Create a new sever side request processor for this + // message and let it handle the rest. + + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("----Processing Message---"); + } + if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { + + sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(), + this.messageProcessor.getIpAddress().getHostAddress() + ":" + + this.messageProcessor.getPort(), false, receptionTime); + + } + // Check for reasonable size - reject message + // if it is too long. + if (sipStack.getMaxMessageSize() > 0 + && sipRequest.getSize() + + (sipRequest.getContentLength() == null ? 0 : sipRequest + .getContentLength().getContentLength()) > sipStack + .getMaxMessageSize()) { + SIPResponse sipResponse = sipRequest + .createResponse(SIPResponse.MESSAGE_TOO_LARGE); + byte[] resp = sipResponse.encodeAsBytes(this.getTransport()); + this.sendMessage(resp, false); + throw new Exception("Message size exceeded"); + } + + // Stack could not create a new server request interface. + // maybe not enough resources. + ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest( + sipRequest, this); + if (sipServerRequest != null) { + try { + sipServerRequest.processRequest(sipRequest, this); + } finally { + if (sipServerRequest instanceof SIPTransaction) { + SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; + if (!sipServerTx.passToListener()) + ((SIPTransaction) sipServerRequest).releaseSem(); + } + } + } else { + SIPResponse response = sipRequest + .createResponse(Response.SERVICE_UNAVAILABLE); + + RetryAfter retryAfter = new RetryAfter(); + + // Be a good citizen and send a decent response code back. + try { + retryAfter.setRetryAfter((int) (10 * (Math.random()))); + response.setHeader(retryAfter); + this.sendMessage(response); + } catch (Exception e) { + // IGNore + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logWarning("Dropping message -- could not acquire semaphore"); + } + } else { + SIPResponse sipResponse = (SIPResponse) sipMessage; + try { + sipResponse.checkHeaders(); + } catch (ParseException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping Badly formatted response message >>> " + + sipResponse); + return; + } + // This is a response message - process it. + // Check the size of the response. + // If it is too large dump it silently. + if (sipStack.getMaxMessageSize() > 0 + && sipResponse.getSize() + + (sipResponse.getContentLength() == null ? 0 : sipResponse + .getContentLength().getContentLength()) > sipStack + .getMaxMessageSize()) { + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logDebug("Message size exceeded"); + return; + + } + ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse( + sipResponse, this); + if (sipServerResponse != null) { + try { + if (sipServerResponse instanceof SIPClientTransaction + && !((SIPClientTransaction) sipServerResponse) + .checkFromTag(sipResponse)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping response message with invalid tag >>> " + + sipResponse); + return; + } + + sipServerResponse.processResponse(sipResponse, this); + } finally { + if (sipServerResponse instanceof SIPTransaction + && !((SIPTransaction) sipServerResponse).passToListener()) { + // Note that the semaphore is released in event + // scanner if the + // request is actually processed by the Listener. + ((SIPTransaction) sipServerResponse).releaseSem(); + } + } + } else { + sipStack.getStackLogger().logWarning("Could not get semaphore... dropping response"); + } + } + } finally { + } + } + + /** + * This gets invoked when thread.start is called from the constructor. Implements a message + * loop - reading the tcp connection and processing messages until we are done or the other + * end has closed. + */ + public void run() { + Pipeline hispipe = null; + // Create a pipeline to connect to our message parser. + hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout, + ((SIPTransactionStack) sipStack).getTimer()); + // Create a pipelined message parser to read and parse + // messages that we write out to him. + myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize()); + // Start running the parser thread. + myParser.processInput(); + // bug fix by Emmanuel Proulx + int bufferSize = 4096; + this.tlsMessageProcessor.useCount++; + this.isRunning = true; + try { + while (true) { + try { + byte[] msg = new byte[bufferSize]; + int nbytes = myClientInputStream.read(msg, 0, bufferSize); + // no more bytes to read... + if (nbytes == -1) { + hispipe.write("\r\n\r\n".getBytes("UTF-8")); + try { + if (sipStack.maxConnections != -1) { + synchronized (tlsMessageProcessor) { + tlsMessageProcessor.nConnections--; + tlsMessageProcessor.notify(); + } + } + hispipe.close(); + mySock.close(); + } catch (IOException ioex) { + } + return; + } + hispipe.write(msg, 0, nbytes); + + } catch (IOException ex) { + // Terminate the message. + try { + hispipe.write("\r\n\r\n".getBytes("UTF-8")); + } catch (Exception e) { + // InternalErrorHandler.handleException(e); + } + + try { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("IOException closing sock " + ex); + try { + if (sipStack.maxConnections != -1) { + synchronized (tlsMessageProcessor) { + tlsMessageProcessor.nConnections--; + tlsMessageProcessor.notify(); + } + } + mySock.close(); + hispipe.close(); + } catch (IOException ioex) { + } + } catch (Exception ex1) { + // Do nothing. + } + return; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + } finally { + this.isRunning = false; + this.tlsMessageProcessor.remove(this); + this.tlsMessageProcessor.useCount--; + this.myParser.close(); + } + + } + + protected void uncache() { + if (isCached && !isRunning) { + this.tlsMessageProcessor.remove(this); + } + } + + /** + * Equals predicate. + * + * @param other is the other object to compare ourselves to for equals + */ + + public boolean equals(Object other) { + + if (!this.getClass().equals(other.getClass())) + return false; + else { + TLSMessageChannel that = (TLSMessageChannel) other; + if (this.mySock != that.mySock) + return false; + else + return true; + } + } + + /** + * Get an identifying key. This key is used to cache the connection and re-use it if + * necessary. + */ + public String getKey() { + if (this.key != null) { + return this.key; + } else { + this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, "TLS"); + return this.key; + } + } + + /** + * Get the host to assign to outgoing messages. + * + * @return the host to assign to the via header. + */ + public String getViaHost() { + return myAddress; + } + + /** + * Get the port for outgoing messages sent from the channel. + * + * @return the port to assign to the via header. + */ + public int getViaPort() { + return myPort; + } + + /** + * Get the port of the peer to whom we are sending messages. + * + * @return the peer port. + */ + public int getPeerPort() { + return peerPort; + } + + public int getPeerPacketSourcePort() { + return this.peerPort; + } + + public InetAddress getPeerPacketSourceAddress() { + return this.peerAddress; + } + + /** + * TLS Is a secure protocol. + */ + public boolean isSecure() { + return true; + } + + public void setHandshakeCompletedListener( + HandshakeCompletedListener handshakeCompletedListenerImpl) { + this.handshakeCompletedListener = handshakeCompletedListenerImpl; + } + + /** + * @return the handshakeCompletedListener + */ + public HandshakeCompletedListenerImpl getHandshakeCompletedListener() { + return (HandshakeCompletedListenerImpl) handshakeCompletedListener; + } +} diff --git a/java/gov/nist/javax/sip/stack/TLSMessageProcessor.java b/java/gov/nist/javax/sip/stack/TLSMessageProcessor.java new file mode 100644 index 0000000..6ff5113 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/TLSMessageProcessor.java @@ -0,0 +1,307 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/* This class is entirely derived from TCPMessageProcessor, + * by making some minor changes. + * + * Daniel J. Martinez Manzano <dani@dif.um.es> + * Acknowledgement: Jeff Keyser suggested that a + * Stop mechanism be added to this. Niklas Uhrberg suggested that + * a means to limit the number of simultaneous active connections + * should be added. Mike Andrews suggested that the thread be + * accessible so as to implement clean stop using Thread.join(). + * + */ + +/****************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + ******************************************************************************/ +package gov.nist.javax.sip.stack; + +import gov.nist.core.HostPort; +import gov.nist.javax.sip.SipStackImpl; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; + +import java.io.IOException; +import java.net.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; + +/** + * Sit in a loop waiting for incoming tls connections and start a new thread to handle each new + * connection. This is the active object that creates new TLS MessageChannels (one for each new + * accept socket). + * + * @version 1.2 $Revision: 1.23 $ $Date: 2009/12/06 15:58:39 $ + * + * @author M. Ranganathan <br/> + * + */ +public class TLSMessageProcessor extends MessageProcessor { + + protected int nConnections; + + private boolean isRunning; + + private Hashtable<String, TLSMessageChannel> tlsMessageChannels; + + private ServerSocket sock; + + protected int useCount = 0; + + private ArrayList<TLSMessageChannel> incomingTlsMessageChannels; + + /** + * Constructor. + * + * @param ipAddress -- inet address where I am listening. + * @param sipStack SIPStack structure. + * @param port port where this message processor listens. + */ + protected TLSMessageProcessor(InetAddress ipAddress, SIPTransactionStack sipStack, int port) { + super(ipAddress, port, "tls",sipStack); + this.sipStack = sipStack; + this.tlsMessageChannels = new Hashtable<String, TLSMessageChannel>(); + this.incomingTlsMessageChannels = new ArrayList<TLSMessageChannel>(); + + } + + /** + * Start the processor. + */ + public void start() throws IOException { + Thread thread = new Thread(this); + thread.setName("TLSMessageProcessorThread"); + // ISSUE 184 + thread.setPriority(Thread.MAX_PRIORITY); + thread.setDaemon(true); + + this.sock = sipStack.getNetworkLayer().createSSLServerSocket(this.getPort(), 0, + this.getIpAddress()); + ((SSLServerSocket) this.sock).setNeedClientAuth(false); + ((SSLServerSocket) this.sock).setUseClientMode(false); + ((SSLServerSocket) this.sock).setWantClientAuth(true); + String []enabledCiphers = ((SipStackImpl)sipStack).getEnabledCipherSuites(); + ((SSLServerSocket) this.sock).setEnabledCipherSuites(enabledCiphers); + ((SSLServerSocket)this.sock).setWantClientAuth(true); + + + this.isRunning = true; + thread.start(); + + } + + /** + * Run method for the thread that gets created for each accept socket. + */ + public void run() { + // Accept new connectins on our socket. + while (this.isRunning) { + try { + synchronized (this) { + // sipStack.maxConnections == -1 means we are + // willing to handle an "infinite" number of + // simultaneous connections (no resource limitation). + // This is the default behavior. + while (sipStack.maxConnections != -1 + && this.nConnections >= sipStack.maxConnections) { + try { + this.wait(); + + if (!this.isRunning) + return; + } catch (InterruptedException ex) { + break; + } + } + this.nConnections++; + } + + Socket newsock = sock.accept(); + + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Accepting new connection!"); + + + // Note that for an incoming message channel, the + // thread is already running + + incomingTlsMessageChannels.add(new TLSMessageChannel(newsock, sipStack, this)); + } catch (SocketException ex) { + if ( this.isRunning ) { + sipStack.getStackLogger().logError( + "Fatal - SocketException occured while Accepting connection", ex); + this.isRunning = false; + break; + } + } catch (SSLException ex) { + this.isRunning = false; + sipStack.getStackLogger().logError( + "Fatal - SSSLException occured while Accepting connection", ex); + break; + } catch (IOException ex) { + // Problem accepting connection. + sipStack.getStackLogger().logError("Problem Accepting Connection", ex); + continue; + } catch (Exception ex) { + sipStack.getStackLogger().logError("Unexpected Exception!", ex); + } + } + } + + /** + * Returns the stack. + * + * @return my sip stack. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * Stop the message processor. Feature suggested by Jeff Keyser. + */ + public synchronized void stop() { + if (!isRunning) + return; + + isRunning = false; + try { + sock.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + Collection en = tlsMessageChannels.values(); + for (Iterator it = en.iterator(); it.hasNext();) { + TLSMessageChannel next = (TLSMessageChannel) it.next(); + next.close(); + } + for (Iterator incomingMCIterator = incomingTlsMessageChannels.iterator(); incomingMCIterator + .hasNext();) { + TLSMessageChannel next = (TLSMessageChannel) incomingMCIterator.next(); + next.close(); + } + this.notify(); + + } + + protected synchronized void remove(TLSMessageChannel tlsMessageChannel) { + + String key = tlsMessageChannel.getKey(); + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug(Thread.currentThread() + " removing " + key); + } + + /** May have been removed already */ + if (tlsMessageChannels.get(key) == tlsMessageChannel) + this.tlsMessageChannels.remove(key); + + incomingTlsMessageChannels.remove(tlsMessageChannel); + } + + public synchronized MessageChannel createMessageChannel(HostPort targetHostPort) + throws IOException { + String key = MessageChannel.getKey(targetHostPort, "TLS"); + if (tlsMessageChannels.get(key) != null) { + return (TLSMessageChannel) this.tlsMessageChannels.get(key); + } else { + TLSMessageChannel retval = new TLSMessageChannel(targetHostPort.getInetAddress(), + targetHostPort.getPort(), sipStack, this); + this.tlsMessageChannels.put(key, retval); + retval.isCached = true; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("key " + key); + sipStack.getStackLogger().logDebug("Creating " + retval); + } + return retval; + } + } + + protected synchronized void cacheMessageChannel(TLSMessageChannel messageChannel) { + String key = messageChannel.getKey(); + TLSMessageChannel currentChannel = (TLSMessageChannel) tlsMessageChannels.get(key); + if (currentChannel != null) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Closing " + key); + currentChannel.close(); + } + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Caching " + key); + this.tlsMessageChannels.put(key, messageChannel); + + } + + public synchronized MessageChannel createMessageChannel(InetAddress host, int port) + throws IOException { + try { + String key = MessageChannel.getKey(host, port, "TLS"); + if (tlsMessageChannels.get(key) != null) { + return (TLSMessageChannel) this.tlsMessageChannels.get(key); + } else { + TLSMessageChannel retval = new TLSMessageChannel(host, port, sipStack, this); + this.tlsMessageChannels.put(key, retval); + retval.isCached = true; + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("key " + key); + sipStack.getStackLogger().logDebug("Creating " + retval); + } + return retval; + } + } catch (UnknownHostException ex) { + throw new IOException(ex.getMessage()); + } + } + + /** + * TLS can handle an unlimited number of bytes. + */ + public int getMaximumMessageSize() { + return Integer.MAX_VALUE; + } + + public boolean inUse() { + return this.useCount != 0; + } + + /** + * Default target port for TLS + */ + public int getDefaultTargetPort() { + return 5061; + } + + /** + * TLS is a secure protocol. + */ + public boolean isSecure() { + return true; + } +} diff --git a/java/gov/nist/javax/sip/stack/UDPMessageChannel.java b/java/gov/nist/javax/sip/stack/UDPMessageChannel.java new file mode 100644 index 0000000..a36aa57 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/UDPMessageChannel.java @@ -0,0 +1,941 @@ +/* + * Conditions Of Use + * + * This software was developed by employees of the National Institute of + * Standards and Technology (NIST), an agency of the Federal Government. + * Pursuant to title 15 Untied States Code Section 105, works of NIST + * employees are not subject to copyright protection in the United States + * and are considered to be in the public domain. As a result, a formal + * license is not needed to use the software. + * + * This software is provided by NIST as a service and is expressly + * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT + * AND DATA ACCURACY. NIST does not warrant or make any representations + * regarding the use of the software or the results thereof, including but + * not limited to the correctness, accuracy, reliability or usefulness of + * the software. + * + * Permission to use this software is contingent upon your acceptance + * of the terms of this agreement + * + * . + * + */ +/***************************************************************************** + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *****************************************************************************/ + +package gov.nist.javax.sip.stack; + +import gov.nist.core.InternalErrorHandler; +import gov.nist.core.ServerLogger; +import gov.nist.core.StackLogger; +import gov.nist.core.ThreadAuditor; +import gov.nist.javax.sip.SIPConstants; +import gov.nist.javax.sip.header.CSeq; +import gov.nist.javax.sip.header.CallID; +import gov.nist.javax.sip.header.From; +import gov.nist.javax.sip.header.RequestLine; +import gov.nist.javax.sip.header.StatusLine; +import gov.nist.javax.sip.header.To; +import gov.nist.javax.sip.header.Via; +import gov.nist.javax.sip.header.ViaList; +import gov.nist.javax.sip.message.SIPMessage; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; +import gov.nist.javax.sip.parser.ParseExceptionListener; +import gov.nist.javax.sip.parser.StringMsgParser; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Socket; +import java.text.ParseException; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.TimerTask; + +import javax.sip.address.Hop; + +/* + * Kim Kirby (Keyvoice) suggested that duplicate checking should be added to the + * stack (later removed). Lamine Brahimi suggested a single threaded behavior + * flag be added to this. Niklas Uhrberg suggested that thread pooling support + * be added to this for performance and resource management. Peter Parnes found + * a bug with this code that was sending it into an infinite loop when a bad + * incoming message was parsed. Bug fix by viswashanti.kadiyala@antepo.com. + * Hagai Sela addded fixes for NAT traversal. Jeroen van Bemmel fixed up for + * buggy clients (such as windows messenger) and added code to return + * BAD_REQUEST. David Alique fixed an address recording bug. Jeroen van Bemmel + * fixed a performance issue where the stack was doing DNS lookups (potentially + * unnecessary). Ricardo Bora (Natural Convergence ) added code that prevents + * the stack from exitting when an exception is encountered. + * + */ + +/** + * This is the UDP Message handler that gets created when a UDP message needs to + * be processed. The message is processed by creating a String Message parser + * and invoking it on the message read from the UDP socket. The parsed structure + * is handed off via a SIP stack request for further processing. This stack + * structure isolates the message handling logic from the mechanics of sending + * and recieving messages (which could be either udp or tcp. + * + * + * @author M. Ranganathan <br/> + * + * + * + * @version 1.2 $Revision: 1.66 $ $Date: 2010/01/14 05:15:49 $ + */ +public class UDPMessageChannel extends MessageChannel implements + ParseExceptionListener, Runnable, RawMessageChannel { + + + /** + * SIP Stack structure for this channel. + */ + protected SIPTransactionStack sipStack; + + /** + * The parser we are using for messages received from this channel. + */ + protected StringMsgParser myParser; + + /** + * Where we got the stuff from + */ + private InetAddress peerAddress; + + private String myAddress; + + private int peerPacketSourcePort; + + private InetAddress peerPacketSourceAddress; + + /** + * Reciever port -- port of the destination. + */ + private int peerPort; + + /** + * Protocol to use when talking to receiver (i.e. when sending replies). + */ + private String peerProtocol; + + protected int myPort; + + private DatagramPacket incomingPacket; + + private long receptionTime; + + /* + * A table that keeps track of when the last pingback was sent to a given remote IP address + * and port. This is for NAT compensation. This stays in the table for 1 seconds and prevents + * infinite loop. If a second pingback happens in that period of time, it will be dropped. + */ + private Hashtable<String,PingBackTimerTask> pingBackRecord = new Hashtable<String,PingBackTimerTask>(); + + class PingBackTimerTask extends TimerTask { + String ipAddress; + int port; + + public PingBackTimerTask(String ipAddress, int port) { + this.ipAddress = ipAddress; + this.port = port; + pingBackRecord.put(ipAddress + ":" + port, this); + } + @Override + public void run() { + pingBackRecord.remove(ipAddress + ":" + port); + } + @Override + public int hashCode() { + return (ipAddress + ":" + port).hashCode(); + } + } + + /** + * Constructor - takes a datagram packet and a stack structure Extracts the + * address of the other from the datagram packet and stashes away the + * pointer to the passed stack structure. + * + * @param stack + * is the shared SIPStack structure + * @param messageProcessor + * is the creating message processor. + */ + protected UDPMessageChannel(SIPTransactionStack stack, + UDPMessageProcessor messageProcessor) { + super.messageProcessor = messageProcessor; + this.sipStack = stack; + + Thread mythread = new Thread(this); + + this.myAddress = messageProcessor.getIpAddress().getHostAddress(); + this.myPort = messageProcessor.getPort(); + + mythread.setName("UDPMessageChannelThread"); + mythread.setDaemon(true); + mythread.start(); + + } + + /** + * Constructor. We create one of these in order to process an incoming + * message. + * + * @param stack + * is the SIP sipStack. + * @param messageProcessor + * is the creating message processor. + * @param packet + * is the incoming datagram packet. + */ + protected UDPMessageChannel(SIPTransactionStack stack, + UDPMessageProcessor messageProcessor, DatagramPacket packet) { + + this.incomingPacket = packet; + super.messageProcessor = messageProcessor; + this.sipStack = stack; + + this.myAddress = messageProcessor.getIpAddress().getHostAddress(); + this.myPort = messageProcessor.getPort(); + Thread mythread = new Thread(this); + mythread.setDaemon(true); + mythread.setName("UDPMessageChannelThread"); + + mythread.start(); + + } + + /** + * Constructor. We create one of these when we send out a message. + * + * @param targetAddr + * INET address of the place where we want to send messages. + * @param port + * target port (where we want to send the message). + * @param sipStack + * our SIP Stack. + */ + protected UDPMessageChannel(InetAddress targetAddr, int port, + SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) { + peerAddress = targetAddr; + peerPort = port; + peerProtocol = "UDP"; + super.messageProcessor = messageProcessor; + this.myAddress = messageProcessor.getIpAddress().getHostAddress(); + this.myPort = messageProcessor.getPort(); + this.sipStack = sipStack; + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("Creating message channel " + + targetAddr.getHostAddress() + "/" + port); + } + } + + /** + * Run method specified by runnnable. + */ + public void run() { + // Assume no thread pooling (bug fix by spierhj) + ThreadAuditor.ThreadHandle threadHandle = null; + + while (true) { + // Create a new string message parser to parse the list of messages. + if (myParser == null) { + myParser = new StringMsgParser(); + myParser.setParseExceptionListener(this); + } + // messages that we write out to him. + DatagramPacket packet; + + if (sipStack.threadPoolSize != -1) { + synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) { + while (((UDPMessageProcessor) messageProcessor).messageQueue + .isEmpty()) { + // Check to see if we need to exit. + if (!((UDPMessageProcessor) messageProcessor).isRunning) + return; + try { + // We're part of a thread pool. Ask the auditor to + // monitor this thread. + if (threadHandle == null) { + threadHandle = sipStack.getThreadAuditor() + .addCurrentThread(); + } + + // Send a heartbeat to the thread auditor + threadHandle.ping(); + + // Wait for packets + // Note: getPingInterval returns 0 (infinite) if the + // thread auditor is disabled. + ((UDPMessageProcessor) messageProcessor).messageQueue + .wait(threadHandle + .getPingIntervalInMillisecs()); + } catch (InterruptedException ex) { + if (!((UDPMessageProcessor) messageProcessor).isRunning) + return; + } + } + packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue + .removeFirst(); + + } + this.incomingPacket = packet; + } else { + packet = this.incomingPacket; + } + + // Process the packet. Catch and log any exception we may throw. + try { + processIncomingDataPacket(packet); + } catch (Exception e) { + + sipStack.getStackLogger().logError( + "Error while processing incoming UDP packet", e); + } + + if (sipStack.threadPoolSize == -1) { + return; + } + } + } + + /** + * Process an incoming datagram + * + * @param packet + * is the incoming datagram packet. + */ + private void processIncomingDataPacket(DatagramPacket packet) + throws Exception { + this.peerAddress = packet.getAddress(); + int packetLength = packet.getLength(); + // Read bytes and put it in a eueue. + byte[] bytes = packet.getData(); + byte[] msgBytes = new byte[packetLength]; + System.arraycopy(bytes, 0, msgBytes, 0, packetLength); + + // Do debug logging. + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger() + .logDebug("UDPMessageChannel: processIncomingDataPacket : peerAddress = " + + peerAddress.getHostAddress() + "/" + + packet.getPort() + " Length = " + packetLength); + + } + + SIPMessage sipMessage = null; + try { + this.receptionTime = System.currentTimeMillis(); + sipMessage = myParser.parseSIPMessage(msgBytes); + myParser = null; + } catch (ParseException ex) { + myParser = null; // let go of the parser reference. + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("Rejecting message ! " + + new String(msgBytes)); + this.sipStack.getStackLogger().logDebug("error message " + + ex.getMessage()); + this.sipStack.getStackLogger().logException(ex); + } + + + // JvB: send a 400 response for requests (except ACK) + // Currently only UDP, @todo also other transports + String msgString = new String(msgBytes, 0, packetLength); + if (!msgString.startsWith("SIP/") && !msgString.startsWith("ACK ")) { + + String badReqRes = createBadReqRes(msgString, ex); + if (badReqRes != null) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug( + "Sending automatic 400 Bad Request:"); + sipStack.getStackLogger().logDebug(badReqRes); + } + try { + this.sendMessage(badReqRes.getBytes(), peerAddress, + packet.getPort(), "UDP", false); + } catch (IOException e) { + this.sipStack.getStackLogger().logException(e); + } + } else { + if (sipStack.isLoggingEnabled()) { + sipStack + .getStackLogger() + .logDebug( + "Could not formulate automatic 400 Bad Request"); + } + } + } + + return; + } + // No parse exception but null message - reject it and + // march on (or return). + // exit this message processor if the message did not parse. + + if (sipMessage == null) { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("Rejecting message ! + Null message parsed."); + } + if (pingBackRecord.get(packet.getAddress().getHostAddress() + ":" + packet.getPort()) == null ) { + byte[] retval = "\r\n\r\n".getBytes(); + DatagramPacket keepalive = new DatagramPacket(retval,0,retval.length,packet.getAddress(),packet.getPort()); + ((UDPMessageProcessor)this.messageProcessor).sock.send(keepalive); + this.sipStack.getTimer().schedule(new PingBackTimerTask(packet.getAddress().getHostAddress(), + packet.getPort()), 1000); + } + return; + } + ViaList viaList = sipMessage.getViaHeaders(); + // Check for the required headers. + if (sipMessage.getFrom() == null || sipMessage.getTo() == null + || sipMessage.getCallId() == null + || sipMessage.getCSeq() == null + || sipMessage.getViaHeaders() == null) { + String badmsg = new String(msgBytes); + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logError("bad message " + badmsg); + this.sipStack.getStackLogger().logError(">>> Dropped Bad Msg " + + "From = " + sipMessage.getFrom() + "To = " + + sipMessage.getTo() + "CallId = " + + sipMessage.getCallId() + "CSeq = " + + sipMessage.getCSeq() + "Via = " + + sipMessage.getViaHeaders()); + } + return; + } + // For a request first via header tells where the message + // is coming from. + // For response, just get the port from the packet. + if (sipMessage instanceof SIPRequest) { + Via v = (Via) viaList.getFirst(); + Hop hop = sipStack.addressResolver.resolveAddress(v.getHop()); + this.peerPort = hop.getPort(); + this.peerProtocol = v.getTransport(); + + this.peerPacketSourceAddress = packet.getAddress(); + this.peerPacketSourcePort = packet.getPort(); + try { + this.peerAddress = packet.getAddress(); + // Check to see if the received parameter matches + // the peer address and tag it appropriately. + + + boolean hasRPort = v.hasParameter(Via.RPORT); + if (hasRPort + || !hop.getHost().equals( + this.peerAddress.getHostAddress())) { + v.setParameter(Via.RECEIVED, this.peerAddress + .getHostAddress()); + } + + if (hasRPort) { + v.setParameter(Via.RPORT, Integer + .toString(this.peerPacketSourcePort)); + } + } catch (java.text.ParseException ex1) { + InternalErrorHandler.handleException(ex1); + } + + } else { + + this.peerPacketSourceAddress = packet.getAddress(); + this.peerPacketSourcePort = packet.getPort(); + this.peerAddress = packet.getAddress(); + this.peerPort = packet.getPort(); + this.peerProtocol = ((Via) viaList.getFirst()).getTransport(); + } + + this.processMessage(sipMessage); + + } + + /** + * Actually proces the parsed message. + * + * @param sipMessage + */ + public void processMessage(SIPMessage sipMessage) { + + if (sipMessage instanceof SIPRequest) { + SIPRequest sipRequest = (SIPRequest) sipMessage; + + // This is a request - process it. + // So far so good -- we will commit this message if + // all processing is OK. + if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) { + + this.sipStack.serverLogger.logMessage(sipMessage, this + .getPeerHostPort().toString(), this.getHost() + ":" + + this.myPort, false, receptionTime); + + } + ServerRequestInterface sipServerRequest = sipStack + .newSIPServerRequest(sipRequest, this); + // Drop it if there is no request returned + if (sipServerRequest == null) { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger() + .logWarning("Null request interface returned -- dropping request"); + } + + + return; + } + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logDebug("About to process " + + sipRequest.getFirstLine() + "/" + sipServerRequest); + try { + sipServerRequest.processRequest(sipRequest, this); + } finally { + if (sipServerRequest instanceof SIPTransaction) { + SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest; + if (!sipServerTx.passToListener()) { + ((SIPTransaction) sipServerRequest).releaseSem(); + } + } + } + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logDebug("Done processing " + + sipRequest.getFirstLine() + "/" + sipServerRequest); + + // So far so good -- we will commit this message if + // all processing is OK. + + } else { + // Handle a SIP Reply message. + SIPResponse sipResponse = (SIPResponse) sipMessage; + try { + sipResponse.checkHeaders(); + } catch (ParseException ex) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping Badly formatted response message >>> " + + sipResponse); + return; + } + ServerResponseInterface sipServerResponse = sipStack + .newSIPServerResponse(sipResponse, this); + if (sipServerResponse != null) { + try { + if (sipServerResponse instanceof SIPClientTransaction + && !((SIPClientTransaction) sipServerResponse) + .checkFromTag(sipResponse)) { + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger() + .logError("Dropping response message with invalid tag >>> " + + sipResponse); + return; + } + + sipServerResponse.processResponse(sipResponse, this); + } finally { + if (sipServerResponse instanceof SIPTransaction + && !((SIPTransaction) sipServerResponse) + .passToListener()) + ((SIPTransaction) sipServerResponse).releaseSem(); + } + + // Normal processing of message. + } else { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("null sipServerResponse!"); + } + } + + } + } + + /** + * JvB: added method to check for known buggy clients (Windows Messenger) to + * fix the port to which responses are sent + * + * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701) + * + * JvB 22/7/2006 better to take this out for the moment, it is only a + * problem in rare cases (unregister) + * + * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah = + * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) { + * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p = + * (String) uah.getProduct().next(); return p.startsWith( "RTC" ); } } + * return false; } + */ + + /** + * Implementation of the ParseExceptionListener interface. + * + * @param ex + * Exception that is given to us by the parser. + * @throws ParseException + * If we choose to reject the header or message. + */ + public void handleException(ParseException ex, SIPMessage sipMessage, + Class hdrClass, String header, String message) + throws ParseException { + if (sipStack.isLoggingEnabled()) + this.sipStack.getStackLogger().logException(ex); + // Log the bad message for later reference. + if ((hdrClass != null) + && (hdrClass.equals(From.class) || hdrClass.equals(To.class) + || hdrClass.equals(CSeq.class) + || hdrClass.equals(Via.class) + || hdrClass.equals(CallID.class) + || hdrClass.equals(RequestLine.class) || hdrClass + .equals(StatusLine.class))) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logError("BAD MESSAGE!"); + sipStack.getStackLogger().logError(message); + } + throw ex; + } else { + sipMessage.addUnparsed(header); + } + } + + /** + * Return a reply from a pre-constructed reply. This sends the message back + * to the entity who caused us to create this channel in the first place. + * + * @param sipMessage + * Message string to send. + * @throws IOException + * If there is a problem with sending the message. + */ + public void sendMessage(SIPMessage sipMessage) throws IOException { + if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) { + if ( sipMessage instanceof SIPRequest && + ((SIPRequest)sipMessage).getRequestLine() != null) { + /* + * We dont want to log empty trace messages. + */ + this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); + } else { + this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); + } + } + + // Test and see where we are going to send the messsage. If the message + // is sent back to oursleves, just + // shortcircuit processing. + long time = System.currentTimeMillis(); + try { + for (MessageProcessor messageProcessor : sipStack + .getMessageProcessors()) { + if (messageProcessor.getIpAddress().equals(this.peerAddress) + && messageProcessor.getPort() == this.peerPort + && messageProcessor.getTransport().equals( + this.peerProtocol)) { + MessageChannel messageChannel = messageProcessor + .createMessageChannel(this.peerAddress, + this.peerPort); + if (messageChannel instanceof RawMessageChannel) { + ((RawMessageChannel) messageChannel) + .processMessage(sipMessage); + if (sipStack.isLoggingEnabled()) + sipStack.getStackLogger().logDebug("Self routing message"); + return; + } + + } + } + + byte[] msg = sipMessage.encodeAsBytes( this.getTransport() ); + + sendMessage(msg, peerAddress, peerPort, peerProtocol, + sipMessage instanceof SIPRequest); + + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + sipStack.getStackLogger().logError("An exception occured while sending message",ex); + throw new IOException( + "An exception occured while sending message"); + } finally { + if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest()) + logMessage(sipMessage, peerAddress, peerPort, time); + else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG)) + sipStack.getStackLogger().logDebug("Sent EMPTY Message"); + } + } + + /** + * Send a message to a specified receiver address. + * + * @param msg + * string to send. + * @param peerAddress + * Address of the place to send it to. + * @param peerPort + * the port to send it to. + * @throws IOException + * If there is trouble sending this message. + */ + protected void sendMessage(byte[] msg, InetAddress peerAddress, + int peerPort, boolean reConnect) throws IOException { + // Via is not included in the request so silently drop the reply. + if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend() ) { + this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO); + } + if (peerPort == -1) { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug(getClass().getName() + + ":sendMessage: Dropping reply!"); + } + throw new IOException("Receiver port not set "); + } else { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("sendMessage " + peerAddress.getHostAddress() + "/" + + peerPort + "\n" + "messageSize = " + msg.length + " message = " + new String(msg)) ; + this.sipStack.getStackLogger().logDebug("*******************\n"); + } + + } + DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, + peerPort); + try { + DatagramSocket sock; + boolean created = false; + + if (sipStack.udpFlag) { + // Use the socket from the message processor (for firewall + // support use the same socket as the message processor + // socket -- feature request # 18 from java.net). This also + // makes the whole thing run faster! + sock = ((UDPMessageProcessor) messageProcessor).sock; + + // Bind the socket to the stack address in case there + // are multiple interfaces on the machine (feature reqeust + // by Will Scullin) 0 binds to an ephemeral port. + // sock = new DatagramSocket(0,sipStack.stackInetAddress); + } else { + // bind to any interface and port. + sock = new DatagramSocket(); + created = true; + } + sock.send(reply); + if (created) + sock.close(); + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + } + + /** + * Send a message to a specified receiver address. + * + * @param msg + * message string to send. + * @param peerAddress + * Address of the place to send it to. + * @param peerPort + * the port to send it to. + * @param peerProtocol + * protocol to use to send. + * @throws IOException + * If there is trouble sending this message. + */ + protected void sendMessage(byte[] msg, InetAddress peerAddress, + int peerPort, String peerProtocol, boolean retry) + throws IOException { + // Via is not included in the request so silently drop the reply. + if (peerPort == -1) { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug(getClass().getName() + + ":sendMessage: Dropping reply!"); + } + throw new IOException("Receiver port not set "); + } else { + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug( ":sendMessage " + peerAddress.getHostAddress() + "/" + + peerPort + "\n" + " messageSize = " + msg.length); + } + } + if (peerProtocol.compareToIgnoreCase("UDP") == 0) { + DatagramPacket reply = new DatagramPacket(msg, msg.length, + peerAddress, peerPort); + + try { + DatagramSocket sock; + if (sipStack.udpFlag) { + sock = ((UDPMessageProcessor) messageProcessor).sock; + + } else { + // bind to any interface and port. + sock = sipStack.getNetworkLayer().createDatagramSocket(); + } + if (sipStack.isLoggingEnabled()) { + this.sipStack.getStackLogger().logDebug("sendMessage " + + peerAddress.getHostAddress() + "/" + peerPort + + "\n" + new String(msg)); + } + sock.send(reply); + if (!sipStack.udpFlag) + sock.close(); + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + InternalErrorHandler.handleException(ex); + } + + } else { + // Use TCP to talk back to the sender. + Socket outputSocket = sipStack.ioHandler.sendBytes( + this.messageProcessor.getIpAddress(), peerAddress, + peerPort, "tcp", msg, retry,this); + OutputStream myOutputStream = outputSocket.getOutputStream(); + myOutputStream.write(msg, 0, msg.length); + myOutputStream.flush(); + // The socket is cached (dont close it!); + } + } + + /** + * get the stack pointer. + * + * @return The sip stack for this channel. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * Return a transport string. + * + * @return the string "udp" in this case. + */ + public String getTransport() { + return SIPConstants.UDP; + } + + /** + * get the stack address for the stack that received this message. + * + * @return The stack address for our sipStack. + */ + public String getHost() { + return messageProcessor.getIpAddress().getHostAddress(); + } + + /** + * get the port. + * + * @return Our port (on which we are getting datagram packets). + */ + public int getPort() { + return ((UDPMessageProcessor) messageProcessor).getPort(); + } + + /** + * get the name (address) of the host that sent me the message + * + * @return The name of the sender (from the datagram packet). + */ + public String getPeerName() { + return peerAddress.getHostName(); + } + + /** + * get the address of the host that sent me the message + * + * @return The senders ip address. + */ + public String getPeerAddress() { + return peerAddress.getHostAddress(); + } + + protected InetAddress getPeerInetAddress() { + return peerAddress; + } + + /** + * Compare two UDP Message channels for equality. + * + * @param other + * The other message channel with which to compare oursleves. + */ + public boolean equals(Object other) { + + if (other == null) + return false; + boolean retval; + if (!this.getClass().equals(other.getClass())) { + retval = false; + } else { + UDPMessageChannel that = (UDPMessageChannel) other; + retval = this.getKey().equals(that.getKey()); + } + + return retval; + } + + public String getKey() { + return getKey(peerAddress, peerPort, "UDP"); + } + + public int getPeerPacketSourcePort() { + return peerPacketSourcePort; + } + + public InetAddress getPeerPacketSourceAddress() { + return peerPacketSourceAddress; + } + + /** + * Get the logical originator of the message (from the top via header). + * + * @return topmost via header sentby field + */ + public String getViaHost() { + return this.myAddress; + } + + /** + * Get the logical port of the message orginator (from the top via hdr). + * + * @return the via port from the topmost via header. + */ + public int getViaPort() { + return this.myPort; + } + + /** + * Returns "false" as this is an unreliable transport. + */ + public boolean isReliable() { + return false; + } + + /** + * UDP is not a secure protocol. + */ + public boolean isSecure() { + return false; + } + + public int getPeerPort() { + return peerPort; + } + + public String getPeerProtocol() { + return this.peerProtocol; + } + + /** + * Close the message channel. + */ + public void close() { + } + + +} diff --git a/java/gov/nist/javax/sip/stack/UDPMessageProcessor.java b/java/gov/nist/javax/sip/stack/UDPMessageProcessor.java new file mode 100644 index 0000000..f3d9b47 --- /dev/null +++ b/java/gov/nist/javax/sip/stack/UDPMessageProcessor.java @@ -0,0 +1,350 @@ +/* +* Conditions Of Use +* +* This software was developed by employees of the National Institute of +* Standards and Technology (NIST), an agency of the Federal Government. +* Pursuant to title 15 Untied States Code Section 105, works of NIST +* employees are not subject to copyright protection in the United States +* and are considered to be in the public domain. As a result, a formal +* license is not needed to use the software. +* +* This software is provided by NIST as a service and is expressly +* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED +* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT +* AND DATA ACCURACY. NIST does not warrant or make any representations +* regarding the use of the software or the results thereof, including but +* not limited to the correctness, accuracy, reliability or usefulness of +* the software. +* +* Permission to use this software is contingent upon your acceptance +* of the terms of this agreement +* +* . +* +*/ +/******************************************************************************* + * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * + *******************************************************************************/ +package gov.nist.javax.sip.stack; + +import java.io.IOException; +import java.util.LinkedList; +import java.net.*; + +import gov.nist.core.*; + +/** + * Sit in a loop and handle incoming udp datagram messages. For each Datagram + * packet, a new UDPMessageChannel is created (upto the max thread pool size). + * Each UDP message is processed in its own thread). + * + * @version 1.2 $Revision: 1.37 $ $Date: 2009/11/14 20:06:16 $ + * + * @author M. Ranganathan <br/> + * + * + * + * <a href="{@docRoot}/../uml/udp-request-processing-sequence-diagram.jpg"> + * See the implementation sequence diagram for processing incoming requests. + * </a> + * + * + * Acknowledgement: Jeff Keyser contributed ideas on starting and stoppping the + * stack that were incorporated into this code. Niklas Uhrberg suggested that + * thread pooling be added to limit the number of threads and improve + * performance. + */ +public class UDPMessageProcessor extends MessageProcessor { + /** + * The Mapped port (in case STUN suport is enabled) + */ + private int port; + + /** + * Incoming messages are queued here. + */ + protected LinkedList messageQueue; + + /** + * A list of message channels that we have started. + */ + protected LinkedList messageChannels; + + /** + * Max # of udp message channels + */ + protected int threadPoolSize; + + protected DatagramSocket sock; + + /** + * A flag that is set to false to exit the message processor (suggestion by + * Jeff Keyser). + */ + protected boolean isRunning; + + private static final int HIGHWAT=5000; + + private static final int LOWAT=2500; + + /** + * Constructor. + * + * @param sipStack + * pointer to the stack. + */ + protected UDPMessageProcessor(InetAddress ipAddress, + SIPTransactionStack sipStack, int port) throws IOException { + super(ipAddress, port, "udp",sipStack); + + this.sipStack = sipStack; + + this.messageQueue = new LinkedList(); + + this.port = port; + try { + this.sock = sipStack.getNetworkLayer().createDatagramSocket(port, + ipAddress); + // Create a new datagram socket. + sock.setReceiveBufferSize(sipStack.getReceiveUdpBufferSize()); + sock.setSendBufferSize(sipStack.getSendUdpBufferSize()); + + /** + * If the thread auditor is enabled, define a socket timeout value in order to + * prevent sock.receive() from blocking forever + */ + if (sipStack.getThreadAuditor().isEnabled()) { + sock.setSoTimeout((int) sipStack.getThreadAuditor().getPingIntervalInMillisecs()); + } + if ( ipAddress.getHostAddress().equals(IN_ADDR_ANY) || + ipAddress.getHostAddress().equals(IN6_ADDR_ANY)){ + // Store the address to which we are actually bound + // Note that on WINDOWS this is actually broken. It will + // return IN_ADDR_ANY again. On linux it will return the + // address to which the socket was actually bound. + super.setIpAddress( sock.getLocalAddress() ); + + } + } catch (SocketException ex) { + throw new IOException(ex.getMessage()); + } + } + + + + /** + * Get port on which to listen for incoming stuff. + * + * @return port on which I am listening. + */ + public int getPort() { + return this.port; + } + + /** + * Start our processor thread. + */ + public void start() throws IOException { + + + this.isRunning = true; + Thread thread = new Thread(this); + thread.setDaemon(true); + // Issue #32 on java.net + thread.setName("UDPMessageProcessorThread"); + // Issue #184 + thread.setPriority(Thread.MAX_PRIORITY); + thread.start(); + } + + /** + * Thread main routine. + */ + public void run() { + // Check for running flag. + this.messageChannels = new LinkedList(); + // start all our messageChannels (unless the thread pool size is + // infinity. + if (sipStack.threadPoolSize != -1) { + for (int i = 0; i < sipStack.threadPoolSize; i++) { + UDPMessageChannel channel = new UDPMessageChannel(sipStack, + this); + this.messageChannels.add(channel); + + } + } + + // Ask the auditor to monitor this thread + ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread(); + + // Somebody asked us to exit. if isRunnning is set to false. + while (this.isRunning) { + + try { + // Let the thread auditor know we're up and running + threadHandle.ping(); + + int bufsize = sock.getReceiveBufferSize(); + byte message[] = new byte[bufsize]; + DatagramPacket packet = new DatagramPacket(message, bufsize); + sock.receive(packet); + + + + // This is a simplistic congestion control algorithm. + // It accepts packets if queuesize is < LOWAT. It drops + // requests if the queue size exceeds a HIGHWAT and accepts + // requests with probability p proportional to the difference + // between current queue size and LOWAT in the range + // of queue sizes between HIGHWAT and LOWAT. + // TODO -- penalize spammers by looking at the source + // port and IP address. + if ( sipStack.stackDoesCongestionControl ) { + if ( this.messageQueue.size() >= HIGHWAT) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Dropping message -- queue length exceeded"); + + } + //System.out.println("HIGHWAT Drop!"); + continue; + } else if ( this.messageQueue.size() > LOWAT && this .messageQueue.size() < HIGHWAT ) { + // Drop the message with a probabilty that is linear in the range 0 to 1 + float threshold = ((float)(messageQueue.size() - LOWAT))/ ((float)(HIGHWAT - LOWAT)); + boolean decision = Math.random() > 1.0 - threshold; + if ( decision ) { + if (sipStack.isLoggingEnabled()) { + sipStack.getStackLogger().logDebug("Dropping message with probability " + (1.0 - threshold)); + + } + //System.out.println("RED Drop!"); + continue; + } + + } + } + + + + // Count of # of packets in process. + // this.useCount++; + if (sipStack.threadPoolSize != -1) { + // Note: the only condition watched for by threads + // synchronizing on the messageQueue member is that it is + // not empty. As soon as you introduce some other + // condition you will have to call notifyAll instead of + // notify below. + + synchronized (this.messageQueue) { + // was addLast + this.messageQueue.add(packet); + this.messageQueue.notify(); + } + } else { + new UDPMessageChannel(sipStack, this, packet); + } + } catch (SocketTimeoutException ex) { + // This socket timeout alows us to ping the thread auditor periodically + } catch (SocketException ex) { + if (sipStack.isLoggingEnabled()) + getSIPStack().getStackLogger() + .logDebug("UDPMessageProcessor: Stopping"); + isRunning = false; + // The notifyAll should be in a synchronized block. + // ( bug report by Niklas Uhrberg ). + synchronized (this.messageQueue) { + this.messageQueue.notifyAll(); + } + } catch (IOException ex) { + isRunning = false; + ex.printStackTrace(); + if (sipStack.isLoggingEnabled()) + getSIPStack().getStackLogger() + .logDebug("UDPMessageProcessor: Got an IO Exception"); + } catch (Exception ex) { + if (sipStack.isLoggingEnabled()) + getSIPStack().getStackLogger() + .logDebug("UDPMessageProcessor: Unexpected Exception - quitting"); + InternalErrorHandler.handleException(ex); + return; + } + } + } + + /** + * Shut down the message processor. Close the socket for recieving incoming + * messages. + */ + public void stop() { + synchronized (this.messageQueue) { + this.isRunning = false; + this.messageQueue.notifyAll(); + sock.close(); + + + } + } + + /** + * Return the transport string. + * + * @return the transport string + */ + public String getTransport() { + return "udp"; + } + + /** + * Returns the stack. + * + * @return my sip stack. + */ + public SIPTransactionStack getSIPStack() { + return sipStack; + } + + /** + * Create and return new TCPMessageChannel for the given host/port. + */ + public MessageChannel createMessageChannel(HostPort targetHostPort) + throws UnknownHostException { + return new UDPMessageChannel(targetHostPort.getInetAddress(), + targetHostPort.getPort(), sipStack, this); + } + + public MessageChannel createMessageChannel(InetAddress host, int port) + throws IOException { + return new UDPMessageChannel(host, port, sipStack, this); + } + + /** + * Default target port for UDP + */ + public int getDefaultTargetPort() { + return 5060; + } + + /** + * UDP is not a secure protocol. + */ + public boolean isSecure() { + return false; + } + + /** + * UDP can handle a message as large as the MAX_DATAGRAM_SIZE. + */ + public int getMaximumMessageSize() { + return 8*1024; + } + + /** + * Return true if there are any messages in use. + */ + public boolean inUse() { + synchronized (messageQueue) { + return messageQueue.size() != 0; + } + } + +} diff --git a/java/gov/nist/javax/sip/stack/package.html b/java/gov/nist/javax/sip/stack/package.html new file mode 100644 index 0000000..40d848e --- /dev/null +++ b/java/gov/nist/javax/sip/stack/package.html @@ -0,0 +1,12 @@ +<body> +This package implements the main protocol abstractions that are defined by the SIP RFC 3261. +These include the following main ones: +<ul> +<li>SIPServerTransaction -- an implementation of the Server Transaction State Machine (Chapter 17 of RFC 3261). +<li>SIPClientTransaction -- an implementation of the Client Transction State Machine (Chapter 17 of RFC 3261). +<li>SIPDialog -- an implementation of the SIP Dialog ( Chapter 11 of RFC 3261 ). +</ul> + +SIPTransactionStack is the container that holds references to these protocol objects. + +</body> diff --git a/java/javax/sip/ClientTransaction.java b/java/javax/sip/ClientTransaction.java new file mode 100644 index 0000000..8d87f9a --- /dev/null +++ b/java/javax/sip/ClientTransaction.java @@ -0,0 +1,23 @@ +package javax.sip; + +import javax.sip.address.Hop; +import javax.sip.message.Request; + +public interface ClientTransaction extends Transaction { + /** + * @deprecated + * For 2xx response, use {@link Dialog.createAck(long)}. The application + * should not need to handle non-2xx responses. + */ + Request createAck() throws SipException; + + Request createCancel() throws SipException; + void sendRequest() throws SipException; + + void alertIfStillInCallingStateBy(int count); + + Hop getNextHop(); + + void setNotifyOnRetransmit(boolean notifyOnRetransmit); +} + diff --git a/java/javax/sip/Dialog.java b/java/javax/sip/Dialog.java new file mode 100644 index 0000000..7829263 --- /dev/null +++ b/java/javax/sip/Dialog.java @@ -0,0 +1,80 @@ +package javax.sip; + +import java.io.Serializable; +import java.text.ParseException; +import java.util.Iterator; +import javax.sip.address.Address; +import javax.sip.header.CallIdHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +public interface Dialog extends Serializable { + Object getApplicationData(); + void setApplicationData(Object applicationData); + + CallIdHeader getCallId(); + String getDialogId(); + + /** + * @deprecated + */ + Transaction getFirstTransaction(); + + Address getLocalParty(); + + /** + * @deprecated + * @see #getLocalSeqNumber() + */ + int getLocalSequenceNumber(); + + long getLocalSeqNumber(); + + String getLocalTag(); + + Address getRemoteParty(); + + /** + * @deprecated + * @see #getRemoteSeqNumber() + */ + int getRemoteSequenceNumber(); + + long getRemoteSeqNumber(); + + String getRemoteTag(); + + Address getRemoteTarget(); + + Iterator getRouteSet(); + + SipProvider getSipProvider(); + + DialogState getState(); + + boolean isSecure(); + + boolean isServer(); + + void delete(); + + void incrementLocalSequenceNumber(); + + Request createRequest(String method) throws SipException; + Request createAck(long cseq) throws InvalidArgumentException, SipException; + Request createPrack(Response relResponse) + throws DialogDoesNotExistException, SipException; + Response createReliableProvisionalResponse(int statusCode) + throws InvalidArgumentException, SipException; + + + void sendRequest(ClientTransaction clientTransaction) + throws TransactionDoesNotExistException, SipException; + void sendAck(Request ackRequest) throws SipException; + void sendReliableProvisionalResponse(Response relResponse) + throws SipException; + + void setBackToBackUserAgent(); + + void terminateOnBye(boolean terminateFlag) throws SipException; +} diff --git a/java/javax/sip/DialogDoesNotExistException.java b/java/javax/sip/DialogDoesNotExistException.java new file mode 100644 index 0000000..91b6116 --- /dev/null +++ b/java/javax/sip/DialogDoesNotExistException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class DialogDoesNotExistException extends SipException { + public DialogDoesNotExistException(){ + } + + public DialogDoesNotExistException(String message) { + super(message); + } + + public DialogDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/DialogState.java b/java/javax/sip/DialogState.java new file mode 100644 index 0000000..f134fee --- /dev/null +++ b/java/javax/sip/DialogState.java @@ -0,0 +1,24 @@ +package javax.sip; + +public enum DialogState { + EARLY, + CONFIRMED, + TERMINATED; + + public static final int _EARLY = EARLY.ordinal(); + public static final int _CONFIRMED = CONFIRMED.ordinal(); + public static final int _TERMINATED = TERMINATED.ordinal(); + + public static DialogState getObject(int state) { + try { + return values()[state]; + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException( + "Invalid dialog state: " + state); + } + } + + public int getValue() { + return ordinal(); + } +} diff --git a/java/javax/sip/DialogTerminatedEvent.java b/java/javax/sip/DialogTerminatedEvent.java new file mode 100644 index 0000000..5e1115b --- /dev/null +++ b/java/javax/sip/DialogTerminatedEvent.java @@ -0,0 +1,16 @@ +package javax.sip; + +import java.util.EventObject; + +public class DialogTerminatedEvent extends EventObject { + private Dialog mDialog; + + public DialogTerminatedEvent(Object source, Dialog dialog) { + super(source); + mDialog = dialog; + } + + public Dialog getDialog() { + return mDialog; + } +} diff --git a/java/javax/sip/IOExceptionEvent.java b/java/javax/sip/IOExceptionEvent.java new file mode 100644 index 0000000..a3d20e2 --- /dev/null +++ b/java/javax/sip/IOExceptionEvent.java @@ -0,0 +1,29 @@ +package javax.sip; + +import java.util.EventObject; + +public class IOExceptionEvent extends EventObject { + private String mHost; + private int mPort; + private String mTransport; + + public IOExceptionEvent(Object source, String host, int port, + String transport) { + super(source); + mHost = host; + mPort = port; + mTransport = transport; + } + + public String getHost() { + return mHost; + } + + public int getPort() { + return mPort; + } + + public String getTransport() { + return mTransport; + } +} diff --git a/java/javax/sip/InvalidArgumentException.java b/java/javax/sip/InvalidArgumentException.java new file mode 100644 index 0000000..d17688d --- /dev/null +++ b/java/javax/sip/InvalidArgumentException.java @@ -0,0 +1,14 @@ +package javax.sip; + +public class InvalidArgumentException extends SipException { + public InvalidArgumentException() { + } + + public InvalidArgumentException(String message) { + super(message); + } + + public InvalidArgumentException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/java/javax/sip/ListeningPoint.java b/java/javax/sip/ListeningPoint.java new file mode 100644 index 0000000..dfb626b --- /dev/null +++ b/java/javax/sip/ListeningPoint.java @@ -0,0 +1,26 @@ +package javax.sip; + +import java.io.IOException; +import java.text.ParseException; +import javax.sip.header.ContactHeader; + +public interface ListeningPoint extends Cloneable { + String TCP = "TCP"; + String UDP = "UDP"; + String SCTP = "SCTP"; + String TLS = "TLS"; + int PORT_5060 = 5060; + int PORT_5061 = 5061; + + String getIPAddress(); + int getPort(); + String getTransport(); + + String getSentBy(); + void setSentBy(String sentBy) throws ParseException; + + ContactHeader createContactHeader(); + + void sendHeartbeat(String s, int i) throws IOException; +} + diff --git a/java/javax/sip/ObjectInUseException.java b/java/javax/sip/ObjectInUseException.java new file mode 100644 index 0000000..98d60d6 --- /dev/null +++ b/java/javax/sip/ObjectInUseException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class ObjectInUseException extends SipException { + public ObjectInUseException() { + } + + public ObjectInUseException(String message) { + super(message); + } + + public ObjectInUseException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/PeerUnavailableException.java b/java/javax/sip/PeerUnavailableException.java new file mode 100644 index 0000000..cb2c87d --- /dev/null +++ b/java/javax/sip/PeerUnavailableException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class PeerUnavailableException extends SipException { + public PeerUnavailableException() { + } + + public PeerUnavailableException(String message) { + super(message); + } + + public PeerUnavailableException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/ProviderDoesNotExistException.java b/java/javax/sip/ProviderDoesNotExistException.java new file mode 100644 index 0000000..91be313 --- /dev/null +++ b/java/javax/sip/ProviderDoesNotExistException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class ProviderDoesNotExistException extends SipException { + public ProviderDoesNotExistException(){ + } + + public ProviderDoesNotExistException(String message) { + super(message); + } + + public ProviderDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/RequestEvent.java b/java/javax/sip/RequestEvent.java new file mode 100644 index 0000000..cf72e69 --- /dev/null +++ b/java/javax/sip/RequestEvent.java @@ -0,0 +1,30 @@ +package javax.sip; + +import java.util.EventObject; +import javax.sip.message.Request; + +public class RequestEvent extends EventObject { + private Dialog mDialog; + private Request mRequest; + private ServerTransaction mServerTransaction; + + public RequestEvent(Object source, ServerTransaction serverTransaction, + Dialog dialog, Request request) { + super(source); + mDialog = dialog; + mRequest = request; + mServerTransaction = serverTransaction; + } + + public Dialog getDialog() { + return mDialog; + } + + public Request getRequest() { + return mRequest; + } + + public ServerTransaction getServerTransaction() { + return mServerTransaction; + } +} diff --git a/java/javax/sip/ResponseEvent.java b/java/javax/sip/ResponseEvent.java new file mode 100644 index 0000000..9a63677 --- /dev/null +++ b/java/javax/sip/ResponseEvent.java @@ -0,0 +1,30 @@ +package javax.sip; + +import java.util.EventObject; +import javax.sip.message.Response; + +public class ResponseEvent extends EventObject { + private Dialog mDialog; + private Response mResponse; + private ClientTransaction mClientTransaction; + + public ResponseEvent(Object source, ClientTransaction clientTransaction, + Dialog dialog, Response response) { + super(source); + mDialog = dialog; + mResponse = response; + mClientTransaction = clientTransaction; + } + + public Dialog getDialog() { + return mDialog; + } + + public Response getResponse() { + return mResponse; + } + + public ClientTransaction getClientTransaction(){ + return mClientTransaction; + } +} diff --git a/java/javax/sip/ServerTransaction.java b/java/javax/sip/ServerTransaction.java new file mode 100644 index 0000000..4398b20 --- /dev/null +++ b/java/javax/sip/ServerTransaction.java @@ -0,0 +1,12 @@ +package javax.sip; + +import javax.sip.message.Response; + +public interface ServerTransaction extends Transaction { + void sendResponse(Response response) + throws SipException, InvalidArgumentException; + + void enableRetransmissionAlerts() throws SipException; + + ServerTransaction getCanceledInviteTransaction(); +} diff --git a/java/javax/sip/SipException.java b/java/javax/sip/SipException.java new file mode 100644 index 0000000..50b3545 --- /dev/null +++ b/java/javax/sip/SipException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class SipException extends Exception { + public SipException() { + } + + public SipException(String message) { + super(message); + } + + public SipException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/SipFactory.java b/java/javax/sip/SipFactory.java new file mode 100644 index 0000000..e175b82 --- /dev/null +++ b/java/javax/sip/SipFactory.java @@ -0,0 +1,104 @@ +package javax.sip; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import javax.sip.address.AddressFactory; +import javax.sip.header.HeaderFactory; +import javax.sip.message.MessageFactory; + +public class SipFactory { + private static final String IP_ADDRESS_PROP = "javax.sip.IP_ADDRESS"; + private static final String STACK_NAME_PROP = "javax.sip.STACK_NAME"; + + private static SipFactory sSipFactory = null; + + public static synchronized SipFactory getInstance() { + if (sSipFactory == null) sSipFactory = new SipFactory(); + return sSipFactory; + } + + // name-to-SipStack map; name could be IP address for backward compatibility + private Map<String, SipStack> mNameSipStackMap = + new HashMap<String, SipStack>(); + + private SipFactory() { + } + + public synchronized void resetFactory() { + mNameSipStackMap.clear(); + } + + public synchronized SipStack createSipStack(Properties properties) + throws PeerUnavailableException { + // for backward compatibility, if IP_ADDRESS_PROP exists, use it and + // ignore STACK_NAME_PROP. + String name = properties.getProperty(IP_ADDRESS_PROP); + if (name == null) { + name = properties.getProperty(STACK_NAME_PROP); + if (name == null ) { + throw new PeerUnavailableException( + STACK_NAME_PROP + " property not found"); + } + } + + SipStack sipStack = mNameSipStackMap.get(name); + if (sipStack == null) { + String implClassName = "gov.nist." + + SipStack.class.getCanonicalName() + "Impl"; + try { + sipStack = Class.forName(implClassName) + .asSubclass(SipStack.class) + .getConstructor(new Class[] {Properties.class}) + .newInstance(new Object[] {properties}); + } catch (Exception e) { + throw new PeerUnavailableException( + "Failed to initiate " + implClassName, e); + } + mNameSipStackMap.put(name, sipStack); + } + return sipStack; + } + + public AddressFactory createAddressFactory() + throws PeerUnavailableException { + try { + return new gov.nist.javax.sip.address.AddressFactoryImpl(); + } catch (Exception e) { + if (e instanceof PeerUnavailableException) { + throw (PeerUnavailableException) e; + } else { + throw new PeerUnavailableException( + "Failed to create AddressFactory", e); + } + } + } + + public HeaderFactory createHeaderFactory() throws PeerUnavailableException { + try { + return new gov.nist.javax.sip.header.HeaderFactoryImpl(); + } catch (Exception e) { + if (e instanceof PeerUnavailableException) { + throw (PeerUnavailableException) e; + } else { + throw new PeerUnavailableException( + "Failed to create HeaderFactory", e); + } + } + } + + public MessageFactory createMessageFactory() + throws PeerUnavailableException { + try { + return new gov.nist.javax.sip.message.MessageFactoryImpl(); + } catch (Exception e) { + if (e instanceof PeerUnavailableException) { + throw (PeerUnavailableException) e; + } else { + throw new PeerUnavailableException( + "Failed to create MessageFactory", e); + } + } + } +} diff --git a/java/javax/sip/SipListener.java b/java/javax/sip/SipListener.java new file mode 100644 index 0000000..22c460d --- /dev/null +++ b/java/javax/sip/SipListener.java @@ -0,0 +1,12 @@ +package javax.sip; + +public interface SipListener { + void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent); + void processIOException(IOExceptionEvent exceptionEvent); + void processRequest(RequestEvent requestEvent); + void processResponse(ResponseEvent responseEvent); + void processTimeout(TimeoutEvent timeoutEvent); + void processTransactionTerminated( + TransactionTerminatedEvent transactionTerminatedEvent); +} + diff --git a/java/javax/sip/SipProvider.java b/java/javax/sip/SipProvider.java new file mode 100644 index 0000000..1b7cb91 --- /dev/null +++ b/java/javax/sip/SipProvider.java @@ -0,0 +1,51 @@ +package javax.sip; + +import java.util.TooManyListenersException; +import javax.sip.header.CallIdHeader; +import javax.sip.message.Request; +import javax.sip.message.Response; + +public interface SipProvider { + /** + * @deprecated + * @see #addListeningPoint(ListeningPoint) + */ + void setListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException; + void addListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException; + void removeListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException; + void removeListeningPoints(); + + /** + * @deprecated + * @see #getListeningPoints() + */ + ListeningPoint getListeningPoint(); + ListeningPoint getListeningPoint(String transport); + ListeningPoint[] getListeningPoints(); + + void addSipListener(SipListener sipListener) + throws TooManyListenersException; + void removeSipListener(SipListener sipListener); + + CallIdHeader getNewCallId(); + + ClientTransaction getNewClientTransaction(Request request) + throws TransactionUnavailableException; + ServerTransaction getNewServerTransaction(Request request) + throws TransactionAlreadyExistsException, + TransactionUnavailableException; + + Dialog getNewDialog(Transaction transaction) throws SipException; + + boolean isAutomaticDialogSupportEnabled(); + void setAutomaticDialogSupportEnabled(boolean flag); + + SipStack getSipStack(); + + void sendRequest(Request request) throws SipException; + void sendResponse(Response response) throws SipException; +} + diff --git a/java/javax/sip/SipStack.java b/java/javax/sip/SipStack.java new file mode 100644 index 0000000..57447d4 --- /dev/null +++ b/java/javax/sip/SipStack.java @@ -0,0 +1,41 @@ +package javax.sip; + +import java.util.Collection; +import java.util.Iterator; +import javax.sip.address.Router; + +public interface SipStack { + /** + * Deprecated. Use {@link #createListeningPoint(String, int, String)} + * instead. + */ + ListeningPoint createListeningPoint(int port, String transport) + throws TransportNotSupportedException, InvalidArgumentException; + ListeningPoint createListeningPoint(String ipAddress, int port, + String transport) throws TransportNotSupportedException, + InvalidArgumentException; + void deleteListeningPoint(ListeningPoint listeningPoint) + throws ObjectInUseException; + + SipProvider createSipProvider(ListeningPoint listeningPoint) + throws ObjectInUseException; + void deleteSipProvider(SipProvider sipProvider) throws ObjectInUseException; + + Collection getDialogs(); + String getIPAddress(); + Iterator getListeningPoints(); + Router getRouter(); + Iterator getSipProviders(); + String getStackName(); + + /** + * @deprecated + * Use {@link ServerTransaction#enableRetransmissionAlerts()} to enable + * retransmission alerts instead. + */ + boolean isRetransmissionFilterActive(); + + void start() throws ProviderDoesNotExistException, SipException; + void stop(); +} + diff --git a/java/javax/sip/Timeout.java b/java/javax/sip/Timeout.java new file mode 100644 index 0000000..63329e9 --- /dev/null +++ b/java/javax/sip/Timeout.java @@ -0,0 +1,6 @@ +package javax.sip; + +public enum Timeout { + RETRANSMIT, + TRANSACTION; +} diff --git a/java/javax/sip/TimeoutEvent.java b/java/javax/sip/TimeoutEvent.java new file mode 100644 index 0000000..245994e --- /dev/null +++ b/java/javax/sip/TimeoutEvent.java @@ -0,0 +1,21 @@ +package javax.sip; + +public class TimeoutEvent extends TransactionTerminatedEvent { + private Timeout mTimeout; + + public TimeoutEvent(Object source, ServerTransaction serverTransaction, + Timeout timeout) { + super(source, serverTransaction); + mTimeout = timeout; + } + + public TimeoutEvent(Object source, ClientTransaction clientTransaction, + Timeout timeout) { + super(source, clientTransaction); + mTimeout = timeout; + } + + public Timeout getTimeout() { + return mTimeout; + } +} diff --git a/java/javax/sip/Transaction.java b/java/javax/sip/Transaction.java new file mode 100644 index 0000000..481f5ad --- /dev/null +++ b/java/javax/sip/Transaction.java @@ -0,0 +1,26 @@ +package javax.sip; + +import java.io.Serializable; +import javax.sip.message.Request; + +public interface Transaction extends Serializable { + Object getApplicationData(); + void setApplicationData (Object applicationData); + + String getBranchId(); + Dialog getDialog(); + String getHost(); + String getPeerAddress(); + int getPeerPort(); + int getPort(); + Request getRequest(); + SipProvider getSipProvider(); + TransactionState getState(); + String getTransport(); + + int getRetransmitTimer() throws UnsupportedOperationException; + void setRetransmitTimer(int retransmitTimer) + throws UnsupportedOperationException; + + void terminate() throws ObjectInUseException; +} diff --git a/java/javax/sip/TransactionAlreadyExistsException.java b/java/javax/sip/TransactionAlreadyExistsException.java new file mode 100644 index 0000000..30ba646 --- /dev/null +++ b/java/javax/sip/TransactionAlreadyExistsException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class TransactionAlreadyExistsException extends SipException { + public TransactionAlreadyExistsException(){ + } + + public TransactionAlreadyExistsException(String message) { + super(message); + } + + public TransactionAlreadyExistsException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/TransactionDoesNotExistException.java b/java/javax/sip/TransactionDoesNotExistException.java new file mode 100644 index 0000000..9257c95 --- /dev/null +++ b/java/javax/sip/TransactionDoesNotExistException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class TransactionDoesNotExistException extends SipException { + public TransactionDoesNotExistException(){ + } + + public TransactionDoesNotExistException(String message) { + super(message); + } + + public TransactionDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/TransactionState.java b/java/javax/sip/TransactionState.java new file mode 100644 index 0000000..235bbf8 --- /dev/null +++ b/java/javax/sip/TransactionState.java @@ -0,0 +1,10 @@ +package javax.sip; + +public enum TransactionState { + CALLING, + TRYING, + PROCEEDING, + COMPLETED, + CONFIRMED, + TERMINATED; +} diff --git a/java/javax/sip/TransactionTerminatedEvent.java b/java/javax/sip/TransactionTerminatedEvent.java new file mode 100644 index 0000000..9299045 --- /dev/null +++ b/java/javax/sip/TransactionTerminatedEvent.java @@ -0,0 +1,37 @@ +package javax.sip; + +import java.util.EventObject; + +public class TransactionTerminatedEvent extends EventObject { + private boolean mIsServerTransaction; + private ServerTransaction mServerTransaction; + private ClientTransaction mClientTransaction; + + public TransactionTerminatedEvent( + Object source, ServerTransaction serverTransaction) { + super(source); + mServerTransaction = serverTransaction; + + mIsServerTransaction = true; + } + + public TransactionTerminatedEvent( + Object source, ClientTransaction clientTransaction) { + super(source); + mClientTransaction = clientTransaction; + + mIsServerTransaction = false; + } + + public boolean isServerTransaction() { + return mIsServerTransaction; + } + + public ClientTransaction getClientTransaction() { + return mClientTransaction; + } + + public ServerTransaction getServerTransaction() { + return mServerTransaction; + } +} diff --git a/java/javax/sip/TransactionUnavailableException.java b/java/javax/sip/TransactionUnavailableException.java new file mode 100644 index 0000000..52f3f82 --- /dev/null +++ b/java/javax/sip/TransactionUnavailableException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class TransactionUnavailableException extends SipException { + public TransactionUnavailableException() { + } + + public TransactionUnavailableException(String message) { + super(message); + } + + public TransactionUnavailableException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/TransportNotSupportedException.java b/java/javax/sip/TransportNotSupportedException.java new file mode 100644 index 0000000..c8a1a53 --- /dev/null +++ b/java/javax/sip/TransportNotSupportedException.java @@ -0,0 +1,15 @@ +package javax.sip; + +public class TransportNotSupportedException extends SipException { + public TransportNotSupportedException() { + } + + public TransportNotSupportedException(String message) { + super(message); + } + + public TransportNotSupportedException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/address/Address.java b/java/javax/sip/address/Address.java new file mode 100644 index 0000000..34fc1db --- /dev/null +++ b/java/javax/sip/address/Address.java @@ -0,0 +1,27 @@ +package javax.sip.address; + +import java.io.Serializable; +import java.text.ParseException; + +public interface Address extends Cloneable, Serializable { + String getDisplayName(); + void setDisplayName(String displayName) throws ParseException; + boolean hasDisplayName(); + + String getHost(); + int getPort(); + String getUserAtHostPort(); + + boolean isSIPAddress(); + + URI getURI(); + void setURI(URI uri); + + boolean isWildcard(); + void setWildCardFlag(); + + boolean equals(Object obj); + int hashCode(); + Object clone(); +} + diff --git a/java/javax/sip/address/AddressFactory.java b/java/javax/sip/address/AddressFactory.java new file mode 100644 index 0000000..540af3d --- /dev/null +++ b/java/javax/sip/address/AddressFactory.java @@ -0,0 +1,16 @@ +package javax.sip.address; + +import java.text.ParseException; + +public interface AddressFactory { + Address createAddress(); + Address createAddress(String address) throws ParseException; + Address createAddress(URI uri); + Address createAddress(String displayName, URI uri) + throws ParseException; + SipURI createSipURI(String uri) throws ParseException; + SipURI createSipURI(String user, String host) throws ParseException; + TelURL createTelURL(String uri) throws ParseException; + URI createURI(String uri) throws ParseException; +} + diff --git a/java/javax/sip/address/Hop.java b/java/javax/sip/address/Hop.java new file mode 100644 index 0000000..fcb0e90 --- /dev/null +++ b/java/javax/sip/address/Hop.java @@ -0,0 +1,13 @@ +package javax.sip.address; + +public interface Hop { + String getHost(); + int getPort(); + String getTransport(); + + boolean isURIRoute(); + void setURIRouteFlag(); + + String toString(); +} + diff --git a/java/javax/sip/address/Router.java b/java/javax/sip/address/Router.java new file mode 100644 index 0000000..52be450 --- /dev/null +++ b/java/javax/sip/address/Router.java @@ -0,0 +1,12 @@ +package javax.sip.address; + +import java.util.ListIterator; +import javax.sip.SipException; +import javax.sip.message.Request; + +public interface Router { + Hop getNextHop(Request request) throws SipException; + ListIterator getNextHops(Request request); + Hop getOutboundProxy(); +} + diff --git a/java/javax/sip/address/SipURI.java b/java/javax/sip/address/SipURI.java new file mode 100644 index 0000000..ec40c8c --- /dev/null +++ b/java/javax/sip/address/SipURI.java @@ -0,0 +1,53 @@ +package javax.sip.address; + +import java.text.ParseException; +import java.util.Iterator; +import javax.sip.header.Parameters; +import javax.sip.InvalidArgumentException; + +public interface SipURI extends URI, Parameters { + boolean isSecure(); + void setSecure(boolean secure); + + String getHeader(String name); + void setHeader(String name, String value); + Iterator getHeaderNames(); + + String getHost(); + void setHost(String host) throws ParseException; + + String getLrParam(); + void setLrParam(); + boolean hasLrParam(); + + String getMAddrParam(); + void setMAddrParam(String mAddrParam) throws ParseException; + + int getPort(); + void setPort(int port) throws InvalidArgumentException; + + int getTTLParam(); + void setTTLParam(int ttlParam); + + String getTransportParam(); + void setTransportParam(String transportParam) throws ParseException; + boolean hasTransport(); + + String getUser(); + void setUser(String user); + String getUserParam(); + void setUserParam(String userParam); + + String getUserType(); + void removeUserType(); + + String getUserPassword(); + void setUserPassword(String userPassword); + + String getUserAtHost(); + String getUserAtHostPort(); + + String getMethodParam(); + void setMethodParam(String methodParam) throws ParseException; +} + diff --git a/java/javax/sip/address/TelURL.java b/java/javax/sip/address/TelURL.java new file mode 100644 index 0000000..247781f --- /dev/null +++ b/java/javax/sip/address/TelURL.java @@ -0,0 +1,21 @@ +package javax.sip.address; + +import java.text.ParseException; +import javax.sip.header.Parameters; + +public interface TelURL extends URI, Parameters { + String getIsdnSubAddress(); + void setIsdnSubAddress(String isdnSubAddress) throws ParseException; + + String getPhoneContext(); + void setPhoneContext(String phoneContext) throws ParseException; + + String getPhoneNumber(); + void setPhoneNumber(String phoneNumber) throws ParseException; + + String getPostDial(); + void setPostDial(String postDial) throws ParseException; + + boolean isGlobal(); + void setGlobal(boolean global); +} diff --git a/java/javax/sip/address/URI.java b/java/javax/sip/address/URI.java new file mode 100644 index 0000000..6ea37ef --- /dev/null +++ b/java/javax/sip/address/URI.java @@ -0,0 +1,12 @@ +package javax.sip.address; + +import java.io.Serializable; + +public interface URI extends Cloneable, Serializable { + String getScheme(); + boolean isSipURI(); + + Object clone(); + String toString(); +} + diff --git a/java/javax/sip/header/AcceptEncodingHeader.java b/java/javax/sip/header/AcceptEncodingHeader.java new file mode 100644 index 0000000..8c90e24 --- /dev/null +++ b/java/javax/sip/header/AcceptEncodingHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface AcceptEncodingHeader extends Encoding, Header, Parameters { + String NAME = "Accept-Encoding"; + + float getQValue(); + void setQValue(float qValue) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/AcceptHeader.java b/java/javax/sip/header/AcceptHeader.java new file mode 100644 index 0000000..bba2dd4 --- /dev/null +++ b/java/javax/sip/header/AcceptHeader.java @@ -0,0 +1,15 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface AcceptHeader extends Header, MediaType, Parameters { + String NAME = "Accept"; + + boolean allowsAllContentSubTypes(); + boolean allowsAllContentTypes(); + + float getQValue(); + void setQValue(float qValue) throws InvalidArgumentException; + boolean hasQValue(); + void removeQValue(); +} diff --git a/java/javax/sip/header/AcceptLanguageHeader.java b/java/javax/sip/header/AcceptLanguageHeader.java new file mode 100644 index 0000000..c0e428a --- /dev/null +++ b/java/javax/sip/header/AcceptLanguageHeader.java @@ -0,0 +1,17 @@ +package javax.sip.header; + +import java.util.Locale; +import javax.sip.InvalidArgumentException; + +public interface AcceptLanguageHeader extends Header, Parameters { + String NAME = "Accept-Language"; + + Locale getAcceptLanguage(); + void setAcceptLanguage(Locale acceptLanguage); + void setLanguageRange(String languageRange); + + float getQValue(); + void setQValue(float qValue) throws InvalidArgumentException; + boolean hasQValue(); + void removeQValue(); +} diff --git a/java/javax/sip/header/AlertInfoHeader.java b/java/javax/sip/header/AlertInfoHeader.java new file mode 100644 index 0000000..4c6c51b --- /dev/null +++ b/java/javax/sip/header/AlertInfoHeader.java @@ -0,0 +1,11 @@ +package javax.sip.header; + +import javax.sip.address.URI; + +public interface AlertInfoHeader extends Header, Parameters { + String NAME = "Alert-Info"; + + URI getAlertInfo(); + void setAlertInfo(URI alertInfo); + void setAlertInfo(String alertInfo); +} diff --git a/java/javax/sip/header/AllowEventsHeader.java b/java/javax/sip/header/AllowEventsHeader.java new file mode 100644 index 0000000..89c1a14 --- /dev/null +++ b/java/javax/sip/header/AllowEventsHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface AllowEventsHeader extends Header { + String NAME = "Allow-Events"; + + String getEventType(); + void setEventType(String eventType) throws ParseException; +} diff --git a/java/javax/sip/header/AllowHeader.java b/java/javax/sip/header/AllowHeader.java new file mode 100644 index 0000000..71b748a --- /dev/null +++ b/java/javax/sip/header/AllowHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface AllowHeader extends Header { + String NAME = "Allow"; + + String getMethod(); + void setMethod(String method) throws ParseException; +} diff --git a/java/javax/sip/header/AuthenticationInfoHeader.java b/java/javax/sip/header/AuthenticationInfoHeader.java new file mode 100644 index 0000000..37b0248 --- /dev/null +++ b/java/javax/sip/header/AuthenticationInfoHeader.java @@ -0,0 +1,22 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface AuthenticationInfoHeader extends Header, Parameters { + String NAME = "Authentication-Info"; + + String getCNonce(); + void setCNonce(String cNonce) throws ParseException; + + String getNextNonce(); + void setNextNonce(String nextNonce) throws ParseException; + + int getNonceCount(); + void setNonceCount(int nonceCount) throws ParseException; + + String getQop(); + void setQop(String qop) throws ParseException; + + String getResponse(); + void setResponse(String response) throws ParseException; +} diff --git a/java/javax/sip/header/AuthorizationHeader.java b/java/javax/sip/header/AuthorizationHeader.java new file mode 100644 index 0000000..bff4e80 --- /dev/null +++ b/java/javax/sip/header/AuthorizationHeader.java @@ -0,0 +1,44 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.address.URI; + +public interface AuthorizationHeader extends Header, Parameters { + String NAME = "Authorization"; + + String getAlgorithm(); + void setAlgorithm(String algorithm) throws ParseException; + + String getCNonce(); + void setCNonce(String cNonce) throws ParseException; + + String getNonce(); + void setNonce(String nonce) throws ParseException; + + int getNonceCount(); + void setNonceCount(int nonceCount) throws ParseException; + + String getOpaque(); + void setOpaque(String opaque) throws ParseException; + + String getQop(); + void setQop(String qop) throws ParseException; + + String getRealm(); + void setRealm(String realm) throws ParseException; + + String getResponse(); + void setResponse(String response) throws ParseException; + + String getScheme(); + void setScheme(String scheme); + + boolean isStale(); + void setStale(boolean stale); + + URI getURI(); + void setURI(URI uri); + + String getUsername(); + void setUsername(String username) throws ParseException; +} diff --git a/java/javax/sip/header/CSeqHeader.java b/java/javax/sip/header/CSeqHeader.java new file mode 100644 index 0000000..317d9d6 --- /dev/null +++ b/java/javax/sip/header/CSeqHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface CSeqHeader extends AllowHeader, RSeqHeader { + String NAME = "CSeq"; +} diff --git a/java/javax/sip/header/CallIdHeader.java b/java/javax/sip/header/CallIdHeader.java new file mode 100644 index 0000000..126bbae --- /dev/null +++ b/java/javax/sip/header/CallIdHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface CallIdHeader extends Header { + String NAME = "Call-ID"; + + String getCallId(); + void setCallId(String callId) throws ParseException; +} diff --git a/java/javax/sip/header/CallInfoHeader.java b/java/javax/sip/header/CallInfoHeader.java new file mode 100644 index 0000000..89d1de7 --- /dev/null +++ b/java/javax/sip/header/CallInfoHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import javax.sip.address.URI; + +public interface CallInfoHeader extends Header, Parameters { + String NAME = "Call-Info"; + + URI getInfo(); + void setInfo(URI info); + + String getPurpose(); + void setPurpose(String purpose); +} diff --git a/java/javax/sip/header/ContactHeader.java b/java/javax/sip/header/ContactHeader.java new file mode 100644 index 0000000..301afe9 --- /dev/null +++ b/java/javax/sip/header/ContactHeader.java @@ -0,0 +1,17 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface ContactHeader extends HeaderAddress, Header, Parameters { + String NAME = "Contact"; + + int getExpires(); + void setExpires(int expires) throws InvalidArgumentException; + + float getQValue(); + void setQValue(float qValue) throws InvalidArgumentException; + + boolean isWildCard(); + void setWildCard(); + void setWildCardFlag(boolean wildCardFlag); +} diff --git a/java/javax/sip/header/ContentDispositionHeader.java b/java/javax/sip/header/ContentDispositionHeader.java new file mode 100644 index 0000000..535e646 --- /dev/null +++ b/java/javax/sip/header/ContentDispositionHeader.java @@ -0,0 +1,18 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface ContentDispositionHeader extends Header, Parameters { + String NAME = "Content-Disposition"; + + String RENDER = "Render"; + String SESSION = "Session"; + String ICON = "Icon"; + String ALERT = "Alert"; + + String getDispositionType(); + void setDispositionType(String dispositionType) throws ParseException; + + String getHandling(); + void setHandling(String handling) throws ParseException; +} diff --git a/java/javax/sip/header/ContentEncodingHeader.java b/java/javax/sip/header/ContentEncodingHeader.java new file mode 100644 index 0000000..3730095 --- /dev/null +++ b/java/javax/sip/header/ContentEncodingHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface ContentEncodingHeader extends Encoding, Header { + String NAME = "Content-Encoding"; +} diff --git a/java/javax/sip/header/ContentLanguageHeader.java b/java/javax/sip/header/ContentLanguageHeader.java new file mode 100644 index 0000000..f8640ef --- /dev/null +++ b/java/javax/sip/header/ContentLanguageHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import java.util.Locale; + +public interface ContentLanguageHeader extends Header { + String NAME = "Content-Language"; + + Locale getContentLanguage(); + void setContentLanguage(Locale language); + + String getLanguageTag(); + void setLanguageTag(String languageTag); +} diff --git a/java/javax/sip/header/ContentLengthHeader.java b/java/javax/sip/header/ContentLengthHeader.java new file mode 100644 index 0000000..6eb59fa --- /dev/null +++ b/java/javax/sip/header/ContentLengthHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface ContentLengthHeader extends Header { + String NAME = "Content-Length"; + + int getContentLength(); + void setContentLength(int contentLength) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/ContentTypeHeader.java b/java/javax/sip/header/ContentTypeHeader.java new file mode 100644 index 0000000..78ea2dd --- /dev/null +++ b/java/javax/sip/header/ContentTypeHeader.java @@ -0,0 +1,11 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface ContentTypeHeader extends Header, MediaType, Parameters { + String NAME = "Content-Type"; + + String getCharset(); + void setContentType(String contentType, String contentSubType) + throws ParseException; +} diff --git a/java/javax/sip/header/DateHeader.java b/java/javax/sip/header/DateHeader.java new file mode 100644 index 0000000..6896ff6 --- /dev/null +++ b/java/javax/sip/header/DateHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.util.Calendar; + +public interface DateHeader extends Header { + String NAME = "Date"; + + Calendar getDate(); + void setDate(Calendar date); +} diff --git a/java/javax/sip/header/Encoding.java b/java/javax/sip/header/Encoding.java new file mode 100644 index 0000000..cb54886 --- /dev/null +++ b/java/javax/sip/header/Encoding.java @@ -0,0 +1,8 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface Encoding { + String getEncoding(); + void setEncoding(String encoding) throws ParseException; +} diff --git a/java/javax/sip/header/ErrorInfoHeader.java b/java/javax/sip/header/ErrorInfoHeader.java new file mode 100644 index 0000000..3e18bde --- /dev/null +++ b/java/javax/sip/header/ErrorInfoHeader.java @@ -0,0 +1,14 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.address.URI; + +public interface ErrorInfoHeader extends Header, Parameters { + String NAME = "Error-Info"; + + URI getErrorInfo(); + void setErrorInfo(URI errorInfo); + + String getErrorMessage(); + void setErrorMessage(String errorMessage) throws ParseException; +} diff --git a/java/javax/sip/header/EventHeader.java b/java/javax/sip/header/EventHeader.java new file mode 100644 index 0000000..d2c68bc --- /dev/null +++ b/java/javax/sip/header/EventHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface EventHeader extends Header, Parameters { + String NAME = "Event"; + + String getEventId(); + void setEventId(String eventId) throws ParseException; + + String getEventType(); + void setEventType(String eventType) throws ParseException; +} diff --git a/java/javax/sip/header/ExpiresHeader.java b/java/javax/sip/header/ExpiresHeader.java new file mode 100644 index 0000000..21d4b8b --- /dev/null +++ b/java/javax/sip/header/ExpiresHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface ExpiresHeader extends Header { + String NAME = "Expires"; + + int getExpires(); + void setExpires(int expires) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/ExtensionHeader.java b/java/javax/sip/header/ExtensionHeader.java new file mode 100644 index 0000000..8e6c0df --- /dev/null +++ b/java/javax/sip/header/ExtensionHeader.java @@ -0,0 +1,8 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface ExtensionHeader extends Header { + String getValue(); + void setValue(String value) throws ParseException; +} diff --git a/java/javax/sip/header/FromHeader.java b/java/javax/sip/header/FromHeader.java new file mode 100644 index 0000000..5117404 --- /dev/null +++ b/java/javax/sip/header/FromHeader.java @@ -0,0 +1,15 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface FromHeader extends HeaderAddress, Header, Parameters { + String NAME = "From"; + + String getTag(); + void setTag(String tag) throws ParseException; + boolean hasTag(); + void removeTag(); + + String getDisplayName(); + String getUserAtHostPort(); +} diff --git a/java/javax/sip/header/Header.java b/java/javax/sip/header/Header.java new file mode 100644 index 0000000..9571746 --- /dev/null +++ b/java/javax/sip/header/Header.java @@ -0,0 +1,12 @@ +package javax.sip.header; + +import java.io.Serializable; + +public interface Header extends Cloneable, Serializable { + String getName(); + + Object clone(); + boolean equals(Object obj); + int hashCode(); + String toString(); +} diff --git a/java/javax/sip/header/HeaderAddress.java b/java/javax/sip/header/HeaderAddress.java new file mode 100644 index 0000000..cc4d125 --- /dev/null +++ b/java/javax/sip/header/HeaderAddress.java @@ -0,0 +1,8 @@ +package javax.sip.header; + +import javax.sip.address.Address; + +public interface HeaderAddress { + Address getAddress(); + void setAddress(Address address); +} diff --git a/java/javax/sip/header/HeaderFactory.java b/java/javax/sip/header/HeaderFactory.java new file mode 100644 index 0000000..0458ba1 --- /dev/null +++ b/java/javax/sip/header/HeaderFactory.java @@ -0,0 +1,180 @@ +package javax.sip.header; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import javax.sip.InvalidArgumentException; +import javax.sip.address.Address; +import javax.sip.address.URI; + +public interface HeaderFactory { + void setPrettyEncoding(boolean flag); + + AcceptEncodingHeader createAcceptEncodingHeader(String encoding) + throws ParseException; + + AcceptHeader createAcceptHeader(String contentType, String contentSubType) + throws ParseException; + + AcceptLanguageHeader createAcceptLanguageHeader(Locale language); + + AlertInfoHeader createAlertInfoHeader(URI alertInfo); + + AllowEventsHeader createAllowEventsHeader(String eventType) + throws ParseException; + + AllowHeader createAllowHeader(String method) throws ParseException; + + AuthenticationInfoHeader createAuthenticationInfoHeader(String response) + throws ParseException; + + AuthorizationHeader createAuthorizationHeader(String scheme) + throws ParseException; + + CallIdHeader createCallIdHeader(String callId) throws ParseException; + + CallInfoHeader createCallInfoHeader(URI callInfo); + + ContactHeader createContactHeader(); + + ContactHeader createContactHeader(Address address); + + ContentDispositionHeader createContentDispositionHeader( + String contentDispositionType) throws ParseException; + + ContentEncodingHeader createContentEncodingHeader(String encoding) + throws ParseException; + + ContentLanguageHeader createContentLanguageHeader(Locale contentLanguage); + + ContentLengthHeader createContentLengthHeader(int contentLength) + throws InvalidArgumentException; + + ContentTypeHeader createContentTypeHeader(String contentType, + String contentSubType) throws ParseException; + + /** + * @deprecated + * @see #createCSeqHeader(long, String) + */ + CSeqHeader createCSeqHeader(int sequenceNumber, String method) + throws ParseException, InvalidArgumentException; + + CSeqHeader createCSeqHeader(long sequenceNumber, String method) + throws ParseException, InvalidArgumentException; + + DateHeader createDateHeader(Calendar date); + + ErrorInfoHeader createErrorInfoHeader(URI errorInfo); + + EventHeader createEventHeader(String eventType) throws ParseException; + + ExpiresHeader createExpiresHeader(int expires) + throws InvalidArgumentException; + + ExtensionHeader createExtensionHeader(String name, String value) + throws ParseException; + + FromHeader createFromHeader(Address address, String tag) + throws ParseException; + + Header createHeader(String name, String value) throws ParseException; + Header createHeader(String headerText) throws ParseException; + + List createHeaders(String headers) throws ParseException; + + InReplyToHeader createInReplyToHeader(String callId) throws ParseException; + + MaxForwardsHeader createMaxForwardsHeader(int maxForwards) + throws InvalidArgumentException; + + MimeVersionHeader createMimeVersionHeader(int majorVersion, + int minorVersion) throws InvalidArgumentException; + + MinExpiresHeader createMinExpiresHeader(int minExpires) + throws InvalidArgumentException; + + OrganizationHeader createOrganizationHeader(String organization) + throws ParseException; + + PriorityHeader createPriorityHeader(String priority) throws ParseException; + + ProxyAuthenticateHeader createProxyAuthenticateHeader(String scheme) + throws ParseException; + + ProxyAuthorizationHeader createProxyAuthorizationHeader(String scheme) + throws ParseException; + + ProxyRequireHeader createProxyRequireHeader(String optionTag) + throws ParseException; + + RAckHeader createRAckHeader(long rSeqNumber, long cSeqNumber, String method) + throws InvalidArgumentException, ParseException; + + /** + * @deprecated + * @see #createRAckHeader(long, long, String) + */ + RAckHeader createRAckHeader(int rSeqNumber, int cSeqNumber, String method) + throws InvalidArgumentException, ParseException; + + ReasonHeader createReasonHeader(String protocol, int cause, String text) + throws InvalidArgumentException, ParseException; + + RecordRouteHeader createRecordRouteHeader(Address address); + + ReferToHeader createReferToHeader(Address address); + + ReplyToHeader createReplyToHeader(Address address); + + RequireHeader createRequireHeader(String optionTag) throws ParseException; + + RetryAfterHeader createRetryAfterHeader(int retryAfter) + throws InvalidArgumentException; + + RouteHeader createRouteHeader(Address address); + + RSeqHeader createRSeqHeader(long sequenceNumber) + throws InvalidArgumentException; + + /** + * @deprecated + * @see #createRSeqHeader(long) + */ + RSeqHeader createRSeqHeader(int sequenceNumber) + throws InvalidArgumentException; + + ServerHeader createServerHeader(List product) throws ParseException; + + SIPETagHeader createSIPETagHeader(String etag) throws ParseException; + + SIPIfMatchHeader createSIPIfMatchHeader(String etag) throws ParseException; + + SubjectHeader createSubjectHeader(String subject) throws ParseException; + + SubscriptionStateHeader createSubscriptionStateHeader( + String subscriptionState) throws ParseException; + + SupportedHeader createSupportedHeader(String optionTag) + throws ParseException; + + TimeStampHeader createTimeStampHeader(float timeStamp) + throws InvalidArgumentException; + + ToHeader createToHeader(Address address, String tag) throws ParseException; + + UnsupportedHeader createUnsupportedHeader(String optionTag) + throws ParseException; + + UserAgentHeader createUserAgentHeader(List product) throws ParseException; + + ViaHeader createViaHeader(String host, int port, String transport, + String branch) throws InvalidArgumentException, ParseException; + + WarningHeader createWarningHeader(String agent, int code, String comment) + throws InvalidArgumentException, ParseException; + + WWWAuthenticateHeader createWWWAuthenticateHeader(String scheme) + throws ParseException; +} diff --git a/java/javax/sip/header/InReplyToHeader.java b/java/javax/sip/header/InReplyToHeader.java new file mode 100644 index 0000000..0da9d8a --- /dev/null +++ b/java/javax/sip/header/InReplyToHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface InReplyToHeader extends CallIdHeader { + String NAME = "In-Reply-To"; +} diff --git a/java/javax/sip/header/MaxForwardsHeader.java b/java/javax/sip/header/MaxForwardsHeader.java new file mode 100644 index 0000000..f6c9c63 --- /dev/null +++ b/java/javax/sip/header/MaxForwardsHeader.java @@ -0,0 +1,14 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface MaxForwardsHeader extends Header { + String NAME = "Max-Forwards"; + + void decrementMaxForwards() throws TooManyHopsException; + + int getMaxForwards(); + void setMaxForwards(int maxForwards) throws InvalidArgumentException; + + boolean hasReachedZero(); +} diff --git a/java/javax/sip/header/MediaType.java b/java/javax/sip/header/MediaType.java new file mode 100644 index 0000000..94c899e --- /dev/null +++ b/java/javax/sip/header/MediaType.java @@ -0,0 +1,11 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface MediaType { + String getContentSubType(); + void setContentSubType(String contentSubType) throws ParseException; + + String getContentType(); + void setContentType(String contentType) throws ParseException; +} diff --git a/java/javax/sip/header/MimeVersionHeader.java b/java/javax/sip/header/MimeVersionHeader.java new file mode 100644 index 0000000..7a54f8d --- /dev/null +++ b/java/javax/sip/header/MimeVersionHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface MimeVersionHeader extends Header { + String NAME = "MIME-Version"; + + int getMajorVersion(); + void setMajorVersion(int majorVersion) throws InvalidArgumentException; + + int getMinorVersion(); + void setMinorVersion(int minorVersion) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/MinExpiresHeader.java b/java/javax/sip/header/MinExpiresHeader.java new file mode 100644 index 0000000..7f83738 --- /dev/null +++ b/java/javax/sip/header/MinExpiresHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface MinExpiresHeader extends ExpiresHeader { + String NAME = "Min-Expires"; +} diff --git a/java/javax/sip/header/OptionTag.java b/java/javax/sip/header/OptionTag.java new file mode 100644 index 0000000..4d6b478 --- /dev/null +++ b/java/javax/sip/header/OptionTag.java @@ -0,0 +1,8 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface OptionTag { + String getOptionTag(); + void setOptionTag(String optionTag) throws ParseException; +} diff --git a/java/javax/sip/header/OrganizationHeader.java b/java/javax/sip/header/OrganizationHeader.java new file mode 100644 index 0000000..077cb93 --- /dev/null +++ b/java/javax/sip/header/OrganizationHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface OrganizationHeader extends Header { + String NAME = "Organization"; + + String getOrganization(); + void setOrganization(String organization) throws ParseException; +} diff --git a/java/javax/sip/header/Parameters.java b/java/javax/sip/header/Parameters.java new file mode 100644 index 0000000..2690b3c --- /dev/null +++ b/java/javax/sip/header/Parameters.java @@ -0,0 +1,12 @@ +package javax.sip.header; + +import java.text.ParseException; +import java.util.Iterator; + +public interface Parameters { + String getParameter(String name); + void setParameter(String name, String value) throws ParseException; + + Iterator getParameterNames(); + void removeParameter(String name); +} diff --git a/java/javax/sip/header/PriorityHeader.java b/java/javax/sip/header/PriorityHeader.java new file mode 100644 index 0000000..72a0737 --- /dev/null +++ b/java/javax/sip/header/PriorityHeader.java @@ -0,0 +1,15 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface PriorityHeader extends Header { + String NAME = "Priority"; + + String NON_URGENT = "Non-Urgent"; + String NORMAL = "Normal"; + String URGENT = "Urgent"; + String EMERGENCY = "Emergency"; + + String getPriority(); + void setPriority(String priority) throws ParseException; +} diff --git a/java/javax/sip/header/ProxyAuthenticateHeader.java b/java/javax/sip/header/ProxyAuthenticateHeader.java new file mode 100644 index 0000000..fa5feef --- /dev/null +++ b/java/javax/sip/header/ProxyAuthenticateHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface ProxyAuthenticateHeader extends WWWAuthenticateHeader { + String NAME = "Proxy-Authenticate"; +} diff --git a/java/javax/sip/header/ProxyAuthorizationHeader.java b/java/javax/sip/header/ProxyAuthorizationHeader.java new file mode 100644 index 0000000..d0dca8c --- /dev/null +++ b/java/javax/sip/header/ProxyAuthorizationHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface ProxyAuthorizationHeader extends AuthorizationHeader { + String NAME = "Proxy-Authorization"; +} diff --git a/java/javax/sip/header/ProxyRequireHeader.java b/java/javax/sip/header/ProxyRequireHeader.java new file mode 100644 index 0000000..19072d3 --- /dev/null +++ b/java/javax/sip/header/ProxyRequireHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface ProxyRequireHeader extends RequireHeader { + String NAME = "Proxy-Require"; +} diff --git a/java/javax/sip/header/RAckHeader.java b/java/javax/sip/header/RAckHeader.java new file mode 100644 index 0000000..52060c6 --- /dev/null +++ b/java/javax/sip/header/RAckHeader.java @@ -0,0 +1,39 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface RAckHeader extends Header { + String NAME = "RAck"; + + String getMethod(); + void setMethod(String method) throws ParseException; + + long getCSequenceNumber(); + void setCSequenceNumber(long cSequenceNumber) throws InvalidArgumentException; + + long getRSequenceNumber(); + void setRSequenceNumber(long rSequenceNumber) throws InvalidArgumentException; + + /** + * @deprecated + * @see #getCSequenceNumber() + */ + int getCSeqNumber(); + /** + * @deprecated + * @see #setCSequenceNumber(long) + */ + void setCSeqNumber(int cSeqNumber) throws InvalidArgumentException; + + /** + * @deprecated + * @see #getRSequenceNumber() + */ + int getRSeqNumber(); + /** + * @deprecated + * @see #setRSequenceNumber(long) + */ + void setRSeqNumber(int rSeqNumber) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/RSeqHeader.java b/java/javax/sip/header/RSeqHeader.java new file mode 100644 index 0000000..22c1c3d --- /dev/null +++ b/java/javax/sip/header/RSeqHeader.java @@ -0,0 +1,22 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface RSeqHeader extends Header { + String NAME = "RSeq"; + + long getSeqNumber(); + void setSeqNumber(long sequenceNumber) throws InvalidArgumentException; + + /** + * @deprecated + * @see #getSeqNumber() + */ + int getSequenceNumber(); + + /** + * @deprecated + * @see #setSeqNumber(long) + */ + void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/ReasonHeader.java b/java/javax/sip/header/ReasonHeader.java new file mode 100644 index 0000000..21c4b72 --- /dev/null +++ b/java/javax/sip/header/ReasonHeader.java @@ -0,0 +1,17 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface ReasonHeader extends Header, Parameters { + String NAME = "Reason"; + + int getCause(); + void setCause(int cause) throws InvalidArgumentException; + + String getProtocol(); + void setProtocol(String protocol) throws ParseException; + + String getText(); + void setText(String text) throws ParseException; +} diff --git a/java/javax/sip/header/RecordRouteHeader.java b/java/javax/sip/header/RecordRouteHeader.java new file mode 100644 index 0000000..a510309 --- /dev/null +++ b/java/javax/sip/header/RecordRouteHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface RecordRouteHeader extends HeaderAddress, Header, Parameters { + String NAME = "Record-Route"; +} diff --git a/java/javax/sip/header/ReferToHeader.java b/java/javax/sip/header/ReferToHeader.java new file mode 100644 index 0000000..5dec530 --- /dev/null +++ b/java/javax/sip/header/ReferToHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface ReferToHeader extends HeaderAddress, Header, Parameters { + String NAME = "Refer-To"; +} diff --git a/java/javax/sip/header/ReplyToHeader.java b/java/javax/sip/header/ReplyToHeader.java new file mode 100644 index 0000000..599b3dd --- /dev/null +++ b/java/javax/sip/header/ReplyToHeader.java @@ -0,0 +1,7 @@ +package javax.sip.header; + +public interface ReplyToHeader extends HeaderAddress, Header, Parameters { + String NAME = "Reply-To"; + + String getDisplayName(); +} diff --git a/java/javax/sip/header/RequireHeader.java b/java/javax/sip/header/RequireHeader.java new file mode 100644 index 0000000..f3ea02a --- /dev/null +++ b/java/javax/sip/header/RequireHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface RequireHeader extends OptionTag, Header { + String NAME = "Require"; +} diff --git a/java/javax/sip/header/RetryAfterHeader.java b/java/javax/sip/header/RetryAfterHeader.java new file mode 100644 index 0000000..14f369a --- /dev/null +++ b/java/javax/sip/header/RetryAfterHeader.java @@ -0,0 +1,20 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface RetryAfterHeader extends Header, Parameters { + String NAME = "Retry-After"; + + String getComment(); + void setComment(String comment) throws ParseException; + boolean hasComment(); + void removeComment(); + + int getDuration(); + void setDuration(int duration) throws InvalidArgumentException; + void removeDuration(); + + int getRetryAfter(); + void setRetryAfter(int retryAfter) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/RouteHeader.java b/java/javax/sip/header/RouteHeader.java new file mode 100644 index 0000000..5b603c4 --- /dev/null +++ b/java/javax/sip/header/RouteHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface RouteHeader extends HeaderAddress, Header, Parameters { + String NAME = "Route"; +} diff --git a/java/javax/sip/header/SIPETagHeader.java b/java/javax/sip/header/SIPETagHeader.java new file mode 100644 index 0000000..c882dcb --- /dev/null +++ b/java/javax/sip/header/SIPETagHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface SIPETagHeader extends ExtensionHeader { + String NAME = "SIP-ETag"; + + String getETag(); + void setETag(String etag) throws ParseException; +} diff --git a/java/javax/sip/header/SIPIfMatchHeader.java b/java/javax/sip/header/SIPIfMatchHeader.java new file mode 100644 index 0000000..dcae8f5 --- /dev/null +++ b/java/javax/sip/header/SIPIfMatchHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface SIPIfMatchHeader extends SIPETagHeader { + String NAME = "SIP-If-Match"; +} diff --git a/java/javax/sip/header/ServerHeader.java b/java/javax/sip/header/ServerHeader.java new file mode 100644 index 0000000..2ffd6f3 --- /dev/null +++ b/java/javax/sip/header/ServerHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import java.text.ParseException; +import java.util.List; +import java.util.ListIterator; + +public interface ServerHeader extends Header { + String NAME = "Server"; + + ListIterator getProduct(); + void setProduct(List product) throws ParseException; + void addProductToken(String productToken); +} diff --git a/java/javax/sip/header/SubjectHeader.java b/java/javax/sip/header/SubjectHeader.java new file mode 100644 index 0000000..839f65d --- /dev/null +++ b/java/javax/sip/header/SubjectHeader.java @@ -0,0 +1,10 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface SubjectHeader extends Header { + String NAME = "Subject"; + + String getSubject(); + void setSubject(String subject) throws ParseException; +} diff --git a/java/javax/sip/header/SubscriptionStateHeader.java b/java/javax/sip/header/SubscriptionStateHeader.java new file mode 100644 index 0000000..3efdbe0 --- /dev/null +++ b/java/javax/sip/header/SubscriptionStateHeader.java @@ -0,0 +1,29 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface SubscriptionStateHeader extends ExpiresHeader, Parameters { + String NAME = "Subscription-State"; + + String DEACTIVATED = "Deactivated"; + String GIVE_UP = "Give-Up"; + String NO_RESOURCE = "No-Resource"; + String PROBATION = "Probation"; + String REJECTED = "Rejected"; + String TIMEOUT = "Timeout"; + String UNKNOWN = "Unknown"; + + String ACTIVE = "Active"; + String PENDING = "Pending"; + String TERMINATED = "Terminated"; + + String getReasonCode(); + void setReasonCode(String reasonCode) throws ParseException; + + int getRetryAfter(); + void setRetryAfter(int retryAfter) throws InvalidArgumentException; + + String getState(); + void setState(String state) throws ParseException; +} diff --git a/java/javax/sip/header/SupportedHeader.java b/java/javax/sip/header/SupportedHeader.java new file mode 100644 index 0000000..0ec466f --- /dev/null +++ b/java/javax/sip/header/SupportedHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface SupportedHeader extends OptionTag, Header { + String NAME = "Supported"; +} diff --git a/java/javax/sip/header/TimeStampHeader.java b/java/javax/sip/header/TimeStampHeader.java new file mode 100644 index 0000000..e07af14 --- /dev/null +++ b/java/javax/sip/header/TimeStampHeader.java @@ -0,0 +1,21 @@ +package javax.sip.header; + +import javax.sip.InvalidArgumentException; + +public interface TimeStampHeader extends Header { + String NAME = "Timestamp"; + + float getDelay(); + void setDelay(float delay) throws InvalidArgumentException; + boolean hasDelay(); + void removeDelay(); + + long getTime(); + void setTime(long timeStamp) throws InvalidArgumentException; + + int getTimeDelay(); + void setTimeDelay(int delay) throws InvalidArgumentException; + + float getTimeStamp(); + void setTimeStamp(float timeStamp) throws InvalidArgumentException; +} diff --git a/java/javax/sip/header/ToHeader.java b/java/javax/sip/header/ToHeader.java new file mode 100644 index 0000000..46b846c --- /dev/null +++ b/java/javax/sip/header/ToHeader.java @@ -0,0 +1,15 @@ +package javax.sip.header; + +import java.text.ParseException; + +public interface ToHeader extends HeaderAddress, Header, Parameters { + String NAME = "To"; + + String getTag(); + void setTag(String tag) throws ParseException; + boolean hasTag(); + void removeTag(); + + String getDisplayName(); + String getUserAtHostPort(); +} diff --git a/java/javax/sip/header/TooManyHopsException.java b/java/javax/sip/header/TooManyHopsException.java new file mode 100644 index 0000000..14b21f2 --- /dev/null +++ b/java/javax/sip/header/TooManyHopsException.java @@ -0,0 +1,16 @@ +package javax.sip.header; + +public class TooManyHopsException extends Exception { + public TooManyHopsException(){ + super(); + } + + public TooManyHopsException(String message) { + super(message); + } + + public TooManyHopsException(String message, Throwable cause) { + super(message, cause); + } +} + diff --git a/java/javax/sip/header/UnsupportedHeader.java b/java/javax/sip/header/UnsupportedHeader.java new file mode 100644 index 0000000..cf18e4e --- /dev/null +++ b/java/javax/sip/header/UnsupportedHeader.java @@ -0,0 +1,5 @@ +package javax.sip.header; + +public interface UnsupportedHeader extends OptionTag, Header { + String NAME = "Unsupported"; +} diff --git a/java/javax/sip/header/UserAgentHeader.java b/java/javax/sip/header/UserAgentHeader.java new file mode 100644 index 0000000..aa0c211 --- /dev/null +++ b/java/javax/sip/header/UserAgentHeader.java @@ -0,0 +1,13 @@ +package javax.sip.header; + +import java.text.ParseException; +import java.util.List; +import java.util.ListIterator; + +public interface UserAgentHeader extends Header { + String NAME = "User-Agent"; + + ListIterator getProduct(); + void setProduct(List product) throws ParseException; + void addProductToken(String productToken); +} diff --git a/java/javax/sip/header/ViaHeader.java b/java/javax/sip/header/ViaHeader.java new file mode 100644 index 0000000..37ba138 --- /dev/null +++ b/java/javax/sip/header/ViaHeader.java @@ -0,0 +1,38 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface ViaHeader extends Header, Parameters { + String NAME = "Via"; + + String getBranch(); + void setBranch(String branch) throws ParseException; + + String getHost(); + void setHost(String host) throws ParseException; + + String getMAddr(); + void setMAddr(String mAddr) throws ParseException; + + int getPort(); + void setPort(int port) throws InvalidArgumentException; + + String getProtocol(); + void setProtocol(String protocol) throws ParseException; + + String getReceived(); + void setReceived(String received) throws ParseException; + + int getRPort(); + void setRPort() throws InvalidArgumentException; + + String getTransport(); + void setTransport(String transport) throws ParseException; + + int getTTL(); + void setTTL(int ttl) throws InvalidArgumentException; + + String getSentByField(); + String getSentProtocolField(); +} diff --git a/java/javax/sip/header/WWWAuthenticateHeader.java b/java/javax/sip/header/WWWAuthenticateHeader.java new file mode 100644 index 0000000..9e5c5f3 --- /dev/null +++ b/java/javax/sip/header/WWWAuthenticateHeader.java @@ -0,0 +1,17 @@ +package javax.sip.header; + +import javax.sip.address.URI; + +public interface WWWAuthenticateHeader extends AuthorizationHeader { + String NAME = "WWW-Authenticate"; + + /** + * @deprecated This method should return null. + */ + URI getURI(); + + /** + * @deprecated This method should return immediately. + */ + void setURI(URI uri); +} diff --git a/java/javax/sip/header/WarningHeader.java b/java/javax/sip/header/WarningHeader.java new file mode 100644 index 0000000..e9e37f7 --- /dev/null +++ b/java/javax/sip/header/WarningHeader.java @@ -0,0 +1,30 @@ +package javax.sip.header; + +import java.text.ParseException; +import javax.sip.InvalidArgumentException; + +public interface WarningHeader extends Header { + String NAME = "Warning"; + + int ATTRIBUTE_NOT_UNDERSTOOD = 10; + int INCOMPATIBLE_BANDWIDTH_UNITS = 20; + int INCOMPATIBLE_MEDIA_FORMAT = 21; + int INCOMPATIBLE_NETWORK_ADDRESS_FORMATS = 22; + int INCOMPATIBLE_NETWORK_PROTOCOL = 23; + int INCOMPATIBLE_TRANSPORT_PROTOCOL = 24; + int INSUFFICIENT_BANDWIDTH = 30; + int MEDIA_TYPE_NOT_AVAILABLE = 40; + int MISCELLANEOUS_WARNING = 99; + int MULTICAST_NOT_AVAILABLE = 50; + int SESSION_DESCRIPTION_PARAMETER_NOT_UNDERSTOOD = 60; + int UNICAST_NOT_AVAILABLE = 51; + + String getAgent(); + void setAgent(String agent) throws ParseException; + + int getCode(); + void setCode(int code) throws InvalidArgumentException; + + String getText(); + void setText(String text) throws ParseException; +} diff --git a/java/javax/sip/message/Message.java b/java/javax/sip/message/Message.java new file mode 100644 index 0000000..c18ab7d --- /dev/null +++ b/java/javax/sip/message/Message.java @@ -0,0 +1,63 @@ +package javax.sip.message; + +import java.io.Serializable; +import java.text.ParseException; +import java.util.ListIterator; +import javax.sip.SipException; +import javax.sip.header.ContentDispositionHeader; +import javax.sip.header.ContentEncodingHeader; +import javax.sip.header.ContentLanguageHeader; +import javax.sip.header.ContentLengthHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.ExpiresHeader; +import javax.sip.header.Header; + +public interface Message extends Cloneable, Serializable { + void addFirst(Header header) throws SipException, NullPointerException; + void addHeader(Header header); + void addLast(Header header) throws SipException, NullPointerException; + + Header getHeader(String headerName); + void setHeader(Header header); + + void removeFirst(String headerName) throws NullPointerException; + void removeLast(String headerName) throws NullPointerException; + void removeHeader(String headerName); + + ListIterator getHeaderNames(); + ListIterator getHeaders(String headerName); + ListIterator getUnrecognizedHeaders(); + + Object getApplicationData(); + void setApplicationData(Object applicationData); + + ContentLengthHeader getContentLength(); + void setContentLength(ContentLengthHeader contentLength); + + ContentLanguageHeader getContentLanguage(); + void setContentLanguage(ContentLanguageHeader contentLanguage); + + ContentEncodingHeader getContentEncoding(); + void setContentEncoding(ContentEncodingHeader contentEncoding); + + ContentDispositionHeader getContentDisposition(); + void setContentDisposition(ContentDispositionHeader contentDisposition); + + Object getContent(); + byte[] getRawContent(); + void setContent(Object content, ContentTypeHeader contentTypeHeader) + throws ParseException; + void removeContent(); + + + ExpiresHeader getExpires(); + void setExpires(ExpiresHeader expires); + + String getSIPVersion(); + void setSIPVersion(String version) throws ParseException; + + Object clone(); + boolean equals(Object object); + int hashCode(); + String toString(); +} diff --git a/java/javax/sip/message/MessageFactory.java b/java/javax/sip/message/MessageFactory.java new file mode 100644 index 0000000..be8f5ec --- /dev/null +++ b/java/javax/sip/message/MessageFactory.java @@ -0,0 +1,64 @@ +package javax.sip.message; + +import java.text.ParseException; +import java.util.List; +import javax.sip.address.URI; +import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.header.ContentTypeHeader; +import javax.sip.header.FromHeader; +import javax.sip.header.MaxForwardsHeader; +import javax.sip.header.ServerHeader; +import javax.sip.header.ToHeader; +import javax.sip.header.UserAgentHeader; + +public interface MessageFactory { + Request createRequest(URI requestURI, String method, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + Object content) throws ParseException; + + Request createRequest(URI requestURI, String method, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + byte[] content) throws ParseException; + + Request createRequest(URI requestURI, String method, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards) throws ParseException; + + Request createRequest(String request) throws ParseException; + + Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + Object content) throws ParseException; + + Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards, ContentTypeHeader contentType, + byte[] content) throws ParseException; + + Response createResponse(int statusCode, CallIdHeader callId, + CSeqHeader cSeq, FromHeader from, ToHeader to, List via, + MaxForwardsHeader maxForwards) throws ParseException; + + Response createResponse(int statusCode, Request request, + ContentTypeHeader contentType, Object content) + throws ParseException; + + Response createResponse(int statusCode, Request request, + ContentTypeHeader contentType, byte[] content) + throws ParseException; + + Response createResponse(int statusCode, Request request) + throws ParseException; + + Response createResponse(String response) throws ParseException; + + void setDefaultContentEncodingCharset(String defaultContentEncodingCharset) + throws NullPointerException, IllegalArgumentException; + void setDefaultServerHeader(ServerHeader defaultServerHeader); + void setDefaultUserAgentHeader(UserAgentHeader defaultUserAgentHeader); +} + diff --git a/java/javax/sip/message/Request.java b/java/javax/sip/message/Request.java new file mode 100644 index 0000000..5b3a35d --- /dev/null +++ b/java/javax/sip/message/Request.java @@ -0,0 +1,29 @@ +package javax.sip.message; + +import java.text.ParseException; +import javax.sip.address.URI; + +public interface Request extends Message { + String ACK = "ACK"; + String BYE = "BYE"; + String CANCEL = "CANCEL"; + String INVITE = "INVITE"; + String OPTIONS = "OPTIONS"; + String REGISTER = "REGISTER"; + + String INFO = "INFO"; + String MESSAGE = "MESSAGE"; + String NOTIFY = "NOTIFY"; + String PRACK = "PRACK"; + String PUBLISH = "PUBLISH"; + String REFER = "REFER"; + String SUBSCRIBE = "SUBSCRIBE"; + String UPDATE = "UPDATE"; + + String getMethod(); + void setMethod(String method) throws ParseException; + + URI getRequestURI(); + void setRequestURI(URI requestURI); +} + diff --git a/java/javax/sip/message/Response.java b/java/javax/sip/message/Response.java new file mode 100644 index 0000000..5743f8e --- /dev/null +++ b/java/javax/sip/message/Response.java @@ -0,0 +1,65 @@ +package javax.sip.message; + +import java.text.ParseException; + +public interface Response extends Message { + int TRYING = 100; + int RINGING = 180; + int CALL_IS_BEING_FORWARDED = 181; + int QUEUED = 182; + int SESSION_PROGRESS = 183; + int OK = 200; + int ACCEPTED = 202; + int MULTIPLE_CHOICES = 300; + int MOVED_PERMANENTLY = 301; + int MOVED_TEMPORARILY = 302; + int USE_PROXY = 305; + int ALTERNATIVE_SERVICE = 380; + int BAD_REQUEST = 400; + int UNAUTHORIZED = 401; + int PAYMENT_REQUIRED = 402; + int FORBIDDEN = 403; + int NOT_FOUND = 404; + int METHOD_NOT_ALLOWED = 405; + int NOT_ACCEPTABLE = 406; + int PROXY_AUTHENTICATION_REQUIRED = 407; + int REQUEST_TIMEOUT = 408; + int GONE = 410; + int CONDITIONAL_REQUEST_FAILED = 412; + int REQUEST_ENTITY_TOO_LARGE = 413; + int REQUEST_URI_TOO_LONG = 414; + int UNSUPPORTED_MEDIA_TYPE = 415; + int UNSUPPORTED_URI_SCHEME = 416; + int BAD_EXTENSION = 420; + int EXTENSION_REQUIRED = 421; + int INTERVAL_TOO_BRIEF = 423; + int TEMPORARILY_UNAVAILABLE = 480; + int CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481; + int LOOP_DETECTED = 482; + int TOO_MANY_HOPS = 483; + int ADDRESS_INCOMPLETE = 484; + int AMBIGUOUS = 485; + int BUSY_HERE = 486; + int REQUEST_TERMINATED = 487; + int NOT_ACCEPTABLE_HERE = 488; + int BAD_EVENT = 489; + int REQUEST_PENDING = 491; + int UNDECIPHERABLE = 493; + int SERVER_INTERNAL_ERROR = 500; + int NOT_IMPLEMENTED = 501; + int BAD_GATEWAY = 502; + int SERVICE_UNAVAILABLE = 503; + int SERVER_TIMEOUT = 504; + int VERSION_NOT_SUPPORTED = 505; + int MESSAGE_TOO_LARGE = 513; + int BUSY_EVERYWHERE = 600; + int DECLINE = 603; + int DOES_NOT_EXIST_ANYWHERE = 604; + int SESSION_NOT_ACCEPTABLE = 606; + + int getStatusCode(); + void setStatusCode(int statusCode) throws ParseException; + + String getReasonPhrase(); + void setReasonPhrase(String reasonPhrase) throws ParseException; +} diff --git a/licenses/README.txt b/licenses/README.txt new file mode 100644 index 0000000..143a6f2 --- /dev/null +++ b/licenses/README.txt @@ -0,0 +1,8 @@ + +NIST-CONDITIONS-OF-USE.txt +-------------------------- + +Applies to the classes under the hierarchy "gov.nist" and under the "tools" +and "test" hierarchy. + + diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..c2807f7 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +140
\ No newline at end of file |