summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2010-11-30 16:47:27 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2010-11-30 16:47:27 -0800
commitf35a2ce023b55701ae9ffde56082faa91647e624 (patch)
tree191104b8f7d19486b39bc16fdf98890679fbf435
downloadandroid_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.tar.gz
android_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.tar.bz2
android_external_nist-sip-f35a2ce023b55701ae9ffde56082faa91647e624.zip
snapshot
Change-Id: I430fbda80eb4d33b1af1180e2e86de3a6167ebb4
-rw-r--r--AndroidManifest.xml30
-rw-r--r--CleanSpec.mk49
-rw-r--r--NIST-CONDITIONS-OF-USE.txt27
-rw-r--r--TIMESTAMP1
-rw-r--r--java/gov/nist/core/Debug.java62
-rw-r--r--java/gov/nist/core/DuplicateNameValueList.java261
-rw-r--r--java/gov/nist/core/GenericObject.java712
-rw-r--r--java/gov/nist/core/GenericObjectList.java473
-rw-r--r--java/gov/nist/core/Host.java300
-rw-r--r--java/gov/nist/core/HostNameParser.java342
-rw-r--r--java/gov/nist/core/HostPort.java171
-rw-r--r--java/gov/nist/core/InternalErrorHandler.java78
-rw-r--r--java/gov/nist/core/LexerCore.java761
-rw-r--r--java/gov/nist/core/LogLevels.java18
-rw-r--r--java/gov/nist/core/LogWriter.java593
-rw-r--r--java/gov/nist/core/Match.java46
-rw-r--r--java/gov/nist/core/MultiMap.java37
-rw-r--r--java/gov/nist/core/MultiValueMap.java9
-rw-r--r--java/gov/nist/core/MultiValueMapImpl.java154
-rw-r--r--java/gov/nist/core/NameValue.java285
-rw-r--r--java/gov/nist/core/NameValueList.java354
-rw-r--r--java/gov/nist/core/PackageNames.java59
-rw-r--r--java/gov/nist/core/ParserCore.java142
-rw-r--r--java/gov/nist/core/Separators.java60
-rw-r--r--java/gov/nist/core/ServerLogger.java49
-rw-r--r--java/gov/nist/core/StackLogger.java130
-rw-r--r--java/gov/nist/core/StringTokenizer.java204
-rw-r--r--java/gov/nist/core/ThreadAuditor.java193
-rw-r--r--java/gov/nist/core/Token.java49
-rw-r--r--java/gov/nist/core/net/AddressResolver.java67
-rw-r--r--java/gov/nist/core/net/DefaultNetworkLayer.java159
-rw-r--r--java/gov/nist/core/net/NetworkLayer.java153
-rw-r--r--java/gov/nist/core/net/SslNetworkLayer.java168
-rw-r--r--java/gov/nist/core/net/package.html6
-rw-r--r--java/gov/nist/core/package.html6
-rw-r--r--java/gov/nist/javax/sip/ClientTransactionExt.java55
-rw-r--r--java/gov/nist/javax/sip/DefaultAddressResolver.java74
-rw-r--r--java/gov/nist/javax/sip/DialogExt.java55
-rw-r--r--java/gov/nist/javax/sip/DialogFilter.java1437
-rw-r--r--java/gov/nist/javax/sip/DialogTimeoutEvent.java74
-rw-r--r--java/gov/nist/javax/sip/EventScanner.java529
-rw-r--r--java/gov/nist/javax/sip/EventWrapper.java44
-rw-r--r--java/gov/nist/javax/sip/ListeningPointExt.java41
-rw-r--r--java/gov/nist/javax/sip/ListeningPointImpl.java263
-rw-r--r--java/gov/nist/javax/sip/LogRecord.java20
-rw-r--r--java/gov/nist/javax/sip/LogRecordFactory.java37
-rw-r--r--java/gov/nist/javax/sip/NistSipMessageFactoryImpl.java147
-rw-r--r--java/gov/nist/javax/sip/ResponseEventExt.java50
-rw-r--r--java/gov/nist/javax/sip/SIPConstants.java63
-rw-r--r--java/gov/nist/javax/sip/ServerTransactionExt.java15
-rw-r--r--java/gov/nist/javax/sip/SipListenerExt.java49
-rw-r--r--java/gov/nist/javax/sip/SipProviderExt.java40
-rw-r--r--java/gov/nist/javax/sip/SipProviderImpl.java1116
-rw-r--r--java/gov/nist/javax/sip/SipStackExt.java146
-rw-r--r--java/gov/nist/javax/sip/SipStackImpl.java1496
-rw-r--r--java/gov/nist/javax/sip/TransactionExt.java69
-rw-r--r--java/gov/nist/javax/sip/Utils.java208
-rw-r--r--java/gov/nist/javax/sip/UtilsExt.java55
-rw-r--r--java/gov/nist/javax/sip/address/AddressFactoryImpl.java228
-rw-r--r--java/gov/nist/javax/sip/address/AddressImpl.java346
-rw-r--r--java/gov/nist/javax/sip/address/Authority.java236
-rw-r--r--java/gov/nist/javax/sip/address/GenericURI.java134
-rw-r--r--java/gov/nist/javax/sip/address/NetObject.java396
-rw-r--r--java/gov/nist/javax/sip/address/NetObjectList.java152
-rw-r--r--java/gov/nist/javax/sip/address/ParameterNames.java118
-rw-r--r--java/gov/nist/javax/sip/address/RFC2396UrlDecoder.java91
-rw-r--r--java/gov/nist/javax/sip/address/RouterExt.java42
-rw-r--r--java/gov/nist/javax/sip/address/SipURIExt.java47
-rw-r--r--java/gov/nist/javax/sip/address/SipUri.java1058
-rw-r--r--java/gov/nist/javax/sip/address/TelURLImpl.java222
-rw-r--r--java/gov/nist/javax/sip/address/TelephoneNumber.java248
-rw-r--r--java/gov/nist/javax/sip/address/UserInfo.java183
-rw-r--r--java/gov/nist/javax/sip/address/package.html4
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/AccountManager.java20
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/AuthenticationHelper.java75
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java464
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/CredentialsCache.java119
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/MessageDigestAlgorithm.java225
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/SecureAccountManager.java19
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/UserCredentialHash.java36
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/UserCredentials.java41
-rw-r--r--java/gov/nist/javax/sip/clientauthutils/package.html10
-rw-r--r--java/gov/nist/javax/sip/header/Accept.java201
-rw-r--r--java/gov/nist/javax/sip/header/AcceptEncoding.java153
-rw-r--r--java/gov/nist/javax/sip/header/AcceptEncodingList.java55
-rw-r--r--java/gov/nist/javax/sip/header/AcceptLanguage.java197
-rw-r--r--java/gov/nist/javax/sip/header/AcceptLanguageList.java71
-rw-r--r--java/gov/nist/javax/sip/header/AcceptList.java61
-rw-r--r--java/gov/nist/javax/sip/header/AddressParameters.java30
-rw-r--r--java/gov/nist/javax/sip/header/AddressParametersHeader.java106
-rw-r--r--java/gov/nist/javax/sip/header/AlertInfo.java128
-rw-r--r--java/gov/nist/javax/sip/header/AlertInfoList.java59
-rw-r--r--java/gov/nist/javax/sip/header/Allow.java90
-rw-r--r--java/gov/nist/javax/sip/header/AllowEvents.java100
-rw-r--r--java/gov/nist/javax/sip/header/AllowEventsList.java111
-rw-r--r--java/gov/nist/javax/sip/header/AllowList.java113
-rw-r--r--java/gov/nist/javax/sip/header/AuthenticationHeader.java553
-rw-r--r--java/gov/nist/javax/sip/header/AuthenticationInfo.java235
-rw-r--r--java/gov/nist/javax/sip/header/AuthenticationInfoList.java56
-rw-r--r--java/gov/nist/javax/sip/header/Authorization.java60
-rw-r--r--java/gov/nist/javax/sip/header/AuthorizationList.java62
-rw-r--r--java/gov/nist/javax/sip/header/CSeq.java184
-rw-r--r--java/gov/nist/javax/sip/header/CallID.java147
-rw-r--r--java/gov/nist/javax/sip/header/CallIdentifier.java183
-rw-r--r--java/gov/nist/javax/sip/header/CallInfo.java123
-rw-r--r--java/gov/nist/javax/sip/header/CallInfoList.java59
-rw-r--r--java/gov/nist/javax/sip/header/Challenge.java257
-rw-r--r--java/gov/nist/javax/sip/header/Contact.java293
-rw-r--r--java/gov/nist/javax/sip/header/ContactList.java62
-rw-r--r--java/gov/nist/javax/sip/header/ContentDisposition.java187
-rw-r--r--java/gov/nist/javax/sip/header/ContentEncoding.java135
-rw-r--r--java/gov/nist/javax/sip/header/ContentEncodingList.java56
-rw-r--r--java/gov/nist/javax/sip/header/ContentLanguage.java170
-rw-r--r--java/gov/nist/javax/sip/header/ContentLanguageList.java54
-rw-r--r--java/gov/nist/javax/sip/header/ContentLength.java157
-rw-r--r--java/gov/nist/javax/sip/header/ContentType.java222
-rw-r--r--java/gov/nist/javax/sip/header/Credentials.java135
-rw-r--r--java/gov/nist/javax/sip/header/ErrorInfo.java140
-rw-r--r--java/gov/nist/javax/sip/header/ErrorInfoList.java73
-rw-r--r--java/gov/nist/javax/sip/header/Event.java145
-rw-r--r--java/gov/nist/javax/sip/header/Expires.java105
-rw-r--r--java/gov/nist/javax/sip/header/ExtensionHeaderImpl.java123
-rw-r--r--java/gov/nist/javax/sip/header/ExtensionHeaderList.java71
-rw-r--r--java/gov/nist/javax/sip/header/From.java164
-rw-r--r--java/gov/nist/javax/sip/header/HeaderExt.java36
-rw-r--r--java/gov/nist/javax/sip/header/HeaderFactoryExt.java277
-rw-r--r--java/gov/nist/javax/sip/header/HeaderFactoryImpl.java1706
-rw-r--r--java/gov/nist/javax/sip/header/InReplyTo.java110
-rw-r--r--java/gov/nist/javax/sip/header/InReplyToList.java60
-rw-r--r--java/gov/nist/javax/sip/header/Indentation.java103
-rw-r--r--java/gov/nist/javax/sip/header/MaxForwards.java118
-rw-r--r--java/gov/nist/javax/sip/header/MediaRange.java117
-rw-r--r--java/gov/nist/javax/sip/header/MimeVersion.java201
-rw-r--r--java/gov/nist/javax/sip/header/MinExpires.java171
-rw-r--r--java/gov/nist/javax/sip/header/NameMap.java210
-rw-r--r--java/gov/nist/javax/sip/header/Organization.java156
-rw-r--r--java/gov/nist/javax/sip/header/ParameterNames.java159
-rw-r--r--java/gov/nist/javax/sip/header/ParametersHeader.java616
-rw-r--r--java/gov/nist/javax/sip/header/Priority.java102
-rw-r--r--java/gov/nist/javax/sip/header/Protocol.java221
-rw-r--r--java/gov/nist/javax/sip/header/ProxyAuthenticate.java148
-rw-r--r--java/gov/nist/javax/sip/header/ProxyAuthenticateList.java61
-rw-r--r--java/gov/nist/javax/sip/header/ProxyAuthorization.java123
-rw-r--r--java/gov/nist/javax/sip/header/ProxyAuthorizationList.java60
-rw-r--r--java/gov/nist/javax/sip/header/ProxyRequire.java165
-rw-r--r--java/gov/nist/javax/sip/header/ProxyRequireList.java62
-rw-r--r--java/gov/nist/javax/sip/header/RAck.java156
-rw-r--r--java/gov/nist/javax/sip/header/RSeq.java90
-rw-r--r--java/gov/nist/javax/sip/header/Reason.java247
-rw-r--r--java/gov/nist/javax/sip/header/ReasonList.java60
-rw-r--r--java/gov/nist/javax/sip/header/RecordRoute.java92
-rw-r--r--java/gov/nist/javax/sip/header/RecordRouteList.java55
-rw-r--r--java/gov/nist/javax/sip/header/ReferTo.java146
-rw-r--r--java/gov/nist/javax/sip/header/ReplyTo.java177
-rw-r--r--java/gov/nist/javax/sip/header/RequestLine.java289
-rw-r--r--java/gov/nist/javax/sip/header/Require.java165
-rw-r--r--java/gov/nist/javax/sip/header/RequireList.java63
-rw-r--r--java/gov/nist/javax/sip/header/RetryAfter.java191
-rw-r--r--java/gov/nist/javax/sip/header/Route.java111
-rw-r--r--java/gov/nist/javax/sip/header/RouteList.java89
-rw-r--r--java/gov/nist/javax/sip/header/SIPDate.java612
-rw-r--r--java/gov/nist/javax/sip/header/SIPDateHeader.java171
-rw-r--r--java/gov/nist/javax/sip/header/SIPETag.java101
-rw-r--r--java/gov/nist/javax/sip/header/SIPHeader.java157
-rw-r--r--java/gov/nist/javax/sip/header/SIPHeaderList.java669
-rw-r--r--java/gov/nist/javax/sip/header/SIPHeaderNames.java121
-rw-r--r--java/gov/nist/javax/sip/header/SIPHeaderNamesCache.java39
-rw-r--r--java/gov/nist/javax/sip/header/SIPIfMatch.java99
-rw-r--r--java/gov/nist/javax/sip/header/SIPObject.java402
-rw-r--r--java/gov/nist/javax/sip/header/SIPObjectList.java152
-rw-r--r--java/gov/nist/javax/sip/header/Server.java188
-rw-r--r--java/gov/nist/javax/sip/header/SipRequestLine.java69
-rw-r--r--java/gov/nist/javax/sip/header/SipStatusLine.java55
-rw-r--r--java/gov/nist/javax/sip/header/StatusLine.java286
-rw-r--r--java/gov/nist/javax/sip/header/Subject.java165
-rw-r--r--java/gov/nist/javax/sip/header/SubscriptionState.java187
-rw-r--r--java/gov/nist/javax/sip/header/Supported.java180
-rw-r--r--java/gov/nist/javax/sip/header/SupportedList.java56
-rw-r--r--java/gov/nist/javax/sip/header/TimeStamp.java196
-rw-r--r--java/gov/nist/javax/sip/header/To.java191
-rw-r--r--java/gov/nist/javax/sip/header/Unsupported.java158
-rw-r--r--java/gov/nist/javax/sip/header/UnsupportedList.java56
-rw-r--r--java/gov/nist/javax/sip/header/UserAgent.java206
-rw-r--r--java/gov/nist/javax/sip/header/Via.java563
-rw-r--r--java/gov/nist/javax/sip/header/ViaHeaderExt.java26
-rw-r--r--java/gov/nist/javax/sip/header/ViaList.java62
-rw-r--r--java/gov/nist/javax/sip/header/WWWAuthenticate.java82
-rw-r--r--java/gov/nist/javax/sip/header/WWWAuthenticateList.java58
-rw-r--r--java/gov/nist/javax/sip/header/Warning.java229
-rw-r--r--java/gov/nist/javax/sip/header/WarningList.java60
-rw-r--r--java/gov/nist/javax/sip/header/extensions/Join.java187
-rw-r--r--java/gov/nist/javax/sip/header/extensions/JoinHeader.java229
-rw-r--r--java/gov/nist/javax/sip/header/extensions/MinSE.java98
-rw-r--r--java/gov/nist/javax/sip/header/extensions/MinSEHeader.java11
-rw-r--r--java/gov/nist/javax/sip/header/extensions/References.java87
-rw-r--r--java/gov/nist/javax/sip/header/extensions/ReferencesHeader.java39
-rw-r--r--java/gov/nist/javax/sip/header/extensions/ReferredBy.java134
-rw-r--r--java/gov/nist/javax/sip/header/extensions/ReferredByHeader.java26
-rw-r--r--java/gov/nist/javax/sip/header/extensions/Replaces.java256
-rw-r--r--java/gov/nist/javax/sip/header/extensions/ReplacesHeader.java32
-rw-r--r--java/gov/nist/javax/sip/header/extensions/SessionExpires.java104
-rw-r--r--java/gov/nist/javax/sip/header/extensions/SessionExpiresHeader.java27
-rw-r--r--java/gov/nist/javax/sip/header/ims/AddressHeaderIms.java84
-rw-r--r--java/gov/nist/javax/sip/header/ims/AuthorizationHeaderIms.java67
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAccessNetworkInfo.java288
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAccessNetworkInfoHeader.java123
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssertedIdentity.java104
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssertedIdentityHeader.java64
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssertedIdentityList.java66
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssertedService.java115
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssertedServiceHeader.java63
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssociatedURI.java161
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssociatedURIHeader.java90
-rw-r--r--java/gov/nist/javax/sip/header/ims/PAssociatedURIList.java65
-rw-r--r--java/gov/nist/javax/sip/header/ims/PCalledPartyID.java91
-rw-r--r--java/gov/nist/javax/sip/header/ims/PCalledPartyIDHeader.java67
-rw-r--r--java/gov/nist/javax/sip/header/ims/PChargingFunctionAddresses.java300
-rw-r--r--java/gov/nist/javax/sip/header/ims/PChargingFunctionAddressesHeader.java144
-rw-r--r--java/gov/nist/javax/sip/header/ims/PChargingVector.java226
-rw-r--r--java/gov/nist/javax/sip/header/ims/PChargingVectorHeader.java167
-rw-r--r--java/gov/nist/javax/sip/header/ims/PMediaAuthorization.java144
-rw-r--r--java/gov/nist/javax/sip/header/ims/PMediaAuthorizationHeader.java73
-rw-r--r--java/gov/nist/javax/sip/header/ims/PMediaAuthorizationList.java56
-rw-r--r--java/gov/nist/javax/sip/header/ims/PPreferredIdentity.java94
-rw-r--r--java/gov/nist/javax/sip/header/ims/PPreferredIdentityHeader.java67
-rw-r--r--java/gov/nist/javax/sip/header/ims/PPreferredService.java115
-rw-r--r--java/gov/nist/javax/sip/header/ims/PPreferredServiceHeader.java65
-rw-r--r--java/gov/nist/javax/sip/header/ims/PProfileKey.java87
-rw-r--r--java/gov/nist/javax/sip/header/ims/PProfileKeyHeader.java46
-rw-r--r--java/gov/nist/javax/sip/header/ims/PServedUser.java164
-rw-r--r--java/gov/nist/javax/sip/header/ims/PServedUserHeader.java61
-rw-r--r--java/gov/nist/javax/sip/header/ims/PUserDatabase.java107
-rw-r--r--java/gov/nist/javax/sip/header/ims/PUserDatabaseHeader.java58
-rw-r--r--java/gov/nist/javax/sip/header/ims/PVisitedNetworkID.java164
-rw-r--r--java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDHeader.java107
-rw-r--r--java/gov/nist/javax/sip/header/ims/PVisitedNetworkIDList.java56
-rw-r--r--java/gov/nist/javax/sip/header/ims/ParameterNamesIms.java91
-rw-r--r--java/gov/nist/javax/sip/header/ims/Path.java89
-rw-r--r--java/gov/nist/javax/sip/header/ims/PathHeader.java57
-rw-r--r--java/gov/nist/javax/sip/header/ims/PathList.java51
-rw-r--r--java/gov/nist/javax/sip/header/ims/Privacy.java149
-rw-r--r--java/gov/nist/javax/sip/header/ims/PrivacyHeader.java79
-rw-r--r--java/gov/nist/javax/sip/header/ims/PrivacyList.java64
-rw-r--r--java/gov/nist/javax/sip/header/ims/SIPHeaderNamesIms.java72
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityAgree.java369
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityAgreeHeader.java185
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityClient.java74
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityClientHeader.java50
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityClientList.java68
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityServer.java72
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityServerHeader.java58
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityServerList.java67
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityVerify.java72
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityVerifyHeader.java51
-rw-r--r--java/gov/nist/javax/sip/header/ims/SecurityVerifyList.java70
-rw-r--r--java/gov/nist/javax/sip/header/ims/ServiceRoute.java91
-rw-r--r--java/gov/nist/javax/sip/header/ims/ServiceRouteHeader.java50
-rw-r--r--java/gov/nist/javax/sip/header/ims/ServiceRouteList.java53
-rw-r--r--java/gov/nist/javax/sip/header/ims/WWWAuthenticateHeaderIms.java71
-rw-r--r--java/gov/nist/javax/sip/header/ims/package.html10
-rw-r--r--java/gov/nist/javax/sip/header/package.html7
-rw-r--r--java/gov/nist/javax/sip/message/Content.java24
-rw-r--r--java/gov/nist/javax/sip/message/ContentImpl.java102
-rw-r--r--java/gov/nist/javax/sip/message/HeaderIterator.java99
-rw-r--r--java/gov/nist/javax/sip/message/ListMap.java187
-rw-r--r--java/gov/nist/javax/sip/message/MessageExt.java120
-rw-r--r--java/gov/nist/javax/sip/message/MessageFactoryExt.java70
-rw-r--r--java/gov/nist/javax/sip/message/MessageFactoryImpl.java849
-rw-r--r--java/gov/nist/javax/sip/message/MessageObject.java170
-rw-r--r--java/gov/nist/javax/sip/message/MultipartMimeContent.java42
-rw-r--r--java/gov/nist/javax/sip/message/MultipartMimeContentImpl.java190
-rw-r--r--java/gov/nist/javax/sip/message/RequestExt.java10
-rw-r--r--java/gov/nist/javax/sip/message/ResponseExt.java11
-rw-r--r--java/gov/nist/javax/sip/message/SIPDuplicateHeaderException.java68
-rw-r--r--java/gov/nist/javax/sip/message/SIPMessage.java1895
-rw-r--r--java/gov/nist/javax/sip/message/SIPRequest.java1207
-rw-r--r--java/gov/nist/javax/sip/message/SIPResponse.java735
-rw-r--r--java/gov/nist/javax/sip/message/package.html4
-rw-r--r--java/gov/nist/javax/sip/package.html42
-rw-r--r--java/gov/nist/javax/sip/parser/AcceptEncodingParser.java205
-rw-r--r--java/gov/nist/javax/sip/parser/AcceptLanguageParser.java206
-rw-r--r--java/gov/nist/javax/sip/parser/AcceptParser.java178
-rw-r--r--java/gov/nist/javax/sip/parser/AddressParametersParser.java75
-rw-r--r--java/gov/nist/javax/sip/parser/AddressParser.java216
-rw-r--r--java/gov/nist/javax/sip/parser/AlertInfoParser.java193
-rw-r--r--java/gov/nist/javax/sip/parser/AllowEventsParser.java177
-rw-r--r--java/gov/nist/javax/sip/parser/AllowParser.java176
-rw-r--r--java/gov/nist/javax/sip/parser/AuthenticationInfoParser.java172
-rw-r--r--java/gov/nist/javax/sip/parser/AuthorizationParser.java147
-rw-r--r--java/gov/nist/javax/sip/parser/CSeqParser.java204
-rw-r--r--java/gov/nist/javax/sip/parser/CallIDParser.java158
-rw-r--r--java/gov/nist/javax/sip/parser/CallInfoParser.java185
-rw-r--r--java/gov/nist/javax/sip/parser/ChallengeParser.java109
-rw-r--r--java/gov/nist/javax/sip/parser/ContactParser.java85
-rw-r--r--java/gov/nist/javax/sip/parser/ContentDispositionParser.java167
-rw-r--r--java/gov/nist/javax/sip/parser/ContentEncodingParser.java182
-rw-r--r--java/gov/nist/javax/sip/parser/ContentLanguageParser.java178
-rw-r--r--java/gov/nist/javax/sip/parser/ContentLengthParser.java144
-rw-r--r--java/gov/nist/javax/sip/parser/ContentTypeParser.java89
-rw-r--r--java/gov/nist/javax/sip/parser/DateParser.java84
-rw-r--r--java/gov/nist/javax/sip/parser/ErrorInfoParser.java176
-rw-r--r--java/gov/nist/javax/sip/parser/EventParser.java164
-rw-r--r--java/gov/nist/javax/sip/parser/ExpiresParser.java160
-rw-r--r--java/gov/nist/javax/sip/parser/FromParser.java151
-rw-r--r--java/gov/nist/javax/sip/parser/HeaderParser.java190
-rw-r--r--java/gov/nist/javax/sip/parser/InReplyToParser.java194
-rw-r--r--java/gov/nist/javax/sip/parser/Lexer.java324
-rw-r--r--java/gov/nist/javax/sip/parser/MaxForwardsParser.java141
-rw-r--r--java/gov/nist/javax/sip/parser/MimeVersionParser.java165
-rw-r--r--java/gov/nist/javax/sip/parser/MinExpiresParser.java162
-rw-r--r--java/gov/nist/javax/sip/parser/OrganizationParser.java86
-rw-r--r--java/gov/nist/javax/sip/parser/ParametersParser.java80
-rw-r--r--java/gov/nist/javax/sip/parser/ParseExceptionListener.java129
-rw-r--r--java/gov/nist/javax/sip/parser/Parser.java223
-rw-r--r--java/gov/nist/javax/sip/parser/ParserFactory.java480
-rw-r--r--java/gov/nist/javax/sip/parser/Pipeline.java196
-rw-r--r--java/gov/nist/javax/sip/parser/PipelinedMsgParser.java505
-rw-r--r--java/gov/nist/javax/sip/parser/PriorityParser.java112
-rw-r--r--java/gov/nist/javax/sip/parser/ProxyAuthenticateParser.java154
-rw-r--r--java/gov/nist/javax/sip/parser/ProxyAuthorizationParser.java166
-rw-r--r--java/gov/nist/javax/sip/parser/ProxyRequireParser.java187
-rw-r--r--java/gov/nist/javax/sip/parser/RAckParser.java205
-rw-r--r--java/gov/nist/javax/sip/parser/RSeqParser.java196
-rw-r--r--java/gov/nist/javax/sip/parser/ReasonParser.java183
-rw-r--r--java/gov/nist/javax/sip/parser/RecordRouteParser.java96
-rw-r--r--java/gov/nist/javax/sip/parser/ReferToParser.java190
-rw-r--r--java/gov/nist/javax/sip/parser/ReplyToParser.java162
-rw-r--r--java/gov/nist/javax/sip/parser/RequestLineParser.java181
-rw-r--r--java/gov/nist/javax/sip/parser/RequireParser.java191
-rw-r--r--java/gov/nist/javax/sip/parser/RetryAfterParser.java131
-rw-r--r--java/gov/nist/javax/sip/parser/RouteParser.java176
-rw-r--r--java/gov/nist/javax/sip/parser/SIPETagParser.java144
-rw-r--r--java/gov/nist/javax/sip/parser/SIPIfMatchParser.java144
-rw-r--r--java/gov/nist/javax/sip/parser/SIPMessageListener.java116
-rw-r--r--java/gov/nist/javax/sip/parser/ServerParser.java205
-rw-r--r--java/gov/nist/javax/sip/parser/StatusLineParser.java175
-rw-r--r--java/gov/nist/javax/sip/parser/StringMsgParser.java709
-rw-r--r--java/gov/nist/javax/sip/parser/SubjectParser.java165
-rw-r--r--java/gov/nist/javax/sip/parser/SubscriptionStateParser.java222
-rw-r--r--java/gov/nist/javax/sip/parser/SupportedParser.java192
-rw-r--r--java/gov/nist/javax/sip/parser/TimeStampParser.java240
-rw-r--r--java/gov/nist/javax/sip/parser/ToParser.java170
-rw-r--r--java/gov/nist/javax/sip/parser/TokenNames.java176
-rw-r--r--java/gov/nist/javax/sip/parser/TokenTypes.java343
-rw-r--r--java/gov/nist/javax/sip/parser/URLParser.java833
-rw-r--r--java/gov/nist/javax/sip/parser/UnsupportedParser.java190
-rw-r--r--java/gov/nist/javax/sip/parser/UserAgentParser.java146
-rw-r--r--java/gov/nist/javax/sip/parser/ViaParser.java258
-rw-r--r--java/gov/nist/javax/sip/parser/WWWAuthenticateParser.java140
-rw-r--r--java/gov/nist/javax/sip/parser/WarningParser.java192
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/JoinParser.java78
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/MinSEParser.java87
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/ReferencesParser.java59
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/ReferredByParser.java63
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/ReplacesParser.java80
-rw-r--r--java/gov/nist/javax/sip/parser/extensions/SessionExpiresParser.java84
-rw-r--r--java/gov/nist/javax/sip/parser/ims/AddressHeaderParser.java72
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PAccessNetworkInfoParser.java126
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PAssertedIdentityParser.java108
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PAssertedServiceParser.java116
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PAssociatedURIParser.java148
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PCalledPartyIDParser.java111
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PChargingFunctionAddressesParser.java178
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PChargingVectorParser.java118
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PMediaAuthorizationParser.java145
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PPreferredIdentityParser.java85
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PPreferredServiceParser.java154
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PProfileKeyParser.java73
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PServedUserParser.java78
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PUserDatabaseParser.java111
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PVisitedNetworkIDParser.java175
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PathParser.java106
-rw-r--r--java/gov/nist/javax/sip/parser/ims/PrivacyParser.java144
-rw-r--r--java/gov/nist/javax/sip/parser/ims/SecurityAgreeParser.java167
-rw-r--r--java/gov/nist/javax/sip/parser/ims/SecurityClientParser.java86
-rw-r--r--java/gov/nist/javax/sip/parser/ims/SecurityServerParser.java128
-rw-r--r--java/gov/nist/javax/sip/parser/ims/SecurityVerifyParser.java84
-rw-r--r--java/gov/nist/javax/sip/parser/ims/ServiceRouteParser.java103
-rw-r--r--java/gov/nist/javax/sip/parser/ims/TokenNamesIms.java52
-rw-r--r--java/gov/nist/javax/sip/parser/ims/package.html7
-rw-r--r--java/gov/nist/javax/sip/parser/package.html4
-rw-r--r--java/gov/nist/javax/sip/stack/DefaultMessageLogFactory.java29
-rw-r--r--java/gov/nist/javax/sip/stack/DefaultRouter.java345
-rw-r--r--java/gov/nist/javax/sip/stack/HandshakeCompletedListenerImpl.java54
-rw-r--r--java/gov/nist/javax/sip/stack/HopImpl.java188
-rw-r--r--java/gov/nist/javax/sip/stack/IOHandler.java340
-rw-r--r--java/gov/nist/javax/sip/stack/MessageChannel.java489
-rw-r--r--java/gov/nist/javax/sip/stack/MessageLog.java174
-rw-r--r--java/gov/nist/javax/sip/stack/MessageProcessor.java356
-rw-r--r--java/gov/nist/javax/sip/stack/RawMessageChannel.java9
-rw-r--r--java/gov/nist/javax/sip/stack/SIPClientTransaction.java1570
-rw-r--r--java/gov/nist/javax/sip/stack/SIPDialog.java3343
-rw-r--r--java/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java73
-rw-r--r--java/gov/nist/javax/sip/stack/SIPDialogEventListener.java35
-rw-r--r--java/gov/nist/javax/sip/stack/SIPServerTransaction.java1711
-rw-r--r--java/gov/nist/javax/sip/stack/SIPStackTimerTask.java35
-rw-r--r--java/gov/nist/javax/sip/stack/SIPTransaction.java1281
-rw-r--r--java/gov/nist/javax/sip/stack/SIPTransactionErrorEvent.java93
-rw-r--r--java/gov/nist/javax/sip/stack/SIPTransactionEventListener.java45
-rw-r--r--java/gov/nist/javax/sip/stack/SIPTransactionStack.java2492
-rw-r--r--java/gov/nist/javax/sip/stack/ServerLog.java466
-rw-r--r--java/gov/nist/javax/sip/stack/ServerRequestInterface.java62
-rw-r--r--java/gov/nist/javax/sip/stack/ServerResponseInterface.java78
-rw-r--r--java/gov/nist/javax/sip/stack/StackMessageFactory.java70
-rw-r--r--java/gov/nist/javax/sip/stack/TCPMessageChannel.java747
-rw-r--r--java/gov/nist/javax/sip/stack/TCPMessageProcessor.java291
-rw-r--r--java/gov/nist/javax/sip/stack/TLSMessageChannel.java738
-rw-r--r--java/gov/nist/javax/sip/stack/TLSMessageProcessor.java307
-rw-r--r--java/gov/nist/javax/sip/stack/UDPMessageChannel.java941
-rw-r--r--java/gov/nist/javax/sip/stack/UDPMessageProcessor.java350
-rw-r--r--java/gov/nist/javax/sip/stack/package.html12
-rw-r--r--java/javax/sip/ClientTransaction.java23
-rw-r--r--java/javax/sip/Dialog.java80
-rw-r--r--java/javax/sip/DialogDoesNotExistException.java15
-rw-r--r--java/javax/sip/DialogState.java24
-rw-r--r--java/javax/sip/DialogTerminatedEvent.java16
-rw-r--r--java/javax/sip/IOExceptionEvent.java29
-rw-r--r--java/javax/sip/InvalidArgumentException.java14
-rw-r--r--java/javax/sip/ListeningPoint.java26
-rw-r--r--java/javax/sip/ObjectInUseException.java15
-rw-r--r--java/javax/sip/PeerUnavailableException.java15
-rw-r--r--java/javax/sip/ProviderDoesNotExistException.java15
-rw-r--r--java/javax/sip/RequestEvent.java30
-rw-r--r--java/javax/sip/ResponseEvent.java30
-rw-r--r--java/javax/sip/ServerTransaction.java12
-rw-r--r--java/javax/sip/SipException.java15
-rw-r--r--java/javax/sip/SipFactory.java104
-rw-r--r--java/javax/sip/SipListener.java12
-rw-r--r--java/javax/sip/SipProvider.java51
-rw-r--r--java/javax/sip/SipStack.java41
-rw-r--r--java/javax/sip/Timeout.java6
-rw-r--r--java/javax/sip/TimeoutEvent.java21
-rw-r--r--java/javax/sip/Transaction.java26
-rw-r--r--java/javax/sip/TransactionAlreadyExistsException.java15
-rw-r--r--java/javax/sip/TransactionDoesNotExistException.java15
-rw-r--r--java/javax/sip/TransactionState.java10
-rw-r--r--java/javax/sip/TransactionTerminatedEvent.java37
-rw-r--r--java/javax/sip/TransactionUnavailableException.java15
-rw-r--r--java/javax/sip/TransportNotSupportedException.java15
-rw-r--r--java/javax/sip/address/Address.java27
-rw-r--r--java/javax/sip/address/AddressFactory.java16
-rw-r--r--java/javax/sip/address/Hop.java13
-rw-r--r--java/javax/sip/address/Router.java12
-rw-r--r--java/javax/sip/address/SipURI.java53
-rw-r--r--java/javax/sip/address/TelURL.java21
-rw-r--r--java/javax/sip/address/URI.java12
-rw-r--r--java/javax/sip/header/AcceptEncodingHeader.java10
-rw-r--r--java/javax/sip/header/AcceptHeader.java15
-rw-r--r--java/javax/sip/header/AcceptLanguageHeader.java17
-rw-r--r--java/javax/sip/header/AlertInfoHeader.java11
-rw-r--r--java/javax/sip/header/AllowEventsHeader.java10
-rw-r--r--java/javax/sip/header/AllowHeader.java10
-rw-r--r--java/javax/sip/header/AuthenticationInfoHeader.java22
-rw-r--r--java/javax/sip/header/AuthorizationHeader.java44
-rw-r--r--java/javax/sip/header/CSeqHeader.java5
-rw-r--r--java/javax/sip/header/CallIdHeader.java10
-rw-r--r--java/javax/sip/header/CallInfoHeader.java13
-rw-r--r--java/javax/sip/header/ContactHeader.java17
-rw-r--r--java/javax/sip/header/ContentDispositionHeader.java18
-rw-r--r--java/javax/sip/header/ContentEncodingHeader.java5
-rw-r--r--java/javax/sip/header/ContentLanguageHeader.java13
-rw-r--r--java/javax/sip/header/ContentLengthHeader.java10
-rw-r--r--java/javax/sip/header/ContentTypeHeader.java11
-rw-r--r--java/javax/sip/header/DateHeader.java10
-rw-r--r--java/javax/sip/header/Encoding.java8
-rw-r--r--java/javax/sip/header/ErrorInfoHeader.java14
-rw-r--r--java/javax/sip/header/EventHeader.java13
-rw-r--r--java/javax/sip/header/ExpiresHeader.java10
-rw-r--r--java/javax/sip/header/ExtensionHeader.java8
-rw-r--r--java/javax/sip/header/FromHeader.java15
-rw-r--r--java/javax/sip/header/Header.java12
-rw-r--r--java/javax/sip/header/HeaderAddress.java8
-rw-r--r--java/javax/sip/header/HeaderFactory.java180
-rw-r--r--java/javax/sip/header/InReplyToHeader.java5
-rw-r--r--java/javax/sip/header/MaxForwardsHeader.java14
-rw-r--r--java/javax/sip/header/MediaType.java11
-rw-r--r--java/javax/sip/header/MimeVersionHeader.java13
-rw-r--r--java/javax/sip/header/MinExpiresHeader.java5
-rw-r--r--java/javax/sip/header/OptionTag.java8
-rw-r--r--java/javax/sip/header/OrganizationHeader.java10
-rw-r--r--java/javax/sip/header/Parameters.java12
-rw-r--r--java/javax/sip/header/PriorityHeader.java15
-rw-r--r--java/javax/sip/header/ProxyAuthenticateHeader.java5
-rw-r--r--java/javax/sip/header/ProxyAuthorizationHeader.java5
-rw-r--r--java/javax/sip/header/ProxyRequireHeader.java5
-rw-r--r--java/javax/sip/header/RAckHeader.java39
-rw-r--r--java/javax/sip/header/RSeqHeader.java22
-rw-r--r--java/javax/sip/header/ReasonHeader.java17
-rw-r--r--java/javax/sip/header/RecordRouteHeader.java5
-rw-r--r--java/javax/sip/header/ReferToHeader.java5
-rw-r--r--java/javax/sip/header/ReplyToHeader.java7
-rw-r--r--java/javax/sip/header/RequireHeader.java5
-rw-r--r--java/javax/sip/header/RetryAfterHeader.java20
-rw-r--r--java/javax/sip/header/RouteHeader.java5
-rw-r--r--java/javax/sip/header/SIPETagHeader.java10
-rw-r--r--java/javax/sip/header/SIPIfMatchHeader.java5
-rw-r--r--java/javax/sip/header/ServerHeader.java13
-rw-r--r--java/javax/sip/header/SubjectHeader.java10
-rw-r--r--java/javax/sip/header/SubscriptionStateHeader.java29
-rw-r--r--java/javax/sip/header/SupportedHeader.java5
-rw-r--r--java/javax/sip/header/TimeStampHeader.java21
-rw-r--r--java/javax/sip/header/ToHeader.java15
-rw-r--r--java/javax/sip/header/TooManyHopsException.java16
-rw-r--r--java/javax/sip/header/UnsupportedHeader.java5
-rw-r--r--java/javax/sip/header/UserAgentHeader.java13
-rw-r--r--java/javax/sip/header/ViaHeader.java38
-rw-r--r--java/javax/sip/header/WWWAuthenticateHeader.java17
-rw-r--r--java/javax/sip/header/WarningHeader.java30
-rw-r--r--java/javax/sip/message/Message.java63
-rw-r--r--java/javax/sip/message/MessageFactory.java64
-rw-r--r--java/javax/sip/message/Request.java29
-rw-r--r--java/javax/sip/message/Response.java65
-rw-r--r--licenses/README.txt8
-rw-r--r--version.txt1
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", "&lt;password&gt;");
+ * </code> <br>
+ * The trust store can be changed, to a separate file with the following
+ * setting: <br>
+ * <code>
+ * properties.setProperty("javax.net.ssl.trustStore", "&lt;trustStoreFileName location&gt;");
+ * </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 = &quot;Accept-Encoding&quot; &quot;:&quot;
+ *
+ *
+ * 1#( codings [ &quot;;&quot; &quot;q&quot; &quot;=&quot; qvalue ] )
+ * codings = ( content-coding | &quot;*&quot; )
+ *
+ * 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 | |
+ * +--------&gt;| |--------------&gt;|
+ * +-----------+ 2xx |
+ * | | 2xx to TU |
+ * | |1xx |
+ * 300-699 +---------------+ |1xx to TU |
+ * ACK sent | | |
+ * resp. to TU | 1xx V |
+ * | 1xx to TU -----------+ |
+ * | +---------| | |
+ * | | |Proceeding |--------------&gt;|
+ * | +--------&gt;| | 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 |--------------&gt;| the event
+ * | +--------&gt;| | | over the action
+ * | +-----------+ | to take
+ * | &circ; | |
+ * | | | Timer D fires |
+ * +--------------+ | - |
+ * | |
+ * V |
+ * +-----------+ |
+ * | | |
+ * | Terminated|&lt;--------------+
+ * | |
+ * +-----------+
+ *
+ * Figure 5: INVITE client transaction
+ *
+ *
+ * |Request from TU
+ * |send request
+ * Timer E V
+ * send request +-----------+
+ * +---------| |-------------------+
+ * | | Trying | Timer F |
+ * +--------&gt;| | 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 |------------------&gt;|
+ * | +--------&gt;| |-----+ |
+ * | +-----------+ |1xx |
+ * | | &circ; |resp to TU |
+ * | 200-699 | +--------+ |
+ * | resp. to TU | |
+ * | | |
+ * | V |
+ * | +-----------+ |
+ * | | | |
+ * | | Completed | |
+ * | | | |
+ * | +-----------+ |
+ * | &circ; | |
+ * | | | Timer K |
+ * +--------------+ | - |
+ * | |
+ * V |
+ * NOTE: +-----------+ |
+ * | | |
+ * transitions | Terminated|&lt;------------------+
+ * 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 |
+ * +--------&gt;| | 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 |------------------&gt;|
+ * | +--------&gt;| |-----+ |
+ * | +-----------+ |1xx |
+ * | | &circ; |resp to TU |
+ * | 200-699 | +--------+ |
+ * | resp. to TU | |
+ * | | |
+ * | V |
+ * | +-----------+ |
+ * | | | |
+ * | | Completed | |
+ * | | | |
+ * | +-----------+ |
+ * | &circ; | |
+ * | | | Timer K |
+ * +--------------+ | - |
+ * | |
+ * V |
+ * NOTE: +-----------+ |
+ * | | |
+ * transitions | Terminated|&lt;------------------+
+ * 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 | |
+ * +--------&gt;| |--------------&gt;|
+ * +-----------+ 2xx |
+ * | | 2xx to TU |
+ * | |1xx |
+ * 300-699 +---------------+ |1xx to TU |
+ * ACK sent | | |
+ * resp. to TU | 1xx V |
+ * | 1xx to TU -----------+ |
+ * | +---------| | |
+ * | | |Proceeding |--------------&gt;|
+ * | +--------&gt;| | 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 |--------------&gt;| the event
+ * | +--------&gt;| | | over the action
+ * | +-----------+ | to take
+ * | &circ; | |
+ * | | | Timer D fires |
+ * +--------------+ | - |
+ * | |
+ * V |
+ * +-----------+ |
+ * | | |
+ * | Terminated|&lt;--------------+
+ * | |
+ * +-----------+
+ *
+ *
+ *
+ *
+ * </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
+ * +-------&gt;| |&lt;-------+
+ * | | Transport Err.
+ * | | Inform TU
+ * | |---------------&gt;+
+ * +-----------+ |
+ * 300-699 from TU | |2xx from TU |
+ * send response | |send response |
+ * | +------------------&gt;+
+ * | |
+ * INVITE V Timer G fires |
+ * send response+-----------+ send response |
+ * +--------| |--------+ |
+ * | | Completed | | |
+ * +-------&gt;| |&lt;-------+ |
+ * +-----------+ |
+ * | | |
+ * ACK | | |
+ * - | +------------------&gt;+
+ * | Timer H fires |
+ * V or Transport Err.|
+ * +-----------+ Inform TU |
+ * | | |
+ * | Confirmed | |
+ * | | |
+ * +-----------+ |
+ * | |
+ * |Timer I fires |
+ * |- |
+ * | |
+ * V |
+ * +-----------+ |
+ * | | |
+ * | Terminated|&lt;---------------+
+ * | |
+ * +-----------+
+ *
+ * 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| | |
+ * +-------&gt;| |&lt;-------+ |
+ * +&lt;--------------| | |
+ * |Trnsprt Err +-----------+ |
+ * |Inform TU | |
+ * | | |
+ * | |200-699 from TU |
+ * | |send response |
+ * | Request V |
+ * | send response+-----------+ |
+ * | +--------| | |
+ * | | | Completed |&lt;------------+
+ * | +-------&gt;| |
+ * +&lt;--------------| |
+ * |Trnsprt Err +-----------+
+ * |Inform TU |
+ * | |Timer J fires
+ * | |-
+ * | |
+ * | V
+ * | +-----------+
+ * | | |
+ * +--------------&gt;| 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