From ce628be7615d89475abd3ecbcc385eed4c6e38fc Mon Sep 17 00:00:00 2001 From: oana Date: Fri, 11 Nov 2011 17:12:13 +0000 Subject: [PATCH] Added module which translate MAP/CAMEL protocol data to XML format and vice versa. git-svn-id: http://voip.null.ro/svn/yate@4694 acf43c95-373e-0410-b603-e72c3f656dc1 --- conf.d/camel_map.conf.sample | 24 + modules/Makefile.in | 7 +- modules/sig/camel_map.cpp | 6897 ++++++++++++++++++++++++++++++++++ 3 files changed, 6927 insertions(+), 1 deletion(-) create mode 100644 conf.d/camel_map.conf.sample create mode 100644 modules/sig/camel_map.cpp diff --git a/conf.d/camel_map.conf.sample b/conf.d/camel_map.conf.sample new file mode 100644 index 00000000..bca6009f --- /dev/null +++ b/conf.d/camel_map.conf.sample @@ -0,0 +1,24 @@ +; This file keeps the configuration for the module which translates MAP/CAMEL protocol data to XML and vice versa. +; Each section configures a separate translator + +;[tcap map] +; This section configures a TCAP User MAP/CAMEL protocol translator + +; type: string: Type of TCAP User +; Allowed values are MAP or CAMEL +;type=MAP + +; host: IP address: Address on which the TCP listener should bind on for XML communication +;host=127.0.0.1 + +; port: integer: Port on which the TCP listener should bind on for XML communication +;port=5555 + +; tcap: string: Name of TCAP to which this TCAP user should attach itself to for the SS7 communication +;tcap= + +; add-encoding: bool: Always add encoding attribute to XML elements for decoded parameters +;add-encoding=false + +; print-messages: bool: Debug option to print TCAP and XML messages. This option is applicable on reload. +;print-messages=false \ No newline at end of file diff --git a/modules/Makefile.in b/modules/Makefile.in index ba45602d..5e5284f7 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -44,7 +44,8 @@ INCFILES := @top_srcdir@/yateclass.h @top_srcdir@/yatengine.h @top_srcdir@/yatep JUSTSIG := server/ysigchan.yate server/analog.yate \ server/ciscosm.yate server/sigtransport.yate \ - sig/isupmangler.yate sig/ss7_lnp_ansi.yate + sig/isupmangler.yate sig/ss7_lnp_ansi.yate \ + sig/camel_map.yate SUBDIRS := MKDEPS := ../config.status @@ -280,6 +281,10 @@ $(JUSTSIG) server/wpcard.yate server/tdmcard.yate server/zapcard.yate: LOCALLIBS sig/ss7_lnp_ansi.yate: LOCALFLAGS = -I@top_srcdir@/libs/ysig -I@top_srcdir@/libs/yasn sig/ss7_lnp_ansi.yate: LOCALLIBS = -lyatesig -L../libs/yasn -lyasn +sig/camel_map.yate: ../libs/yasn/libyasn.a ../libs/yxml/libyatexml.a +sig/camel_map.yate: LOCALFLAGS = -I@top_srcdir@/libs/ysig -I@top_srcdir@/libs/yasn -I@top_srcdir@/libs/yxml +sig/camel_map.yate: LOCALLIBS = -lyatesig -L../libs/yasn -lyasn -L../libs/yxml -lyatexml + server/analogdetect.yate: ../libs/ymodem/libyatemodem.a server/analogdetect.yate: LOCALFLAGS = -I@top_srcdir@/libs/ymodem server/analogdetect.yate: LOCALLIBS = -L../libs/ymodem -lyatemodem diff --git a/modules/sig/camel_map.cpp b/modules/sig/camel_map.cpp new file mode 100644 index 00000000..08f6a7a7 --- /dev/null +++ b/modules/sig/camel_map.cpp @@ -0,0 +1,6897 @@ +/** + * camel_map.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * MAP/CAMEL TCAP <-> XML translators + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004 - 2011 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +using namespace TelEngine; + +namespace { + +class TcapXUser; +class TcapXModule; +class XMLConnListener; +class XMLConnection; +class TcapXApplication; +class TcapToXml; +class XmlToTcap; +class TcapXNamespace; +struct MapCamelType; +struct Parameter; +struct Operation; + +struct XMLMap { + Regexp name; + const char* map; + const char* tag; + int type; +}; + +struct TCAPMap { + const char* path; + bool isPrefix; + const String name; +}; + +struct AppCtxt { + const char* name; + const char* oid; + const char* ops; +}; + +struct Capability { + const char* name; + String ops[30]; +}; + + +class XMLConnection : public Thread +{ +public: + XMLConnection(Socket* skt, TcapXApplication* app); + ~XMLConnection(); + // inherited from thread + void start(); + void run(); + void cleanup(); + + bool writeData(XmlFragment* frag); +private: + Socket* m_socket; + String m_address; + TcapXApplication* m_app; + XmlDomParser* m_parser; +}; + +class XMLConnListener : public Thread +{ +public: + XMLConnListener(TcapXUser* user, const NamedList& sect); + ~XMLConnListener(); + virtual bool init(); + virtual void run(); + void cleanup(); + bool createConn(Socket* skt, String& addr); +protected: + // the socket on which we accept connections + TcapXUser* m_user; + Socket m_socket; + String m_host; + int m_port; +}; + +class IDMap : public ObjList +{ +public: + inline IDMap() + {} + inline ~IDMap() + {} + void appendID(const char* tcapID, const char* appID); + const String& findTcapID(const char* appID); + const String& findAppID(const char* tcapID); + void removeAppID(const char* appID); +}; + +class XmlToTcap : public GenObject, public Mutex +{ +public: + enum MsgType { + Unknown, + Capability, + Tcap, + }; + XmlToTcap(TcapXApplication* app); + ~XmlToTcap(); + inline bool hasDeclaration() + { return m_decl; } + inline XmlElement* message() + { return m_elem; } + inline MsgType type() + { return m_type; } + bool validDeclaration(); + bool valid(); + void setXmlFragment(XmlFragment* frag); + bool checkXmlns(); + bool parse(NamedList& tcapParams); + bool parse(NamedList& tcapParams, XmlElement* elem, String prefix); + bool handleComponent(NamedList& tcapParams, XmlElement* elem); + void reset(); + static const TCAPMap s_tcapMap[]; + const TCAPMap* findMap(String& path); + bool encodeComponent(DataBlock& payload, XmlElement* elem, bool searchArgs, int& err, Operation* op); + void encodeOperation(Operation* op, XmlElement* elem, DataBlock& payload, int& err, bool searchArgs); +private: + TcapXApplication* m_app; + XmlFragment* m_frag; + XmlDeclaration* m_decl; + XmlElement* m_elem; + MsgType m_type; +}; + +class TcapToXml : public GenObject, public Mutex +{ +public: + enum MsgType { + Unknown, + State, + Tcap, + }; + enum XmlType { + None, + Element, + Attribute, + Value, + End, + }; + TcapToXml(TcapXApplication* app); + ~TcapToXml(); + inline MsgType type() + { return m_type; } + bool buildXMLMessage(NamedList& msg, XmlFragment* frag, MsgType type); + static const XMLMap s_xmlMap[]; + void reset(); + void addToXml(XmlElement* root, const XMLMap* map, NamedString* val); + void addComponentsToXml(XmlElement* root, NamedList& params, AppCtxt* ctxt); + const XMLMap* findMap(String& elem); + void addParametersToXml(XmlElement* elem, String& payloadHex, Operation* op, bool searchArgs = true); + void decodeTcapToXml(TelEngine::XmlElement*, TelEngine::DataBlock&, Operation* op, unsigned int index = 0, bool seachArgs = true); + bool decodeOperation(Operation* op, XmlElement* elem, DataBlock& data, bool searchArgs = true); +private: + TcapXApplication* m_app; + MsgType m_type; +}; + +class TcapXUser : public TCAPUser, public Mutex +{ +public: + enum UserType { + MAP, + CAMEL, + }; + TcapXUser(const char* name); + ~TcapXUser(); + virtual bool tcapIndication(NamedList& params); + virtual bool managementNotify(SCCP::Type type, NamedList& params); + bool findTCAP(const char* name); + int managementState(); + bool initialize(NamedList& sect); + bool createApplication(Socket* skt, String& addr); + void setListener(XMLConnListener* list); + void removeApp(TcapXApplication* app); + SS7TCAPError applicationRequest(TcapXApplication* app, NamedList& params, int reqType); + bool sendToApp(NamedList& params, TcapXApplication* app = 0); + TcapXApplication* findApplication(NamedList& params); + void reorderApps(TcapXApplication* app); + inline UserType type() + { return m_type; } + inline bool printMessages() + { return m_printMsg; } + inline bool addEncoding() + { return m_addEnc; } + inline unsigned int applicationCount() + { + Lock l(m_appsMtx); + return m_apps.count(); + } + void statusString(String& str); +protected: + ObjList m_apps; + Mutex m_appsMtx; + XMLConnListener* m_listener; + ObjList m_trIDs; + UserType m_type; + bool m_printMsg; + bool m_addEnc; +}; + +class TcapXApplication : public RefObject, public Mutex +{ +public: + enum State { + Waiting, + Active, + ShutDown, + Inactive, + }; + enum ParamType { + Unknown, + Null, + Bool, + Integer, + OID, + HexString, + BitString, + TBCD, + AddressString, + AppString, + Enumerated, + Choice, + Sequence, + SequenceOf, + SetOf, + GSMString, + Flags, + CellIdFixedLength, + LAIFixedLength, + CalledPartyNumber, + CallingPartyNumber, + LocationNumber, + OriginalCalledNumber, + RedirectingNumber, + GenericNumber, + ChargeNumber, + HiLayerCompat, + UserServiceInfo, + RedirectionInformation, + None, + }; + enum EncType { + BoolEnc, + IntEnc, + OIDEnc, + StringEnc, + NullEnc, + HexEnc, + TelephonyEnc, + NoEnc, + }; + enum Error { + NoError, + DataMissing, + UnexpectedDataValue, + }; + TcapXApplication(const char* name, Socket* skt, TcapXUser* user); + ~TcapXApplication(); + bool hasCapability(const char* oper); + bool handleXML(); + void receivedXML(XmlFragment* frag); + const String& toString() const + { return m_name; } + void setIO(XMLConnection* io); + void reportState(State state, const char* error = 0); + void closeConnection(); + bool supportCapability(const String& capab); + void sendStateResponse(const char* error = 0); + bool handleCapability(NamedList& params); + bool handleTcap(NamedList& params); + bool handleIndication(NamedList& params); + void reportError(const char* err); + bool sendTcapMsg(NamedList& params); + bool canHandle(NamedList& params); + void status(NamedList& status); + inline State state() + { return m_state; } + inline unsigned int trCount() + { return m_ids.count() + m_pending.count(); } + inline TcapXUser::UserType type() + { return m_type; } + inline bool addEncoding() + { return (m_user ? m_user->addEncoding() : false); } +private: + IDMap m_ids; + IDMap m_pending; + ObjList m_capab; + XMLConnection* m_io; + String m_name; + TcapXUser* m_user; + unsigned int m_sentXml; + unsigned int m_receivedXml; + unsigned int m_sentTcap; + unsigned int m_receivedTcap; + State m_state; + TcapToXml m_tcap2Xml; + XmlToTcap m_xml2Tcap; + TcapXUser::UserType m_type; +}; + +class TcapXModule : public Module +{ +public: + TcapXModule(); + virtual ~TcapXModule(); + //inherited methods + virtual void initialize(); + // uninstall relays and message handlers + bool unload(); +protected: + // inherited methods + virtual bool received(Message& msg, int id); + virtual void statusModule(String& str); + void initUsers(Configuration& cfg); + virtual void statusParams(String& str); + virtual void statusDetail(String& str); + unsigned int applicationCount(); +private: + bool m_init; + Mutex m_usersMtx; + ObjList m_users; +}; + +INIT_PLUGIN(TcapXModule); + +UNLOAD_PLUGIN(unloadNow) +{ + if (unloadNow && !__plugin.unload()) + return false; + return true; +} + +const String s_namespace = "http://yate.null.ro/xml/tcap/v1"; + +static const String s_msgTag = "m"; +static const String s_capabTag = "c"; +static const String s_component = "component"; +static const String s_typeStr = "type"; +static const String s_tagAttr = "tag"; +static const String s_encAttr = "enc"; +static const String s_qualifierAttr = "qualifier"; +static const String s_planAttr = "plan"; +static const String s_natureAttr = "nature"; +static const String s_innAttr = "inn"; +static const String s_completeAttr = "complete"; +static const String s_restrictAttr = "restrict"; +static const String s_screenedtAttr = "screened"; + +static const String s_tcapUser = "tcap.user"; +static const String s_tcapRequestError = "tcap.request.error"; +static const String s_tcapLocalTID = "tcap.transaction.localTID"; +static const String s_tcapRemoteTID = "tcap.transaction.remoteTID"; +static const String s_tcapAppCtxt = "tcap.dialogPDU.application-context-name"; +static const String s_tcapReqType = "tcap.request.type"; +static const String s_tcapCompCount = "tcap.component.count"; +static const String s_tcapCompPrefix = "tcap.component"; +static const String s_tcapCompPrefixSep = "tcap.component."; +static const String s_tcapAbortCause = "tcap.transaction.abort.cause"; +static const String s_tcapAbortInfo = "tcap.transaction.abort.information"; +static const String s_tcapCompType = "componentType"; +static const String s_tcapOpCodeType = "operationCodeType"; +static const String s_tcapOpCode = "operationCode"; +static const String s_tcapErrCodeType = "errorCodeType"; +static const String s_tcapErrCode = "errorCode"; +static const String s_tcapProblemCode = "problemCode"; + +static const TokenDict s_tagTypes[] = { + {"universal", AsnTag::Universal}, + {"application", AsnTag::Application}, + {"context", AsnTag::Context}, + {"private", AsnTag::Private}, + {"", -1}, +}; + +struct Parameter { + const String name; + const AsnTag& tag; + bool isOptional; + TcapXApplication::ParamType type; + const void* content; +}; + +struct Operation { + const String name; + bool local; + int code; + const AsnTag& argTag; + const Parameter* args; + const AsnTag& retTag; + const Parameter* res; +}; + +static const TokenDict s_dict_numNature[] = { + { "unknown", 0x00 }, + { "international", 0x10 }, + { "national", 0x20 }, + { "network-specific", 0x30 }, + { "subscriber", 0x40 }, + { "reserved", 0x50 }, + { "abbreviated", 0x60 }, + { "extension-reserved", 0x70 }, + { 0, 0 }, +}; + +// Numbering Plan Indicator +static const TokenDict s_dict_numPlan[] = { + { "unknown", 0 }, + { "isdn", 1 }, + { "data", 3 }, + { "telex", 4 }, + { "land-mobile", 6 }, + { "national", 8 }, + { "private", 9 }, + { "extension-reserved", 15 }, + { 0, 0 }, +}; + +struct MapCamelType { + TcapXApplication::ParamType type; + TcapXApplication::EncType encoding; + bool (*decode)(const Parameter*, MapCamelType*, AsnTag& tag, DataBlock&, XmlElement*, bool, int& err); + bool (*encode)(const Parameter*, MapCamelType*, DataBlock&, XmlElement*, int& err); +}; + +static const MapCamelType* findType(TcapXApplication::ParamType type); + +static AsnTag s_sequenceTag(AsnTag::Universal,AsnTag::Constructor,16); +static AsnTag s_intTag(AsnTag::Universal, AsnTag::Primitive, 2); +static AsnTag s_bitsTag(AsnTag::Universal, AsnTag::Primitive, 3); +static AsnTag s_nullTag(AsnTag::Universal, AsnTag::Primitive, 5); +static AsnTag s_oidTag(AsnTag::Universal, AsnTag::Primitive, 6); +static AsnTag s_hexTag(AsnTag::Universal, AsnTag::Primitive, 4); +static AsnTag s_numStrTag(AsnTag::Universal, AsnTag::Primitive, 18); +static AsnTag s_noTag(AsnTag::Universal, AsnTag::Primitive, 0); +static AsnTag s_enumTag(AsnTag::Universal, AsnTag::Primitive, 10); + +static const Parameter* findParam(const Parameter* param, const String& tag) +{ + if (!param) + return 0; + XDebug(DebugAll,"findParam(param=%s,tag=%s)",param->name.c_str(),tag.c_str()); + if (param->type == TcapXApplication::Choice && param->content) { + const Parameter* p = static_cast(param->content); + if (p) + return findParam(p,tag); + } + while (param && !TelEngine::null(param->name)) { + if (tag == param->name) + return param; + param++; + } + return 0; +} + +static bool encodeParam(const Parameter* param, DataBlock& data, XmlElement* elem, int& err); + +static bool encodeRaw(const Parameter* param, DataBlock& payload, XmlElement* elem, int& err) +{ + if (!elem) + return true; + + XDebug(&__plugin,DebugAll,"encodeRaw(param=[%p],elem=%s[%p])",param,elem->getTag().c_str(),elem); + bool hasChildren = false; + bool status = true; + while (XmlElement* child = elem->pop()) { + hasChildren = true; + DataBlock db; + Parameter* p = (Parameter*)findParam(param,elem->getTag()); + if (p) + status = encodeParam(p,db,child,err); + else + status = encodeRaw(p,db,child,err); + payload.append(db); + TelEngine::destruct(child); + if (!status) + break; + } + AsnTag tag; + String* clas = elem->getAttribute(s_typeStr); + if (TelEngine::null(clas)) + return false; + tag.classType((AsnTag::Class)lookup(*clas,s_tagTypes,AsnTag::Universal)); + clas = elem->getAttribute(s_tagAttr); + if (TelEngine::null(clas)) + return false; + tag.code(clas->toInteger()); + + String text = elem->getText(); + if (!hasChildren) { + clas = elem->getAttribute(s_encAttr); + if (TelEngine::null(clas)) + return false; + tag.type(AsnTag::Primitive); + if (*clas == "hex") + payload.unHexify(text.c_str(),text.length(),' '); + else if (*clas == "int") + payload.insert(ASNLib::encodeInteger(text.toInteger(),false)); + else if (*clas == "str") + payload.insert(ASNLib::encodeUtf8(text,false)); + else if (*clas == "null") + payload.clear(); + else if (*clas == "oid") { + ASNObjId obj = text; + payload.insert(ASNLib::encodeOID(obj,false)); + } + else if (*clas == "bool") + payload.insert(ASNLib::encodeBoolean(text.toBoolean(),false)); + payload.insert(ASNLib::buildLength(payload)); + AsnTag::encode(tag.classType(),tag.type(),tag.code(),payload); + } + else { + tag.type(AsnTag::Constructor); + payload.insert(ASNLib::buildLength(payload)); + AsnTag::encode(tag.classType(),tag.type(),tag.code(),payload); + } + return true; +} + +static bool encodeParam(const Parameter* param, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeParam(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + MapCamelType* type = (MapCamelType*)findType(param->type); + bool ok = true; + if (!type) + ok = encodeRaw(param,data,elem,err); + else { + XmlElement* child = (elem->getTag() == s_component ? elem->findFirstChild(¶m->name) : elem); + if (!child) { + if (!param->isOptional) { + err = TcapXApplication::DataMissing; + return false; + } + return true; + } + ok = type->encode(param,type,data,child,err); + elem->removeChild(child); + } + String str; + str.hexify(data.data(),data.length(),' '); + XDebug(&__plugin,DebugAll,"encodeParam(param=%s[%p],elem=%s[%p] has %ssucceeded, encodedData=%s)",param->name.c_str(),param, + elem->getTag().c_str(),elem,(ok ? "" : "not "),str.c_str()); + return ok; +} + +static bool decodeRaw(XmlElement* elem, DataBlock& data, bool singleParam = false) +{ + if (!(elem && data.length())) + return false; + DDebug(&__plugin,DebugAll,"decodeRaw(elem=%s[%p])",elem->getTag().c_str(),elem); + while (data.length()) { + AsnTag tag; + AsnTag::decode(tag,data); + + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement("u"); + elem->addChild(child); + child->setAttributeValid(s_typeStr,lookup(tag.classType(),s_tagTypes,"")); + child->setAttributeValid(s_tagAttr,String((unsigned int)tag.code())); + + if (tag.type() == AsnTag::Primitive) { + + String enc; + String value; + int len = 0; + u_int8_t fullTag = tag.classType() | tag.type() | tag.code(); + switch (fullTag) { + case ASNLib::BOOLEAN: { + bool val; + if (ASNLib::decodeBoolean(data,&val,true) < 0) + return false; + value = String::boolText(val); + enc = "bool"; + } + break; + case ASNLib::INTEGER: { + u_int64_t val; + if (ASNLib::decodeInteger(data,val,sizeof(val),true) < 0) + return false; + // to do fix conversion from u_int64_t + value = String((int)val); + enc = "int"; + } + break; + case ASNLib::OBJECT_ID: { + ASNObjId val; + if (ASNLib::decodeOID(data,&val,true) < 0) + return false; + value = val.toString(); + enc = "oid"; + } + break; + case ASNLib::UTF8_STR: { + if (ASNLib::decodeUtf8(data,&enc,true) < 0) + return false; + value = enc; + enc = "str"; + } + break; + case ASNLib::NULL_ID: + if (ASNLib::decodeNull(data,true) < 0) + return false; + enc = "null"; + break; + case ASNLib::NUMERIC_STR: + case ASNLib::PRINTABLE_STR: + case ASNLib::IA5_STR: + case ASNLib::VISIBLE_STR: { + int type; + if (ASNLib::decodeString(data,&enc,&type,true) < 0) + return false; + value = enc; + enc = "str"; + } + break; + default: + len = ASNLib::decodeLength(data); + value.hexify(data.data(),len,' '); + data.cut(-len); + enc = "hex"; + break; + } + + child->setAttributeValid(s_encAttr,enc); + child->addText(value); + } + else { + int len = ASNLib::decodeLength(data); + DataBlock payload(data.data(),len); + data.cut(-len); + decodeRaw(child,payload); + } + if (singleParam) + break; + } + return true; +} + +static bool decodeParam(const Parameter* param, AsnTag& tag, DataBlock& data, XmlElement* elem, bool addEnc, int& err) +{ + if (!(param && elem && data.length())) + return false; + String str; + str.hexify(data.data(),data.length(),' '); + + XDebug(&__plugin,DebugAll,"decodeParam(param=%s[%p],elem=%s[%p]) - data = %s",param->name.c_str(),param,elem->getTag().c_str(), + elem,str.c_str()); + MapCamelType* type = (MapCamelType*)findType(param->type); + bool ok = true; + if (!type) + ok = decodeRaw(elem,data,true); + else + ok = type->decode(param,type,tag,data,elem,addEnc,err); + + XDebug(&__plugin,DebugAll,"decodeParam(param=%s[%p],elem=%s[%p]) %s",param->name.c_str(),param,elem->getTag().c_str(), + elem, (ok ? "OK" : "FAILED")); + return ok; +} + +static unsigned int decodeBCD(unsigned int length, String& digits, unsigned char* buff) +{ + if (!(buff && length)) + return 0; + static const char s_digits[] = "0123456789*#ABC"; + unsigned int index = 0; + while (index < length) { + digits += s_digits[(buff[index] & 0x0f)]; + u_int8_t odd = (buff[index] >> 4); + if ((odd & 0x0f) != 0x0f) + digits += s_digits[(buff[index] >> 4)]; + index++; + } + XDebug(&__plugin,DebugAll,"Decoded BCD digits=%s",digits.c_str()); + return index; +} + +void encodeBCD(const String& digits, DataBlock& data) +{ + XDebug(&__plugin,DebugAll,"encodeBCD(digit=%s)",digits.c_str()); + unsigned int len = digits.length() / 2 + (digits.length() % 2 ? 1 : 0); + unsigned char buf[32]; + unsigned int i = 0; + unsigned int j = 0; + bool odd = false; + while((i < digits.length()) && (j < len)) { + char c = digits[i++]; + unsigned char d = 0; + if (('0' <= c) && (c <= '9')) + d = c - '0'; + else if ('*' == c) + d = 10; + else if ('#' == c) + d = 11; + else if ('a' == c || 'A' == c) + d = 12; + else if ('b' == c || 'B' == c) + d = 13; + else if ('c' == c || 'C' == c) + d = 14; +// else if ('.' == c) +// d = 15; + else + continue; + odd = !odd; + if (odd) + buf[j] = d; + else + buf[j++] |= (d << 4); + } + if (odd) + buf[j++] |= 0xf0; + + data.append(&buf,j); +} + +static bool decodeTBCD(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeTBCD(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,parent->getTag().c_str(),parent); + if (param->tag != tag) + return false; + + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"str"); + int len = ASNLib::decodeLength(data); + String digits; + len = decodeBCD(len,digits,data.data(0,len)); + data.cut(-len); + child->addText(digits); + return true; +} + +static bool encodeTBCD(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeTBCD(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + const String& text = elem->getText(); + encodeBCD(text,data); + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +static bool decodeTel(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeTel(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + int len = ASNLib::decodeLength(data); + if (len < 1) + return false; + u_int8_t attr = data[0]; + child->setAttribute(s_natureAttr,lookup((attr & 0x70),s_dict_numNature,"unknown")); + child->setAttribute(s_planAttr,lookup((attr & 0x0f),s_dict_numPlan,"unknown")); + if ((attr & 0x0f) == 1) + child->setAttribute(s_encAttr,"e164"); + else if ((attr & 0x0f) == 6) + child->setAttribute(s_encAttr,"e212"); + String digits; + decodeBCD(len - 1,digits,data.data(1,len - 1 )); + + data.cut(-len); + child->addText(digits); + return true; +} + +static bool encodeTel(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeTel(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,elem->getTag().c_str(), + elem,data.length()); + + u_int8_t first = 0x80; // noExtension bit set + first |= lookup(elem->attribute(s_natureAttr),s_dict_numNature,0); + first |= lookup(elem->attribute(s_planAttr),s_dict_numPlan,0); + data.append(&first,sizeof(first)); + + const String& digits = elem->getText(); + encodeBCD(digits,data); + + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +static bool decodeHex(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeHex(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"oid"); + + int len = ASNLib::decodeLength(data); + String octets; + octets.hexify(data.data(),len,' '); + data.cut(-len); + child->addText(octets); + return true; +} + +static bool encodeHex(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeHexparam=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + const String& text = elem->getText(); + data.unHexify(text.c_str(),text.length(),' '); + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding());; + return true; +} + +static bool decodeOID(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeOID(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"oid"); + + ASNObjId obj; + ASNLib::decodeOID(data,&obj,false); + child->addText(obj.toString()); + + return true; +} + +static bool encodeOID(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeOID(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + ASNObjId oid = elem->getText(); + data.append(ASNLib::encodeOID(oid,false)); + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +static bool decodeNull(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeNull(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"null"); + + int len = ASNLib::decodeNull(data,false); + data.cut(-len); + return true; +} + +static bool encodeNull(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeNull(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + ASNObjId oid = elem->getText(); + data.append(ASNLib::encodeNull(false)); + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +static bool decodeInt(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeInt(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"int"); + + u_int64_t val; + ASNLib::decodeInteger(data,val,sizeof(val),false); + child->addText(String((int)val)); + return true; +} + +static bool encodeInt(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeInt(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + u_int64_t val = elem->getText().toInteger(); + data.append(ASNLib::encodeInteger(val,false)); + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +static bool decodeSeq(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeSeq(param=%s[%p],elem=%s[%p],datalen=%d,first=0x%x)",param->name.c_str(),param, + parent->getTag().c_str(),parent,data.length(),data[0]); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + int len = ASNLib::decodeLength(data); + if (len < 0) + return false; + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + + if (param->content) { + const Parameter* params= static_cast(param->content); + while (params && !TelEngine::null(params->name)) { + AsnTag childTag; + AsnTag::decode(childTag,data); + if (!decodeParam(params,childTag,data,child,addEnc,err)) { + if (!params->isOptional) { + err = TcapXApplication::DataMissing; + return false; + } + else { + params++; + continue; + } + } + params++; + } + } + return true; +} + +static bool encodeSeq(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeSeq(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (param->content) { + const Parameter* params= static_cast(param->content); + while (params && !TelEngine::null(params->name)) { + const String name = params->name; + XmlElement* child = elem->findFirstChild(&name); + if (!child) { + if (!params->isOptional) { + err = TcapXApplication::DataMissing; + return false; + } + else { + params++; + continue; + } + } + DataBlock db; + if (!encodeParam(params,db,child,err)) + return false; + data.append(db); + elem->removeChild(child); + params++; + } + } + + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static bool decodeSeqOf(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, + int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeSeqOf(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + int len = ASNLib::decodeLength(data); + if (len < 0) + return false; + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + + int initLength = data.length(); + int payloadLen = len; + if (param->content) { + const Parameter* params= static_cast(param->content); + while (params && !TelEngine::null(params->name) && payloadLen) { + AsnTag childTag; + AsnTag::decode(childTag,data); + if (!decodeParam(params,childTag,data,child,addEnc,err)) { + if (!param->isOptional) { + err = TcapXApplication::DataMissing; + return false; + } + else + break; + } + payloadLen = data.length() - (initLength - len); + } + } + return true; +} + +static bool encodeSeqOf(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeSeqOf(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (param->content) { + const Parameter* params = static_cast(param->content); + XmlElement* child = elem->pop(); + while (params && !TelEngine::null(params->name) && child) { + if (!(child->getTag() == params->name)) { + if (!param->isOptional) { + TelEngine::destruct(child); + err = TcapXApplication::DataMissing; + return false; + } + else + continue; + } + DataBlock db; + if (!encodeParam(params,db,child,err)) { + TelEngine::destruct(child); + return false; + } + data.append(db); + TelEngine::destruct(child); + child = elem->pop(); + } + } + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + + +static bool decodeChoice(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeChoice(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != s_noTag) { + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + int len = ASNLib::decodeLength(data); + if (len < 0) + return false; + } + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + + if (param->content) { + const Parameter* params= static_cast(param->content); + while (params && !TelEngine::null(params->name)) { + AsnTag childTag; + AsnTag::decode(childTag,data); + if (!decodeParam(params,childTag,data,child,addEnc,err)) { + params++; + continue; + } + break; + } + } + return true; +} + +static bool encodeChoice(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeChoice(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (param->content) { + const Parameter* params = static_cast(param->content); + XmlElement* child = elem->pop(); + while (child && params && !TelEngine::null(params->name)) { + if (child->getTag() == params->name) { + DataBlock db; + if (!encodeParam(params,db,child,err)) { + TelEngine::destruct(child); + return false; + } + data.append(db); + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + TelEngine::destruct(child); + return true; + } + params++; + } + TelEngine::destruct(child); + } + return false; +} + +static bool decodeEnumerated(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeEnumerated(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + int len = ASNLib::decodeLength(data); + if (len < 0) + return false; + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + + u_int8_t val = data[0]; + data.cut(-1); + if (param->content) { + const TokenDict* dict = static_cast(param->content); + if (!dict) + return false; + child->addText(lookup(val,dict,"")); + if (addEnc) + child->setAttribute(s_encAttr,"str"); + } + else { + child->addText(String(val)); + if (addEnc) + child->setAttribute(s_encAttr,"int"); + } + return true; +} + +static bool encodeEnumerated(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeEnumerated(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (param->content) { + const TokenDict* dict = static_cast(param->content); + if (!dict) + return false; + const String& text = elem->getText(); + u_int8_t val = lookup(text,dict,0); + if (val < 0) { + err = TcapXApplication::UnexpectedDataValue; + return false; + } + data.append(&val,sizeof(val)); + } + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static bool decodeBitString(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeBitString(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + if (addEnc) + child->setAttribute(s_encAttr,"str"); + + String val, str; + int value = 0; + ASNLib::decodeBitString(data,&val,false); + for (unsigned int i = 0; i < val.length(); i++) { + char c = val[1]; + if (c == '1') { + int mask = 1 << i; + value |= mask; + } + } + if (param->content) { + const TokenDict* dict = static_cast(param->content); + if (!dict) + return true; + while (dict->token){ + if ((dict->value & value) == dict->value) + str.append(dict->token,","); + dict++; + } + } + child->addText(str); + return true; +} + +static bool encodeBitString(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeBitString(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (param->content) { + const TokenDict* dict = static_cast(param->content); + String val; + int value = 0; + if (dict) { + const String& text = elem->getText(); + ObjList* list = text.split(',',false); + while(dict->token){ + if (list->find(dict->token)) + value |= dict->value; + dict++; + } + TelEngine::destruct(list); + } + + int size = sizeof(value) * 8; + bool start = false; + while (size > 0) { + size--; + u_int8_t b = (value >> size) & 0x01; + if (b == 1 && !start) + start = true; + if (start) + val = (b == 1? "1" : "0") + val; + } + + data.append(ASNLib::encodeBitString(val,false)); + } + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static void decodeGSM7Bit(DataBlock& data, int& len, String& decoded) +{ + u_int8_t bits = 0; + for (int i = 0; i < len; i++) { + if (bits == 8) + bits = 1; + char c = (data[i] << bits) & 0x7f; + if (i > 0) + c |= data[i - 1] >> (8 - bits); + decoded << c; + bits++; + } + data.cut(-len); +} + +static bool decodeGSMString(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeGSMString(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length()); + + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + int len = ASNLib::decodeLength(data); + if (len < 0) + return false; + + // TODO - should check Encoding Scheme at some point as also translation tables + XmlElement* enc = new XmlElement(param->name); + parent->addChild(enc); + if (addEnc) + enc->setAttribute(s_encAttr,"str"); + String str; + decodeGSM7Bit(data,len,str); + enc->addText(str); + return true; +} + +static void encodeGSM7Bit(const String& str, DataBlock& db) +{ + if (!str.length()) + return; + u_int8_t bits = 0; + for (unsigned int i = 0; i < str.length(); i++) { + if (bits == 7) { + bits = 0; + continue; + } + u_int8_t byte = 0x00; + byte |= (str[i] & 0x7f) >> bits; + if (i < str.length() - 1) + byte |= str[i + 1] << (7 - bits); + db.append(&byte,sizeof(byte)); + bits++; + } +} + +static bool encodeGSMString(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + + XDebug(&__plugin,DebugAll,"encodeGSMString(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + if (elem->getTag() != param->name) + return false; + + const String& str = elem->getText(); + encodeGSM7Bit(str,data); + + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static bool decodeFlags(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeFlags(param=%s[%p],elem=%s[%p],datalen=%d, data[0]=%d)",param->name.c_str(),param, + parent->getTag().c_str(),parent,data.length(),data[0]); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + int len = ASNLib::decodeLength(data); + if (len <= 0) + return false; + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + + if (addEnc) + child->setAttribute(s_encAttr,"str"); + + u_int8_t flags = data[0]; + String str; + if (param->content) { + const SignallingFlags* list = static_cast(param->content); + if (!list) + return false; + for (; list->mask; list++) { + if ((flags & list->mask) == list->value) + str.append(list->name,","); + } + } + data.cut(-len); + child->addText(str); + return true; +} + +static bool encodeFlags(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + + XDebug(&__plugin,DebugAll,"encodeFlags(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + u_int8_t byte = 0; + if (param->content) { + const SignallingFlags* flags = static_cast(param->content); + if (!flags) + return false; + const String& text = elem->getText(); + ObjList* list = text.split(',',false); + + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + String* s = static_cast(o->get()); + const SignallingFlags* flag = flags; + for (; flag->mask && *s != flag->name; flag++); + if (!flag->name) { + DDebug(&__plugin,DebugAll,"encodeFlags '%s' not found",s->c_str()); + continue; + } + byte |= flag->value; + } + TelEngine::destruct(list); + } + data.append(&byte,sizeof(byte)); + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static bool decodeString(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeString(param=%s[%p],elem=%s[%p],datalen=%d, data[0]=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length(),data[0]); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + String value; + int t = 0; + int len = ASNLib::decodeString(data,&value,&t,false); + if (len <= 0) + return false; + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + child->addText(value); + if (addEnc) + child->setAttribute(s_encAttr,"str"); + return true; +} + +static bool encodeString(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + + XDebug(&__plugin,DebugAll,"encodeString(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + const String& text = elem->getText(); + data.append(ASNLib::encodeString(text,ASNLib::PRINTABLE_STR,false)); + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +static bool decodeBool(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeBool(param=%s[%p],elem=%s[%p],datalen=%d, data[0]=%d)",param->name.c_str(),param,parent->getTag().c_str(), + parent,data.length(),data[0]); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + bool value = false; + int len = ASNLib::decodeBoolean(data,&value,false); + if (len <= 0) + return false; + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + child->addText(String::boolText(value)); + if (addEnc) + child->setAttribute(s_encAttr,"bool"); + return true; +} + +static bool encodeBool(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeBool(param=%s[%p],elem=%s[%p])",param->name.c_str(),param,elem->getTag().c_str(),elem); + + bool val = elem->getText().toBoolean(); + data.append(ASNLib::encodeBoolean(val,false)); + if (param->tag != s_noTag) { + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + } + return true; +} + +// Nature of Address Indicator +static const TokenDict s_dict_nai[] = { + { "subscriber", 1 }, + { "unknown", 2 }, + { "national", 3 }, + { "international", 4 }, + { "network-specific", 5 }, + { "national-routing", 6 }, + { "specific-routing", 7 }, + { "routing-with-cdn", 8 }, + { 0, 0 } +}; + +// Numbering Plan Indicator +static const TokenDict s_dict_numPlanIsup[] = { + { "unknown", 0 }, + { "isdn", 1 }, + { "data", 3 }, + { "telex", 4 }, + { "private", 5 }, + { "national", 6 }, + { 0, 0 } +}; + +// Address Presentation +static const TokenDict s_dict_presentation[] = { + { "allowed", 0 }, + { "restricted", 1 }, + { "unavailable", 2 }, + // aliases for restrict=... + { "no", 0 }, + { "false", 0 }, + { "yes", 1 }, + { "true", 1 }, + { 0, 0 } +}; + +// Screening Indicator +static const TokenDict s_dict_screening[] = { + { "user-provided", 0 }, + { "user-provided-passed", 1 }, + { "user-provided-failed", 2 }, + { "network-provided", 3 }, + // aliases for screened=... + { "no", 0 }, + { "false", 0 }, + { "yes", 1 }, + { "true", 1 }, + { 0, 0 } +}; + +// Generic number qualifier +static const TokenDict s_dict_qual[] = { + { "dialed-digits", 0 }, + { "called-additional", 1 }, + { "caller-failed", 2 }, + { "caller-not-screened", 3 }, + { "terminating", 4 }, + { "connected-additional", 5 }, + { "caller-additional", 6 }, + { "called-original", 7 }, + { "redirecting", 8 }, + { "redirection", 9 }, + { 0, 0 } +}; + +// Utility function - extract just ISUP digits from a parameter +static void getDigits(String& num, bool odd, const unsigned char* buf, unsigned int len) +{ + static const char digits[] = "0123456789ABCD?."; + for (unsigned int i = 0; i < len; i++) { + num += digits[buf[i] & 0x0f]; + if (odd && ((i+1) == len)) + break; + num += digits[buf[i] >> 4]; + } +} + +// Utility function - write digit sequences +static void setDigits(DataBlock& data, const char* val, unsigned char nai, int b2 = -1, int b0 = -1) +{ + unsigned char buf[32]; + unsigned int len = 0; + if (b0 >= 0) + buf[len++] = b0 & 0xff; + unsigned int naiPos = len++; + buf[naiPos] = nai & 0x7f; + if (b2 >= 0) + buf[len++] = b2 & 0xff; + + bool odd = false; + while (val && (len < sizeof(buf))) { + char c = *val++; + if (!c) + break; + unsigned char n = 0; + if (('0' <= c) && (c <= '9')) + n = c - '0'; + else if ('.' == c) + n = 15; + else if ('A' == c) + n = 10; + else if ('B' == c) + n = 11; + else if ('C' == c) + n = 12; + else if ('D' == c) + n = 13; + else + continue; + odd = !odd; + if (odd) + buf[len] = n; + else + buf[len++] |= (n << 4); + } + if (odd) { + buf[naiPos] |= 0x80; + len++; + } + XDebug(&__plugin,DebugAll,"setDigits encoding %u octets (%s)",len,odd ? "odd" : "even"); + data.append(buf,len); +} + +static bool decodeCallNumber(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, + XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeCallNumber(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + parent->getTag().c_str(),parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + int len = ASNLib::decodeLength(data); + if (len < 2) + return false; + unsigned int index = 0; + unsigned char qualifier = 0; + if (type->type == TcapXApplication::GenericNumber) { + if (len < 3) + return false; + qualifier = data[index]; + index++; + } + bool odd = (data[index] & 0x80) == 1; + unsigned char nai = data[index] & 0x7f; + index++; + unsigned char plan = (data[index] >> 4) & 7; + unsigned char pres = (data[index] >> 2) & 3; + unsigned char scrn = data[index] & 3; + + if (type->type == TcapXApplication::GenericNumber) + child->setAttribute(s_qualifierAttr,lookup(qualifier,s_dict_qual,"unknown")); + child->setAttribute(s_natureAttr,lookup(nai,s_dict_nai,"unknown")); + child->setAttribute(s_planAttr,lookup(plan,s_dict_numPlanIsup,"unknown")); + if (plan == 1) + child->setAttribute(s_encAttr,"e164"); + + String tmp; + switch (type->type) { + case TcapXApplication::CalledPartyNumber: + case TcapXApplication::LocationNumber: + tmp = ((data[index] & 0x80) == 0); + child->setAttribute(s_innAttr,tmp); + break; + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::GenericNumber: + tmp = ((data[index] & 0x80) == 0); + child->setAttribute(s_completeAttr,tmp); + break; + default: + break; + } + switch (type->type) { + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::RedirectingNumber: + case TcapXApplication::OriginalCalledNumber: + case TcapXApplication::LocationNumber: + case TcapXApplication::GenericNumber: + child->setAttribute(s_restrictAttr,lookup(pres,s_dict_presentation)); + default: + break; + } + switch (type->type) { + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::LocationNumber: + case TcapXApplication::GenericNumber: + child->setAttribute(s_screenedtAttr,lookup(scrn,s_dict_screening)); + default: + break; + } + + index++; + String digits; + getDigits(digits,odd,data.data(index,len - index),len - index); + + data.cut(-len); + child->addText(digits); + return true; +} + +static bool encodeCallNumber(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeCallNumber(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + elem->getTag().c_str(),elem,data.length()); + + unsigned char nai = lookup(elem->attribute(s_natureAttr),s_dict_nai,2) & 0x7f; + unsigned char plan = lookup(elem->attribute(s_planAttr),s_dict_numPlanIsup,1); + + int b0 = -1; + if (type->type == TcapXApplication::GenericNumber) { + b0 = 0; + b0 = 0xff & (lookup(elem->attribute(s_qualifierAttr),s_dict_presentation)); + } + + // Numbering plan + unsigned char b2 = (plan & 7) << 4; + + switch (type->type) { + case TcapXApplication::CalledPartyNumber: + case TcapXApplication::LocationNumber: + if (!TelEngine::null(elem->getAttribute(s_innAttr)) && !elem->getAttribute(s_innAttr)->toBoolean(true)) + b2 |= 0x80; + break; + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::GenericNumber: + if (!TelEngine::null(elem->getAttribute(s_completeAttr)) && !elem->getAttribute(s_completeAttr)->toBoolean(true)) + b2 |= 0x80; + break; + default: + break; + } + switch (type->type) { + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::RedirectingNumber: + case TcapXApplication::OriginalCalledNumber: + case TcapXApplication::LocationNumber: + case TcapXApplication::GenericNumber: + b2 |= (lookup(elem->attribute(s_restrictAttr),s_dict_presentation) & 3) << 2; + default: + break; + } + switch (param->type) { + case TcapXApplication::CallingPartyNumber: + case TcapXApplication::LocationNumber: + case TcapXApplication::GenericNumber: + b2 |= (lookup(elem->attribute(s_screenedtAttr),s_dict_screening) & 3); + default: + break; + } + const String& digits = elem->getText(); + setDigits(data,digits,nai,b2,b0); + + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + + +// Redirection Information (Q,763 3.45) bits CBA +static const TokenDict s_dict_redir_main[] = { + { "none", 0 }, + { "rerouted", 1 }, + { "rerouted-restrict-all", 2 }, + { "diverted", 3 }, + { "diverted-restrict-all", 4 }, + { "rerouted-restrict-number", 5 }, + { "diverted-restrict-number", 6 }, + { 0, 0 } +}; + +// Redirection Information (Q,763 3.45) bits HGFE or PONM +static const TokenDict s_dict_redir_reason[] = { + { "busy", 1 }, + { "noanswer", 2 }, + { "always", 3 }, + { "deflected", 4 }, + { "diverted", 5 }, + { "offline", 6 }, + { 0, 0 } +}; + +static const String s_reasonOrigAttr = "reason_original"; +static const String s_counterAttr = "counter"; +static const String s_reasonAttr = "reason"; + +static bool decodeRedir(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, + XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeRedir(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + parent->getTag().c_str(),parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + int len = ASNLib::decodeLength(data); + if (len < 1) + return false; + + // Redirecting indicator + unsigned char reason = data[0] & 0x07; + child->addText(lookup(reason,s_dict_redir_main,"")); + + // Original reason + reason = data[0] >> 4; + child->setAttribute(s_reasonOrigAttr,lookup(reason,s_dict_redir_reason)); + + if (len > 1) { + // Counter + int count = data[1] & 0x07; + if (count) + child->setAttribute(s_counterAttr,String(count)); + // Reason + reason = data[1] >> 4; + if (reason) + child->setAttribute(s_reasonAttr,lookup(reason,s_dict_redir_reason)); + } + if (addEnc) + child->setAttribute(s_encAttr,"str"); + data.cut(-len); + return true; +} + +static bool encodeRedir(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodeCallNumber(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + elem->getTag().c_str(),elem,data.length()); + + unsigned char b0 = lookup(elem->getText(),s_dict_redir_main,0) & 0x07; + b0 |= (lookup(elem->attribute(s_reasonOrigAttr),s_dict_redir_reason,0) & 0x0f) << 4; + data.append(&b0,sizeof(b0)); + + unsigned char b1 = String(elem->attribute(s_counterAttr)).toInteger() & 0x07; + b1 |= (lookup(elem->attribute(s_reasonAttr),s_dict_redir_reason,0) & 0x0f) << 4; + data.append(&b1,sizeof(b1)); + + data.insert(ASNLib::buildLength(data)); + data.insert(param->tag.coding()); + return true; +} + +// Coding standard as defined in Q.931/Q.850 +static const TokenDict s_dict_codingStandard[] = { + {"CCITT", 0x00}, + {"ISO/IEC", 0x20}, + {"national", 0x40}, + {"network specific", 0x60}, + {0,0} +}; + +// Q.931 4.5.5. Information transfer capability: Bits 0-4 +// Defined for CCITT coding standard +static const TokenDict s_dict_transferCapCCITT[] = { + {"speech", 0x00}, // Speech + {"udi", 0x08}, // Unrestricted digital information + {"rdi", 0x09}, // Restricted digital information + {"3.1khz-audio", 0x10}, // 3.1 khz audio + {"udi-ta", 0x11}, // Unrestricted digital information with tone/announcements + {"video", 0x18}, // Video + {0,0} +}; + +// Q.931 4.5.5. Transfer mode: Bits 5,6 +// Defined for CCITT coding standard +static const TokenDict s_dict_transferModeCCITT[] = { + {"circuit", 0x00}, // Circuit switch mode + {"packet", 0x40}, // Packet mode + {0,0} +}; + +// Q.931 4.5.5. Transfer rate: Bits 0-4 +// Defined for CCITT coding standard +static const TokenDict s_dict_transferRateCCITT[] = { + {"packet", 0x00}, // Packet mode only + {"64kbit", 0x10}, // 64 kbit/s + {"2x64kbit", 0x11}, // 2x64 kbit/s + {"384kbit", 0x13}, // 384 kbit/s + {"1536kbit", 0x15}, // 1536 kbit/s + {"1920kbit", 0x17}, // 1920 kbit/s + {"multirate", 0x18}, // Multirate (64 kbit/s base rate) + {0,0} +}; + +// Q.931 4.5.5. User information Layer 1 protocol: Bits 0-4 +// Defined for CCITT coding standard +static const TokenDict s_dict_formatCCITT[] = { + {"v110", 0x01}, // Recomendation V.110 and X.30 + {"mulaw", 0x02}, // Recomendation G.711 mu-law + {"alaw", 0x03}, // Recomendation G.711 A-law + {"g721", 0x04}, // Recomendation G.721 32kbit/s ADPCM and I.460 + {"h221", 0x05}, // Recomendation H.221 and H.242 + {"non-CCITT", 0x07}, // Non CCITT standardized rate adaption + {"v120", 0x08}, // Recomendation V.120 + {"x31", 0x09}, // Recomendation X.31 HDLC flag stuffing + {0,0} +}; + +static const String s_codingAttr = "coding"; +static const String s_transferCapAttr = "transfercap"; +static const String s_transferModeAttr = "transfermode"; +static const String s_transferRateAttr = "transferrate"; +static const String s_multiplierAttr = "multiplier"; + +static bool decodeUSI(const Parameter* param, MapCamelType* type, AsnTag& tag, DataBlock& data, + XmlElement* parent, bool addEnc, int& err) +{ + if (!(param && type && data.length() && parent)) + return false; + XDebug(&__plugin,DebugAll,"decodeUSI(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + parent->getTag().c_str(),parent,data.length()); + if (param->tag != tag) + return false; + data.cut(-tag.coding().length()); + + XmlElement* child = new XmlElement(param->name); + parent->addChild(child); + int len = ASNLib::decodeLength(data); + if (len < 2) + return false; + + // Byte 0: Coding standard (bit 5,6), Information transfer capability (bit 0-4) + // Byte 1: Transfer mode (bit 5,6), Transfer rate (bit 0-4) + unsigned char coding = data[0] & 0x60; + child->setAttribute(s_codingAttr,lookup(coding,s_dict_codingStandard)); + coding = data[0] & 0x1f; + child->setAttribute(s_transferCapAttr,lookup(coding,s_dict_transferCapCCITT)); + coding = data[1] & 0x60; + child->setAttribute(s_transferModeAttr,lookup(coding,s_dict_transferModeCCITT)); + u_int8_t rate = data[1] & 0x1f; + child->setAttribute(s_transferRateAttr,lookup(rate,s_dict_transferRateCCITT)); + // Figure 4.11 Note 1: Next byte is the rate multiplier if the transfer rate is 'multirate' (0x18) + u_int8_t crt = 2; + if (rate == 0x18) { + if (len < 3) { + Debug(&__plugin,DebugMild,"decodeUSI(). Invalid length %u. No rate multiplier",len); + return false; + } + child->setAttribute(s_multiplierAttr,String(data[2] & 0x7f)); + crt = 3; + } + if (len <= crt) { + data.cut(-len); + return true; + } + + u_int8_t ident = (data[crt] & 0x60) >> 5; + if (ident != 1) { + Debug(&__plugin,DebugNote,"decodeUSI(). Invalid layer 1 ident %u",ident); + return true; + } + child->addText(lookup(data[crt] & 0x1f,s_dict_formatCCITT)); + + data.cut(-len); + return true; +} + +static bool encodeUSI(const Parameter* param, MapCamelType* type, DataBlock& data, XmlElement* elem, int& err) +{ + if (!(param && elem)) + return false; + XDebug(&__plugin,DebugAll,"encodUSI(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param, + elem->getTag().c_str(),elem,data.length()); + + u_int8_t buff[5] = {2,0x00,0x80,0x80,0x80}; + unsigned char coding = lookup(elem->attribute(s_codingAttr),s_dict_codingStandard,0); + unsigned char cap = lookup(elem->attribute(s_transferCapAttr),s_dict_transferCapCCITT,0); + unsigned char mode = lookup(elem->attribute(s_transferModeAttr),s_dict_transferModeCCITT,0); + unsigned char rate = lookup(elem->attribute(s_transferRateAttr),s_dict_transferRateCCITT,0x10); + + buff[1] = (coding & 0x60) | (cap & 0x1f); + buff[2] |= (mode & 0x60) | (rate & 0x1f); + if (rate == 0x18) { + buff[0] = 3; + rate = String(elem->attribute(s_multiplierAttr)).toInteger(); + buff[3] |= rate & 0x7f; + } + // User information layer data + // Bit 7 = 1, Bits 5,6 = layer (1), Bits 0-4: the value + int format = lookup(elem->getText(),s_dict_formatCCITT,-1); + if (format != -1) { + buff[buff[0] + 1] |= 0x20 | (((unsigned char)format) & 0x1f); + buff[0]++; + } + data.assign(buff,buff[0] + 1); + data.insert(param->tag.coding()); + return true; +} + +static const Capability s_mapCapab[] = { + {"LocationManagement", {"updateLocation", "cancelLocation", "purgeMS", "updateGprsLocation", "anyTimeInterrogation", ""}}, + {"Authentication", {"sendAuthenticationInfo", ""}}, + {"SubscriberData", {"insertSubscriberData", "deleteSubscriberData", "restoreData", ""}}, + {"Routing", {"sendRoutingInfoForGprs", "statusReport", ""}}, + {"VLR-Routing", {"provideRoamingNumber", ""}}, + {"TraceSubscriber", {"activateTraceMode", "deactivateTraceMode", ""}}, + {"Services", {"registerSS", "eraseSS", "activateSS", "deactivateSS", "interrogateSS", "registerPassword", "getPassword", + "processUnstructuredSS-Request", "unstructuredSS-Request", "unstructuredSS-Notify", ""}}, + {"Miscellaneous", {"sendIMSI", "readyForSM", "setReportingState", ""}}, + {"ErrorRecovery", {"reset", "forwardCheckSS-Indication", "failureReport", ""}}, + {"Charging", {""}}, + {"SMSC", {"alertServiceCentre", "sendRoutingInfoForSM", ""}}, + {0, {""}}, +}; + +static const AppCtxt s_mapAppCtxt[]= { + // Network Loc Up context + {"networkLocUpContext-v3", "0.4.0.0.1.0.1.3", "updateLocation,forwardCheckSs,restoreData,insertSubscriberData,activateTraceMode"}, + {"networkLocUpContext-v2", "0.4.0.0.1.0.1.2", "updateLocation,forwardCheckSs,restoreData,insertSubscriberData,activateTraceMode"}, + {"networkLocUpContext-v1", "0.4.0.0.1.0.1.1", "updateLocation,forwardCheckSs,sendParameters,insertSubscriberData,activateTraceMode"}, + + // Location Cancellation context + {"locationCancelationContext-v3", "0.4.0.0.1.0.2.3", "cancelLocation"}, + {"locationCancelationContext-v2", "0.4.0.0.1.0.2.2", "cancelLocation"}, + {"locationCancelationContext-v1", "0.4.0.0.1.0.2.1", "cancelLocation"}, + + // Roaming Number Enquiry Context + {"roamingNumberEnquiryContext-v3", "0.4.0.0.1.0.3.3", "provideRoamingNumber"}, + {"roamingNumberEnquiryContext-v2", "0.4.0.0.1.0.3.2", "provideRoamingNumber"}, + {"roamingNumberEnquiryContext-v1", "0.4.0.0.1.0.3.1", "provideRoamingNumber"}, + + // Location Info Retrieval Context + {"locationInfoRetrievalContext-v3", "0.4.0.0.1.0.5.3", "sendRoutingInfo"}, + {"locationInfoRetrievalContext-v2", "0.4.0.0.1.0.5.2", "sendRoutingInfo"}, + {"locationInfoRetrievalContext-v1", "0.4.0.0.1.0.5.1", "sendRoutingInfo"}, + + // Reporting Context + {"reportingContext-v3", "0.4.0.0.1.0.7.3", "setReportingState,statusReport,remoteUserFree"}, + + // Info retrieval context + {"infoRetrievalPackage-v3", "0.4.0.0.1.0.14.3", "sendAuthenticationInfo"}, + {"infoRetrievalContext-v2", "0.4.0.0.1.0.14.2", "sendAuthenticationInfo"}, + {"infoRetrievalContext-v1", "0.4.0.0.1.0.14.1", "sendParameters"}, + + // Subscriber Data Management Context + {"subscriberDataMngtContext-v3", "0.4.0.0.1.0.16.3", "insertSubscriberData,deleteSubscriberData"}, + {"subscriberDataMngtContext-v2", "0.4.0.0.1.0.16.2", "insertSubscriberData,deleteSubscriberData"}, + {"subscriberDataMngtContext-v1", "0.4.0.0.1.0.16.1", "insertSubscriberData,deleteSubscriberData"}, + + // Tracing context + {"tracingContext-v3 ", "0.4.0.0.1.0.17.3", "activateTraceMode,deactivateTraceMode"}, + {"tracingContext-v2 ", "0.4.0.0.1.0.17.2", "activateTraceMode,deactivateTraceMode"}, + {"tracingContext-v1 ", "0.4.0.0.1.0.17.1", "activateTraceMode,deactivateTraceMode"}, + + // Network functional SS context + {"networkFunctionalSsContext-v2", "0.4.0.0.1.0.18.2", "registerSS,eraseSS,activateSS,deactivateSS," + "interrogateSS,registerPassword,getPassword"}, + {"networkFunctionalSsContext-v1", "0.4.0.0.1.0.18.1", "registerSS,eraseSS,activateSS,deactivateSS," + "interrogateSS,registerPassword,getPassword"}, + // Network unstructured SS context + {"networkUnstructuredSsContext-v2", "0.4.0.0.1.0.19.2", "processUnstructuredSS-Request,unstructuredSS-Request,unstructuredSS-Notify"}, + {"networkUnstructuredSsContext-v1", "0.4.0.0.1.0.19.1", "processUnstructuredSS-Data"}, + + {"shortMsgGatewayContext-v3", "0.4.0.0.1.0.20.3", "sendRoutingInfoForSM"}, + {"shortMsgGatewayContext-v2", "0.4.0.0.1.0.20.2", "sendRoutingInfoForSM"}, + {"shortMsgGatewayContext-v1", "0.4.0.0.1.0.20.1", "sendRoutingInfoForSM"}, + + {"shortMsgAlertContext-v2", "0.4.0.0.1.0.23.2", "alertServiceCentre"}, + {"shortMsgAlertContext-v1", "0.4.0.0.1.0.23.1", "alertServiceCentre"}, + + // MS Purging Context + {"msPurgingContext-v3", "0.4.0.0.1.0.27.3", "purgeMS"}, + {"msPurgingContext-v2", "0.4.0.0.1.0.27.2", "purgeMS"}, + + // Any Time Info Enquiry Context + {"anyTimeInfoEnquiryContext-v3", "0.4.0.0.1.0.29.3", "anyTimeInterrogation"}, + + // GPRS Location Update Context + {"gprsLocationUpdateContext-v3", "0.4.0.0.1.0.32.3", "updateGprsLocation,insertSubscriberData,activateTraceMode"}, + + // GPRS Location Info Retrieval Context + {"gprsLocationInfoRetrievalContext-v3" , "0.4.0.0.1.0.33.3", "sendRoutingInfoForGprs"}, + + {"", "", ""}, +}; + +static const AppCtxt s_camelAppCtxt[] = { + {"CAP-v2-gsmSSF-to-gsmSCF-AC", "0.4.0.0.1.0.50.1", "initialDP,establishTemporaryConnection,connectToResource," + "disconnectForwardConnection,connect,releaseCall,eventReportBCSM," + "requestReportBCSMEvent,applyChargingReport,applyCharging,continue," + "resetTimer,furnishChargingInformation,callInformationReport," + "callInformationRequest,sendChargingInformation,specializedResourceReport," + "playAnnouncement,promptAndCollectUserInformation,cancel,activityTest"}, + + {"CAP-v2-assist-gsmSSF-to-gsmSCF-AC", "0.4.0.0.1.0.51.1", "assistRequestInstructions,disconnectForwardConnection,connectToResource," + "resetTimer,specializedResourceReport,playAnnouncement," + "promptAndCollectUserInformation,cancel,activityTest"}, + + {"CAP-v2-gsmSRF-to-gsmSCF-AC", "0.4.0.0.1.0.52.1", "assistRequestInstructions,specializedResourceReport,playAnnouncement," + "promptAndCollectUserInformation,cancel,activityTest"}, + + {"", "", ""} +}; + +static const MapCamelType s_types[] = { + {TcapXApplication::Null, TcapXApplication::NullEnc, decodeNull, encodeNull}, + {TcapXApplication::Integer, TcapXApplication::IntEnc, decodeInt, encodeInt}, + {TcapXApplication::OID, TcapXApplication::OIDEnc, decodeOID, encodeOID}, + {TcapXApplication::TBCD, TcapXApplication::StringEnc, decodeTBCD, encodeTBCD}, + {TcapXApplication::AddressString, TcapXApplication::TelephonyEnc, decodeTel, encodeTel}, + {TcapXApplication::HexString, TcapXApplication::HexEnc, decodeHex, encodeHex}, + {TcapXApplication::Sequence, TcapXApplication::NoEnc, decodeSeq, encodeSeq}, + {TcapXApplication::SequenceOf, TcapXApplication::NoEnc, decodeSeqOf, encodeSeqOf}, + // for now, use the same encoder/decoder as SequenceOf, TODO - if needed,replace it + {TcapXApplication::SetOf, TcapXApplication::NoEnc, decodeSeqOf, encodeSeqOf}, + {TcapXApplication::Choice, TcapXApplication::NoEnc, decodeChoice, encodeChoice}, + {TcapXApplication::Enumerated, TcapXApplication::NoEnc, decodeEnumerated, encodeEnumerated}, + {TcapXApplication::GSMString, TcapXApplication::StringEnc, decodeGSMString, encodeGSMString}, + {TcapXApplication::BitString, TcapXApplication::HexEnc, decodeBitString, encodeBitString}, + {TcapXApplication::Flags, TcapXApplication::StringEnc, decodeFlags, encodeFlags}, + {TcapXApplication::AppString, TcapXApplication::StringEnc, decodeString, encodeString}, + {TcapXApplication::Bool, TcapXApplication::BoolEnc, decodeBool, encodeBool}, + {TcapXApplication::CellIdFixedLength, TcapXApplication::StringEnc, decodeTBCD, encodeTBCD}, + {TcapXApplication::LAIFixedLength, TcapXApplication::StringEnc, decodeTBCD, encodeTBCD}, + {TcapXApplication::CalledPartyNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::CallingPartyNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::LocationNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::OriginalCalledNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::RedirectingNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::GenericNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::ChargeNumber, TcapXApplication::TelephonyEnc, decodeCallNumber, encodeCallNumber}, + {TcapXApplication::RedirectionInformation, TcapXApplication::StringEnc, decodeRedir, encodeRedir}, + {TcapXApplication::UserServiceInfo, TcapXApplication::NoEnc, decodeUSI, encodeUSI}, + // TODO High Layer Compatibility encode/decode implementation - see User teleservice information (Q.763 3.59) + {TcapXApplication::HiLayerCompat, TcapXApplication::NoEnc, decodeHex, encodeHex}, + {TcapXApplication::None, TcapXApplication::NoEnc, 0, 0}, +}; + + +static const MapCamelType* findType(TcapXApplication::ParamType type) +{ + const MapCamelType* t = s_types; + while (t->type != TcapXApplication::None) { + if (t->type == type) + return t; + t++; + } + return 0; +} + +static const AsnTag s_ctxtPrim_0_Tag(AsnTag::Context, AsnTag::Primitive, 0); +static const AsnTag s_ctxtPrim_1_Tag(AsnTag::Context, AsnTag::Primitive, 1); +static const AsnTag s_ctxtPrim_2_Tag(AsnTag::Context, AsnTag::Primitive, 2); +static const AsnTag s_ctxtPrim_3_Tag(AsnTag::Context, AsnTag::Primitive, 3); +static const AsnTag s_ctxtPrim_4_Tag(AsnTag::Context, AsnTag::Primitive, 4); +static const AsnTag s_ctxtPrim_5_Tag(AsnTag::Context, AsnTag::Primitive, 5); +static const AsnTag s_ctxtPrim_6_Tag(AsnTag::Context, AsnTag::Primitive, 6); +static const AsnTag s_ctxtPrim_7_Tag(AsnTag::Context, AsnTag::Primitive, 7); +static const AsnTag s_ctxtPrim_8_Tag(AsnTag::Context, AsnTag::Primitive, 8); +static const AsnTag s_ctxtPrim_9_Tag(AsnTag::Context, AsnTag::Primitive, 9); +static const AsnTag s_ctxtPrim_10_Tag(AsnTag::Context, AsnTag::Primitive, 10); +static const AsnTag s_ctxtPrim_11_Tag(AsnTag::Context, AsnTag::Primitive, 11); +static const AsnTag s_ctxtPrim_12_Tag(AsnTag::Context, AsnTag::Primitive, 12); +static const AsnTag s_ctxtPrim_13_Tag(AsnTag::Context, AsnTag::Primitive, 13); +static const AsnTag s_ctxtPrim_15_Tag(AsnTag::Context, AsnTag::Primitive, 15); +static const AsnTag s_ctxtPrim_16_Tag(AsnTag::Context, AsnTag::Primitive, 16); +static const AsnTag s_ctxtPrim_17_Tag(AsnTag::Context, AsnTag::Primitive, 17); +static const AsnTag s_ctxtPrim_18_Tag(AsnTag::Context, AsnTag::Primitive, 18); +static const AsnTag s_ctxtPrim_19_Tag(AsnTag::Context, AsnTag::Primitive, 19); +static const AsnTag s_ctxtPrim_20_Tag(AsnTag::Context, AsnTag::Primitive, 20); +static const AsnTag s_ctxtPrim_21_Tag(AsnTag::Context, AsnTag::Primitive, 21); +static const AsnTag s_ctxtPrim_23_Tag(AsnTag::Context, AsnTag::Primitive, 23); +static const AsnTag s_ctxtPrim_25_Tag(AsnTag::Context, AsnTag::Primitive, 25); +static const AsnTag s_ctxtPrim_27_Tag(AsnTag::Context, AsnTag::Primitive, 27); +static const AsnTag s_ctxtPrim_28_Tag(AsnTag::Context, AsnTag::Primitive, 28); +static const AsnTag s_ctxtPrim_29_Tag(AsnTag::Context, AsnTag::Primitive, 29); +static const AsnTag s_ctxtPrim_30_Tag(AsnTag::Context, AsnTag::Primitive, 30); +static const AsnTag s_ctxtPrim_50_Tag(AsnTag::Context, AsnTag::Primitive, 50); +static const AsnTag s_ctxtPrim_51_Tag(AsnTag::Context, AsnTag::Primitive, 51); +static const AsnTag s_ctxtPrim_52_Tag(AsnTag::Context, AsnTag::Primitive, 52); +static const AsnTag s_ctxtPrim_53_Tag(AsnTag::Context, AsnTag::Primitive, 53); +static const AsnTag s_ctxtPrim_54_Tag(AsnTag::Context, AsnTag::Primitive, 54); +static const AsnTag s_ctxtPrim_55_Tag(AsnTag::Context, AsnTag::Primitive, 55); +static const AsnTag s_ctxtPrim_56_Tag(AsnTag::Context, AsnTag::Primitive, 56); +static const AsnTag s_ctxtPrim_57_Tag(AsnTag::Context, AsnTag::Primitive, 57); +static const AsnTag s_ctxtPrim_58_Tag(AsnTag::Context, AsnTag::Primitive, 58); + +static const AsnTag s_ctxtCstr_0_Tag(AsnTag::Context, AsnTag::Constructor, 0); +static const AsnTag s_ctxtCstr_1_Tag(AsnTag::Context, AsnTag::Constructor, 1); +static const AsnTag s_ctxtCstr_2_Tag(AsnTag::Context, AsnTag::Constructor, 2); +static const AsnTag s_ctxtCstr_3_Tag(AsnTag::Context, AsnTag::Constructor, 3); +static const AsnTag s_ctxtCstr_4_Tag(AsnTag::Context, AsnTag::Constructor, 4); +static const AsnTag s_ctxtCstr_5_Tag(AsnTag::Context, AsnTag::Constructor, 5); +static const AsnTag s_ctxtCstr_6_Tag(AsnTag::Context, AsnTag::Constructor, 6); +static const AsnTag s_ctxtCstr_7_Tag(AsnTag::Context, AsnTag::Constructor, 7); +static const AsnTag s_ctxtCstr_8_Tag(AsnTag::Context, AsnTag::Constructor, 8); +static const AsnTag s_ctxtCstr_9_Tag(AsnTag::Context, AsnTag::Constructor, 9); +static const AsnTag s_ctxtCstr_10_Tag(AsnTag::Context, AsnTag::Constructor, 10); +static const AsnTag s_ctxtCstr_11_Tag(AsnTag::Context, AsnTag::Constructor, 11); +static const AsnTag s_ctxtCstr_12_Tag(AsnTag::Context, AsnTag::Constructor, 12); +static const AsnTag s_ctxtCstr_13_Tag(AsnTag::Context, AsnTag::Constructor, 13); +static const AsnTag s_ctxtCstr_14_Tag(AsnTag::Context, AsnTag::Constructor, 14); +static const AsnTag s_ctxtCstr_15_Tag(AsnTag::Context, AsnTag::Constructor, 15); +static const AsnTag s_ctxtCstr_16_Tag(AsnTag::Context, AsnTag::Constructor, 16); +static const AsnTag s_ctxtCstr_21_Tag(AsnTag::Context, AsnTag::Constructor, 21); +static const AsnTag s_ctxtCstr_22_Tag(AsnTag::Context, AsnTag::Constructor, 22); +static const AsnTag s_ctxtCstr_23_Tag(AsnTag::Context, AsnTag::Constructor, 23); +static const AsnTag s_ctxtCstr_24_Tag(AsnTag::Context, AsnTag::Constructor, 24); +static const AsnTag s_ctxtCstr_25_Tag(AsnTag::Context, AsnTag::Constructor, 25); +static const AsnTag s_ctxtCstr_27_Tag(AsnTag::Context, AsnTag::Constructor, 27); +static const AsnTag s_ctxtCstr_28_Tag(AsnTag::Context, AsnTag::Constructor, 28); +static const AsnTag s_ctxtCstr_29_Tag(AsnTag::Context, AsnTag::Constructor, 29); +static const AsnTag s_ctxtCstr_30_Tag(AsnTag::Context, AsnTag::Constructor, 30); +static const AsnTag s_ctxtCstr_50_Tag(AsnTag::Context, AsnTag::Constructor, 50); +static const AsnTag s_ctxtCstr_57_Tag(AsnTag::Context, AsnTag::Constructor, 57); +static const AsnTag s_ctxtCstr_59_Tag(AsnTag::Context, AsnTag::Constructor, 59); + +static const TokenDict s_camelPhases[] = { + {"phase1", 1}, + {"phase2", 2}, + {0,0}, +}; + +static const Parameter s_vlrCapability[] = { + {"supportedCamelPhases", s_ctxtPrim_0_Tag, true, TcapXApplication::BitString, s_camelPhases}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"solsaSupportIndicator", s_nullTag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_imsiWithLmsi[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"lmsi", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_mapIdentity[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"imsi-WithLMSI", s_sequenceTag, false, TcapXApplication::Sequence, s_imsiWithLmsi}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_cancellationType[] = { + {"updateProcedure", 0x00}, + {"subscriptionWithdraw", 0x01}, + {0,0}, +}; + +static const TokenDict s_protocolId[] = { + {"gsm-0408", 0x01}, + {"gsm-0806", 0x02}, + {"gsm-BSSMAP", 0x03}, + {"ets-300102-1",0x04}, + {0,0}, +}; + +static const Parameter s_externalSignalInfo[] = { + {"protocolId", s_enumTag, false, TcapXApplication::Enumerated, s_protocolId}, + {"signalInfo", s_hexTag, false, TcapXApplication::HexString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_alertPattern[] = { + {"alertingLevel-0", 0x00}, + {"alertingLevel-1", 0x01},// AlertingPattern ::= '00000001'B + {"alertingLevel-2", 0x02},// AlertingPattern ::= '00000010'B + {"alertingCategory-1", 0x04},// AlertingPattern ::= '00000100'B + {"alertingCategory-2", 0x05},// AlertingPattern ::= '00000101'B + {"alertingCategory-3", 0x06},// AlertingPattern ::= '00000110'B + {"alertingCategory-4", 0x07},// AlertingPattern ::= '00000111'B + {"alertingCategory-5", 0x08},// AlertingPattern ::= '00001000'B + {0,0}, +}; + +static const TokenDict s_extProtocolId[] = { + {"ets-300356", 0x01}, + {0,0}, +}; + +static const Parameter s_extExtenalSignalInfo[] = { + {"ext-protocolId", s_enumTag, false, TcapXApplication::Enumerated, s_extProtocolId}, + {"signalInfo", s_hexTag, false, TcapXApplication::HexString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_category[] = { + { "unknown", 0x00 }, // calling party's category is unknown + { "operator-FR", 0x01 }, // operator, language French + { "operator-EN", 0x02 }, // operator, language English + { "operator-DE", 0x03 }, // operator, language German + { "operator-RU", 0x04 }, // operator, language Russian + { "operator-ES", 0x05 }, // operator, language Spanish + { "ordinary", 0x0a }, // ordinary calling subscriber + { "priority", 0x0b }, // calling subscriber with priority + { "data", 0x0c }, // data call (voice band data) + { "test", 0x0d }, // test call + { "payphone", 0x0f }, // payphone + { 0, 0 }, +}; + +static const TokenDict s_subscriberStatus[] = { + {"serviceGranted", 0x00}, + {"operatorDeterminedBarring", 0x01}, + {0,0}, +}; + +static const TokenDict s_SSCode[] = { +// TS 100 974 v7.15.0 page 321 + {"allSS", 0x00}, // SS-Code ::= '00000000'B -- all SS + {"allLineIdentificationSS", 0x10}, // SS-Code ::= '00010000'B -- all line identification SS + {"clip", 0x11}, // SS-Code ::= '00010001'B -- calling line identification presentation + {"clir", 0x12}, // SS-Code ::= '00010010'B -- calling line identification restriction + {"colp", 0x13}, // SS-Code ::= '00010011'B -- connected line identification presentation + {"colr", 0x14}, // SS-Code ::= '00010100'B -- connected line identification restriction + {"mci", 0x15}, // SS-Code ::= '00010101'B -- malicious call identification + {"allNameIdentificationSS", 0x18}, // SS-Code ::= '00011000'B -- all name identification SS + {"cnap", 0x19}, // SS-Code ::= '00011001'B -- calling name presentation + {"allForwardingSS", 0x20}, // SS-Code ::= '00100000'B -- all forwarding SS + {"cfu", 0x21}, // SS-Code ::= '00100001'B -- call forwarding unconditional + {"allCondForwardingSS", 0x28}, // SS-Code ::= '00101000'B -- all conditional forwarding SS + {"cfb", 0x29}, // SS-Code ::= '00101001'B -- call forwarding on mobile subscriber busy + {"cfnry", 0x2a}, // SS-Code ::= '00101010'B -- call forwarding on no reply + {"cfnrc", 0x2b}, // SS-Code ::= '00101011'B -- call forwarding on mobile subscriber not reachable + {"cd", 0x24}, // SS-Code ::= '00100100'B -- call deflection + {"allCallOfferingSS", 0x30}, // SS-Code ::= '00110000'B -- all call offering SS includes also all forwarding SS + {"ect", 0x31}, // SS-Code ::= '00110001'B -- explicit call transfer + {"mah", 0x32}, // SS-Code ::= '00110010'B -- mobile access hunting + {"allCallCompletionSS", 0x40}, // SS-Code ::= '01000000'B -- all Call completion SS + {"cw", 0x41}, // SS-Code ::= '01000001'B -- call waiting + {"hold", 0x42}, // SS-Code ::= '01000010'B -- call hold + {"ccbs-A", 0x43}, // SS-Code ::= '01000011'B -- completion of call to busy subscribers, originating side + {"ccbs-B", 0x44}, // SS-Code ::= '01000100'B -- completion of call to busy subscribers, destination side + {"allMultiPartySS", 0x50}, // SS-Code ::= '01010000'B -- all multiparty SS + {"multiPTY", 0x51}, // SS-Code ::= '01010001'B -- multiparty + {"allCommunityOfInterest-SS", 0x60}, // SS-Code ::= '01100000'B -- all community of interest SS + {"cug", 0x61}, // SS-Code ::= '01100001'B -- closed user group + {"allChargingSS", 0x70}, // SS-Code ::= '01110000'B -- all charging SS + {"aoci", 0x71}, // SS-Code ::= '01110001'B -- advice of charge information + {"aocc", 0x72}, // SS-Code ::= '01110010'B -- advice of charge charging + {"allAdditionalInfoTransferSS",0x80}, // SS-Code ::= '10000000'B -- all additional information transfer SS + {"uus1", 0x81}, // SS-Code ::= '10000001'B -- UUS1 user-to-user signalling + {"uus2", 0x82}, // SS-Code ::= '10000010'B -- UUS2 user-to-user signalling + {"uus3", 0x83}, // SS-Code ::= '10000011'B -- UUS3 user-to-user signalling + {"allBarringSS", 0x90}, // SS-Code ::= '10010000'B -- all barring SS + {"barringOfOutgoingCalls", 0x91}, // SS-Code ::= '10010001'B -- barring of outgoing calls + {"baoc", 0x92}, // SS-Code ::= '10010010'B -- barring of all outgoing calls + {"boic", 0x93}, // SS-Code ::= '10010011'B -- barring of outgoing international calls + {"boicExHC", 0x94}, // SS-Code ::= '10010100'B -- barring of outgoing international calls except those directed to the home PLMN + {"barringOfIncomingCalls", 0x99}, // SS-Code ::= '10011001'B -- barring of incoming calls + {"baic", 0x9a}, // SS-Code ::= '10011010'B -- barring of all incoming calls + {"bicRoam", 0x24}, // SS-Code ::= '10011011'B -- barring of incoming calls when roaming outside home PLMN Country + {"allPLMN-specificSS", 0xf0}, // SS-Code ::= '11110000'B + {"plmn-specificSS-1", 0xf1}, // SS-Code ::= '11110001'B + {"plmn-specificSS-2", 0xf2}, // SS-Code ::= '11110010'B + {"plmn-specificSS-3", 0xf3}, // SS-Code ::= '11110011'B + {"plmn-specificSS-4", 0xf4}, // SS-Code ::= '11110100'B + {"plmn-specificSS-5", 0xf5}, // SS-Code ::= '11110101'B + {"plmn-specificSS-6", 0xf6}, // SS-Code ::= '11110110'B + {"plmn-specificSS-7", 0xf7}, // SS-Code ::= '11110111'B + {"plmn-specificSS-8", 0xf8}, // SS-Code ::= '11111000'B + {"plmn-specificSS-9", 0xf9}, // SS-Code ::= '11111001'B + {"plmn-specificSS-A", 0xfa}, // SS-Code ::= '11111010'B + {"plmn-specificSS-B", 0xfb}, // SS-Code ::= '11111011'B + {"plmn-specificSS-C", 0xfc}, // SS-Code ::= '11111100'B + {"plmn-specificSS-D", 0xfd}, // SS-Code ::= '11111101'B + {"plmn-specificSS-E", 0xfe}, // SS-Code ::= '11111110'B + {"plmn-specificSS-F", 0xff}, // SS-Code ::= '11111111'B + {"allCallPrioritySS", 0xa0}, // SS-Code ::= '10100000'B -- all call priority SS + {"emlpp", 0xa1}, // SS-Code ::= '10100001'B -- enhanced Multilevel Precedence Pre-emption (EMLPP) service + {"allLCSPrivacyException", 0xb0}, // SS-Code ::= '10110000'B -- all LCS Privacy Exception Classes + {"universal", 0xb1}, // SS-Code ::= '10110001'B -- allow location by any LCS client + {"callrelated", 0xb2}, // SS-Code ::= '10110010'B -- allow location by any value added LCS client to which a call +// -- is established from the target MS + {"callunrelated", 0xb3}, // SS-Code ::= '10110011'B -- allow location by designated external value added LCS clients + {"plmnoperator", 0xb4}, // SS-Code ::= '10110100'B -- allow location by designated PLMN operator LCS clients + {"allMOLR-SS", 0xc0}, // SS-Code ::= '11000000'B -- all Mobile Originating Location Request Classes + {"basicSelfLocation", 0xc1}, // SS-Code ::= '11000001'B -- allow an MS to request its own location + {"autonomousSelfLocation", 0xc2}, // SS-Code ::= '11000010'B -- allow an MS to perform self location without interaction +// -- with the PLMN for a predetermined period of time + {"transferToThirdParty", 0xc3}, // SS-Code ::= '11000011'B -- allow an MS to request transfer of its location to another LCS client + {0,0}, +}; + +static const TokenDict s_bearerServiceCode[] = { + {"allBearerServices", 0x00}, // BearerServiceCode ::= '00000000'B + {"allDataCDA-Services", 0x10}, // BearerServiceCode ::= '00010000'B + {"dataCDA-300bps", 0x11}, // BearerServiceCode ::= '00010001'B + {"dataCDA-1200bps", 0x12}, // BearerServiceCode ::= '00010010'B + {"dataCDA-1200-75bps", 0x13}, // BearerServiceCode ::= '00010011'B + {"dataCDA-2400bps", 0x14}, // BearerServiceCode ::= '00010100'B + {"dataCDA-4800bps", 0x15}, // BearerServiceCode ::= '00010101'B + {"dataCDA-9600bps", 0x16}, // BearerServiceCode ::= '00010110'B + {"general-dataCDA", 0x17}, // BearerServiceCode ::= '00010111'B + {"allDataCDS-Services", 0x18}, // BearerServiceCode ::= '00011000'B + {"dataCDS-1200bps", 0x1a}, // BearerServiceCode ::= '00011010'B + {"dataCDS-2400bps", 0x1c}, // BearerServiceCode ::= '00011100'B + {"dataCDS-4800bps", 0x1d}, // BearerServiceCode ::= '00011101'B + {"dataCDS-9600bps", 0x1e}, // BearerServiceCode ::= '00011110'B + {"general-dataCDS", 0x1f}, // BearerServiceCode ::= '00011111'B + {"allPadAccessCA-Services",0x20}, // BearerServiceCode ::= '00100000'B + {"padAccessCA-300bps", 0x21}, // BearerServiceCode ::= '00100001'B + {"padAccessCA-1200bps", 0x22}, // BearerServiceCode ::= '00100010'B + {"padAccessCA-1200-75bps", 0x23}, // BearerServiceCode ::= '00100011'B + {"padAccessCA-2400bps", 0x24}, // BearerServiceCode ::= '00100100'B + {"padAccessCA-4800bps", 0x25}, // BearerServiceCode ::= '00100101'B + {"padAccessCA-9600bps", 0x26}, // BearerServiceCode ::= '00100110'B + {"general-padAccessCA", 0x27}, // BearerServiceCode ::= '00100111'B + {"allDataPDS-Services", 0x28}, // BearerServiceCode ::= '00101000'B + {"dataPDS-2400bps", 0x2c}, // BearerServiceCode ::= '00101100'B + {"dataPDS-4800bps", 0x2d}, // BearerServiceCode ::= '00101101'B + {"dataPDS-9600bps", 0x2e}, // BearerServiceCode ::= '00101110'B + {"general-dataPDS", 0x2f}, // BearerServiceCode ::= '00101111'B + + {"allAlternateSpeech-DataCDA", 0x30}, // BearerServiceCode ::= '00110000'B + {"allAlternateSpeech-DataCDS", 0x38}, // BearerServiceCode ::= '00111000'B + {"allSpeechFollowedByDataCDA", 0x40}, // BearerServiceCode ::= '01000000'B + {"allSpeechFollowedByDataCDS", 0x48}, // BearerServiceCode ::= '01001000'B + {"allDataCircuitAsynchronous", 0x50}, // BearerServiceCode ::= '01010000'B + {"allAsynchronousServices", 0x60}, // BearerServiceCode ::= '01100000'B + {"allDataCircuitSynchronous", 0x58}, // BearerServiceCode ::= '01011000'B + {"allSynchronousServices", 0x68}, // BearerServiceCode ::= '01101000'B + + {"allPLMN-specificBS", 0xd0}, // BearerServiceCode ::= '11010000'B + {"plmn-specificBS-1", 0xd1}, // BearerServiceCode ::= '11010001'B + {"plmn-specificBS-2", 0xd2}, // BearerServiceCode ::= '11010010'B + {"plmn-specificBS-3", 0xd3}, // BearerServiceCode ::= '11010011'B + {"plmn-specificBS-4", 0xd4}, // BearerServiceCode ::= '11010100'B + {"plmn-specificBS-5", 0xd5}, // BearerServiceCode ::= '11010101'B + {"plmn-specificBS-6", 0xd6}, // BearerServiceCode ::= '11010110'B + {"plmn-specificBS-7", 0xd7}, // BearerServiceCode ::= '11010111'B + {"plmn-specificBS-8", 0xd8}, // BearerServiceCode ::= '11011000'B + {"plmn-specificBS-9", 0xd9}, // BearerServiceCode ::= '11011001'B + {"plmn-specificBS-A", 0xda}, // BearerServiceCode ::= '11011010'B + {"plmn-specificBS-B", 0xdb}, // BearerServiceCode ::= '11011011'B + {"plmn-specificBS-C", 0xdc}, // BearerServiceCode ::= '11011100'B + {"plmn-specificBS-D", 0xdd}, // BearerServiceCode ::= '11011101'B + {"plmn-specificBS-E", 0xde}, // BearerServiceCode ::= '11011110'B + {"plmn-specificBS-F", 0xdf}, // BearerServiceCode ::= '11011111'B + {0,0}, +}; + +static const TokenDict s_teleserviceCode[] = { + {"allTeleservices", 0x00}, // TeleserviceCode ::= '00000000'B + {"allSpeechTransmissionServices", 0x10}, // TeleserviceCode ::= '00010000'B + {"telephony", 0x11}, // TeleserviceCode ::= '00010001'B + {"emergencyCalls", 0x12}, // TeleserviceCode ::= '00010010'B + {"allShortMessageServices", 0x20}, // TeleserviceCode ::= '00100000'B + {"shortMessageMT-PP", 0x21}, // TeleserviceCode ::= '00100001'B + {"shortMessageMO-PP", 0x22}, // TeleserviceCode ::= '00100010'B + {"allFacsimileTransmissionServices", 0x60}, // TeleserviceCode ::= '01100000'B + {"facsimileGroup3AndAlterSpeech", 0x61}, // TeleserviceCode ::= '01100001'B + {"automaticFacsimileGroup3", 0x62}, // TeleserviceCode ::= '01100010'B + {"facsimileGroup4", 0x63}, // TeleserviceCode ::= '01100011'B + {"allDataTeleservices", 0x70}, // TeleserviceCode ::= '01110000'B + {"allTeleservices-ExeptSMS", 0x80}, // TeleserviceCode ::= '10000000'B + {"allVoiceGroupCallServices", 0x90}, // TeleserviceCode ::= '10010000'B + {"voiceGroupCall", 0x91}, // TeleserviceCode ::= '10010001'B + {"voiceBroadcastCall", 0x92}, // TeleserviceCode ::= '10010010'B + {"allPLMN-specificTS", 0xd0}, // TeleserviceCode ::= '11010000'B + {"plmn-specificTS-1", 0xd1}, // TeleserviceCode ::= '11010001'B + {"plmn-specificTS-2", 0xd2}, // TeleserviceCode ::= '11010010'B + {"plmn-specificTS-3", 0xd3}, // TeleserviceCode ::= '11010011'B + {"plmn-specificTS-4", 0xd4}, // TeleserviceCode ::= '11010100'B + {"plmn-specificTS-5", 0xd5}, // TeleserviceCode ::= '11010101'B + {"plmn-specificTS-6", 0xd6}, // TeleserviceCode ::= '11010110'B + {"plmn-specificTS-7", 0xd7}, // TeleserviceCode ::= '11010111'B + {"plmn-specificTS-8", 0xd8}, // TeleserviceCode ::= '11011000'B + {"plmn-specificTS-9", 0xd9}, // TeleserviceCode ::= '11011001'B + {"plmn-specificTS-A", 0xda}, // TeleserviceCode ::= '11011010'B + {"plmn-specificTS-B", 0xdb}, // TeleserviceCode ::= '11011011'B + {"plmn-specificTS-C", 0xdc}, // TeleserviceCode ::= '11011100'B + {"plmn-specificTS-D", 0xdd}, // TeleserviceCode ::= '11011101'B + {"plmn-specificTS-E", 0xde}, // TeleserviceCode ::= '11011110'B + {"plmn-specificTS-F", 0xdf}, // TeleserviceCode ::= '11011111'B + {0,0}, +}; + +static const Parameter s_extBearerServiceCode[] = { + {"ext-BearerServiceCode", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extTeleserviceCode[] = { + {"ext-TeleserviceCode", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_bearerService[] = { + {"bearerService", s_hexTag, false, TcapXApplication::Enumerated, s_bearerServiceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_teleservice[] = { + {"teleservice", s_hexTag, false, TcapXApplication::Enumerated, s_teleserviceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_basicServiceCode[] = { + {"bearerService", s_ctxtPrim_2_Tag, false, TcapXApplication::Enumerated, s_bearerServiceCode}, + {"teleservice", s_ctxtPrim_3_Tag, false, TcapXApplication::Enumerated, s_teleserviceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extBasicServiceCode[] = { + {"ext-BearerService", s_ctxtPrim_2_Tag, false, TcapXApplication::HexString, 0}, + {"ext-Teleservice", s_ctxtPrim_3_Tag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const SignallingFlags s_forwardOptions[] = { + { 0x80, 0x80, "notify-called" }, + { 0x40, 0x40, "presentation" }, + { 0x20, 0x20, "notify-caller" }, + { 0xc0, 0x00, "offline" }, + { 0xc1, 0xc1, "busy" }, + { 0xc2, 0xc2, "noanswer" }, + { 0xc3, 0xc3, "always" }, + { 0, 0, 0 }, +}; + +static const SignallingFlags s_ssStatus[] = { + { 0x01, 0x01, "active" }, + { 0x02, 0x02, "registered" }, + { 0x04, 0x04, "provisioned" }, + { 0x08, 0x08, "quiescent" }, + { 0, 0, 0 }, +}; + +static const Parameter s_forwFeatureSeq[] = { + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"ss-Status", s_ctxtPrim_4_Tag, false, TcapXApplication::Flags, s_ssStatus}, + {"forwardedToNumber", s_ctxtPrim_5_Tag, true, TcapXApplication::AddressString, 0}, + {"forwardedToSubaddress", s_ctxtPrim_8_Tag, true, TcapXApplication::HexString, 0}, + {"forwardingOptions", s_ctxtPrim_6_Tag, true, TcapXApplication::Flags, s_forwardOptions}, + {"noReplyConditionTime", s_ctxtPrim_7_Tag, true, TcapXApplication::Integer, 0}, + {"extensionContainer", s_ctxtCstr_9_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_forwFeature[] = { + {"forwardingFeature", s_sequenceTag, true, TcapXApplication::Sequence, s_forwFeatureSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extForwInfo[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"forwardingFeatureList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_forwFeature}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extCallBarFeatureSeq[] = { + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"ss-Status", s_ctxtPrim_4_Tag, false, TcapXApplication::Flags, s_ssStatus}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extCallBarFeature[] = { + {"ext-CallBarFeature", s_sequenceTag, true, TcapXApplication::Sequence, s_extCallBarFeatureSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extCallBarInfo[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"callBarringFeatureList",s_sequenceTag, false, TcapXApplication::SequenceOf, s_extCallBarFeature}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_intraCUGOptions[] = { + {"noCUG-Restrictions", 0}, + {"cugIC-CallBarred", 1}, + {"cugOG-CallBarred", 2}, + {0,0}, +}; + +static const Parameter s_basicServiceCodeType[] = { + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_CUGSubscriptionSeq[] = { + {"cug-Index", s_intTag, false, TcapXApplication::Integer, 0}, + {"cug-Interlock", s_hexTag, false, TcapXApplication::HexString, 0}, + {"intraCUG-Options", s_enumTag, false, TcapXApplication::Enumerated, s_intraCUGOptions}, + {"basicServiceGroupList", s_sequenceTag, true, TcapXApplication::SequenceOf, s_basicServiceCodeType}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; +static const Parameter s_CUGSubscription[] = { + {"cug-Subscription", s_sequenceTag, false, TcapXApplication::Sequence, s_CUGSubscriptionSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_interCUGRestrinctions[] = { + {"CUG-only", 0x00}, + {"CUG-outgoing-access", 0x01}, + {"CUG-incoming-access", 0x02}, + {"CUG-both", 0x03}, + {0,0}, +}; + +static const Parameter s_CUGFeatureSeq[] = { + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"preferentialCUG-Indicator", s_intTag, true, TcapXApplication::Integer, 0}, + {"interCUG-Restrictions", s_hexTag, false, TcapXApplication::Enumerated, s_interCUGRestrinctions}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_CUGFeature[] = { + {"cug-Feature", s_sequenceTag, false, TcapXApplication::Sequence, s_CUGFeatureSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_cugInfo[] = { + {"cug-SubscriptionList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_CUGSubscription}, + {"cug-FeatureList", s_sequenceTag, true, TcapXApplication::SequenceOf, s_CUGFeature}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_cliRestrictionOption[] = { + {"permanent", 0}, + {"temporaryDefaultRestricted", 1}, + {"temporaryDefaultAllowed", 2}, + {0,0}, +}; + +static const TokenDict s_overrideCategory[] = { + {"overrideEnabled", 0}, + {"overrideDisabled", 1}, + {0,0}, +}; + +static const Parameter s_ssSubscriptionOption[] = { + {"cliRestrictionOption", s_ctxtPrim_2_Tag, false, TcapXApplication::Enumerated, s_cliRestrictionOption}, + {"overrideCategory", s_ctxtPrim_1_Tag, false, TcapXApplication::Enumerated, s_overrideCategory}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extSSData[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"ss-Status", s_ctxtPrim_4_Tag, false, TcapXApplication::Flags, s_ssStatus}, + {"ss-SubscriptionOption", s_noTag, true, TcapXApplication::Choice, s_ssSubscriptionOption}, + {"basicServiceGroupList", s_sequenceTag, true, TcapXApplication::SequenceOf, s_basicServiceCodeType}, + {"extensionContainer", s_ctxtCstr_5_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_EMLPPPriority[] = { + {"priorityLevel0", 0}, + {"priorityLevel1", 1}, + {"priorityLevel2", 2}, + {"priorityLevel3", 3}, + {"priorityLevel4", 4}, + {"priorityLevelB", 5}, + {"priorityLevelA", 6}, + {0,0}, +}; + +static const Parameter s_EMLPPInfo[] = { + {"maximumentitledPriority", s_intTag, false, TcapXApplication::Enumerated, s_EMLPPPriority}, + {"defaultPriority", s_intTag, false, TcapXApplication::Enumerated, s_EMLPPPriority}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extSSInfoChoice[] = { + {"forwardingInfo", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_extForwInfo}, + {"callBarringInfo", s_ctxtCstr_1_Tag, false, TcapXApplication::Sequence, s_extCallBarInfo}, + {"cug-Info", s_ctxtCstr_2_Tag, false, TcapXApplication::Sequence, s_cugInfo}, + {"ss-Data", s_ctxtCstr_3_Tag, false, TcapXApplication::Sequence, s_extSSData}, + {"emlpp-Info", s_ctxtCstr_4_Tag, false, TcapXApplication::Sequence, s_EMLPPInfo}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extSSInfo[] = { + {"SS-Info", s_noTag, false, TcapXApplication::Choice, s_extSSInfoChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_odbGeneralData[] = { + {"allOG-CallsBarred", 0x01}, + {"internationalOGCallsBarred", 0x02}, + {"internationalOGCallsNotToHPLMN-CountryBarred", 0x04}, + {"interzonalOGCallsBarred", 0x40}, + {"interzonalOGCallsNotToHPLMN-CountryBarred", 0x80}, + {"interzonalOGCallsAndInternationalOGCallsNotToHPLMN-CountryBarred", 0x0100}, + {"premiumRateInformationOGCallsBarred", 0x08}, + {"premiumRateEntertainementOGCallsBarred", 0x10}, + {"ss-AccessBarred", 0x20}, + {"allECT-Barred", 0x0200}, + {"chargeableECT-Barred", 0x0400}, + {"internationalECT-Barred", 0x0800}, + {"interzonalECT-Barred", 0x1000}, + {"doublyChargeableECT-Barred", 0x2000}, + {"multipleECT-Barred", 0x2000}, + {0,0}, +}; + +static const TokenDict s_odbHPLMNData[] = { + {"plmn-SpecificBarringType1", 0x01}, + {"plmn-SpecificBarringType2", 0x02}, + {"plmn-SpecificBarringType3", 0x04}, + {"plmn-SpecificBarringType4", 0x08}, + {0,0}, +}; + +static const Parameter s_odbData[] = { + {"odb-GeneralData", s_bitsTag, false, TcapXApplication::BitString, s_odbGeneralData}, + {"odb-HPLMN-Data", s_bitsTag, true, TcapXApplication::BitString, s_odbHPLMNData}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_zoneCode[] = { + {"zoneCode", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_voiceBroadcastData[] = { + {"groupid", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"broadcastInitEntitlement", s_nullTag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_voiceGroupCallData[] = { + {"groupid", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_OBcsmTriggerDetectionPoint[] = { + {"collectedInfo", 2}, + {0,0}, +}; + +static const TokenDict s_defaultCallHandling[] = { + {"continueCall", 0}, + {"releaseCall", 1}, + {0,0}, +}; + +static const Parameter s_OBcsmCamelTDPData[] = { + {"o-BcsmTriggerDetectionPoint", s_enumTag, false, TcapXApplication::Enumerated, s_OBcsmTriggerDetectionPoint}, + {"serviceKey", s_intTag, false, TcapXApplication::Integer, 0}, + {"gsmSCF-Address", s_ctxtPrim_0_Tag, false, TcapXApplication::AddressString, 0}, + {"defaultCallHandling", s_ctxtPrim_1_Tag, false, TcapXApplication::Enumerated, s_defaultCallHandling}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_camelCapabilityHandling[] = { + {"continueCall", 0}, + {"releaseCall", 1}, + {0,0}, +}; + +static const Parameter s_OCSI[] = { + {"o-BcsmCamelTDPDataList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_OBcsmCamelTDPData}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"camelCapabilityHandling", s_ctxtPrim_0_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_ssCode[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_SSCamelData[] = { + {"ss-EventList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_ssCode}, + {"gsmSCF-Address", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_SSCSI[] = { + {"ss-CamelData", s_sequenceTag, false, TcapXApplication::Sequence, s_SSCamelData}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_matchType[] = { + {"inhibiting", 0x00}, + {"enabling", 0x01}, + {0,0xff}, +}; + +static const Parameter s_destinationNumber[] = { + {"destinationNumber", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_destinationNumberLength[] = { + {"destinationNumberLength", s_intTag, false, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_destinationNumberCriteria[] = { +// TS 100 974 v7.15.0 page 306 + {"matchType", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_matchType}, + {"destinationNumberList", s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_destinationNumber}, + {"destinationNumberLengthList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_destinationNumberLength}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_callTypeCriteria[] = { +// TS 100 974 v7.15.0 page 307 + {"forwarded", 0x00}, + {"notForwarded", 0x01}, + {0,0xff}, +}; + +static const Parameter s_OBcsmCamelTDPCriteria[] = { + {"o-BcsmTriggerDetectionPoint", s_enumTag, false, TcapXApplication::Enumerated, s_OBcsmTriggerDetectionPoint}, + {"destinationNumberCriteria", s_ctxtCstr_0_Tag, true, TcapXApplication::Sequence, s_destinationNumberCriteria}, + {"basicServiceCriteria", s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_basicServiceCodeType}, + {"callTypeCriteria", s_ctxtPrim_2_Tag, true, TcapXApplication::Enumerated, s_callTypeCriteria}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_VlrCamelSubscriptionInfo[] = { + {"o-CSI", s_ctxtCstr_0_Tag, true, TcapXApplication::Sequence, s_OCSI}, + {"extensionContainer", s_ctxtCstr_1_Tag, true, TcapXApplication::HexString, 0}, + {"ss-CSI", s_ctxtCstr_2_Tag, true, TcapXApplication::Sequence, s_SSCSI}, + {"o-BcsmCamelTDP-CriteriaList", s_ctxtCstr_4_Tag, true, TcapXApplication::SequenceOf, s_OBcsmCamelTDPCriteria}, + {"tif-CSI", s_ctxtPrim_3_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_naeaPreferredCI[] = { +// NAEAPreferredICI + {"naea-PreferredCIC", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"extensionContainer", s_ctxtCstr_1_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_PDPContextSeq[] = { + {"pdp-ContextId", s_intTag, false, TcapXApplication::Integer, 0}, + {"pdp-Type", s_ctxtPrim_16_Tag, false, TcapXApplication::HexString, 0}, + {"pdp-Address", s_ctxtPrim_17_Tag, true, TcapXApplication::HexString, 0}, + {"qos-Subscribed", s_ctxtPrim_18_Tag, false, TcapXApplication::HexString, 0}, + {"vplmnAddressAllowed", s_ctxtPrim_19_Tag, true, TcapXApplication::Null, 0}, + {"apn", s_ctxtPrim_20_Tag, false, TcapXApplication::HexString, 0}, + {"extensionContainer", s_ctxtCstr_21_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_PDPContext[] = { + {"pdp-Context", s_sequenceTag, false, TcapXApplication::Sequence, s_PDPContextSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_GPRSSubscriptionData[] = { + {"completeDataListIncluded", s_nullTag, true, TcapXApplication::Null, 0}, + {"gprsDataList", s_ctxtCstr_1_Tag, false, TcapXApplication::SequenceOf, s_PDPContext}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_networkAccessMode[] = { + {"bothMSCAndSGSN", 0x00}, + {"onlyMSC", 0x01}, + {"onlySGSN", 0x02}, + {0,0xff}, +}; + +static const TokenDict s_lsaOnlyAccessIndicator[] = { + {"accessOutsideLSAsAllowed", 0x00}, + {"accessOutsideLSAsRestricted", 0x01}, + {0,0xff}, +}; + +static const Parameter s_LSADataSeq[] = { + {"lsaIdentity", s_ctxtPrim_0_Tag, false, TcapXApplication::HexString, 0}, + {"lsaAttributes", s_ctxtPrim_1_Tag, false, TcapXApplication::HexString, 0}, + {"lsaActiveModeIndicator", s_ctxtPrim_2_Tag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LSAData[] = { + {"lsaData", s_sequenceTag, false, TcapXApplication::Sequence, s_LSADataSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LSAInformation[] = { + {"completeDataListIncluded", s_nullTag, true, TcapXApplication::Null, 0}, + {"lsaOnlyAccessIndicator", s_ctxtPrim_1_Tag, true, TcapXApplication::Enumerated, s_lsaOnlyAccessIndicator}, + {"lsaDataList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_LSAData}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_GMLC[] = { + {"gmlc", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_notificationToMSUser[] = { + {"notifyLocationAllowed", 0x00}, + {"notifyAndVerify-LocationAllowedIfNoResponse", 0x01}, + {"notifyAndVerify-LocationNotAllowedIfNoResponse", 0x02}, + {0,0xff}, +}; + +static const TokenDict s_GMLCRestriction[] = { + {"gmlc-List", 0x00}, + {"home-Country", 0x01}, + {0,0xff}, +}; + +static const Parameter s_LCSClientExternalIDSeq[] = { + {"externalAddress", s_ctxtPrim_0_Tag, true, TcapXApplication::AddressString, 0}, + {"extensionContainer", s_ctxtCstr_1_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_externalClientSeq[] = { + {"clientIdentity", s_sequenceTag, false, TcapXApplication::Sequence, s_LCSClientExternalIDSeq}, + {"gmlc-Restriction", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_GMLCRestriction}, + {"notificationToMSUser", s_ctxtPrim_1_Tag, true, TcapXApplication::Enumerated, s_notificationToMSUser}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_externalClient[] = { + {"externalClient", s_sequenceTag, false, TcapXApplication::Sequence, s_externalClientSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_LCSClientInternalIDEnum[] = { + {"broadcastService", 0x00}, + {"o-andM-HPLMN", 0x01}, + {"o-andM-VPLMN", 0x02}, + {"anonymousLocation", 0x03}, + {"targetMSsubscribedService", 0x04}, + {0,0xff}, +}; + + +static const Parameter s_LCSClientInternalID[] = { + {"lcsClientInternalID", s_enumTag, false, TcapXApplication::Enumerated, s_LCSClientInternalIDEnum}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LCSPrivacyClassSeq[] = { + {"ss-Code", s_hexTag, false,TcapXApplication::Enumerated, s_SSCode}, + {"ss-Status", s_hexTag, false,TcapXApplication::Flags, s_ssStatus}, + {"notificationToMSUser", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_notificationToMSUser}, + {"externalClientList", s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_externalClient}, + {"plmnClientList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_LCSClientInternalID}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_LCSPrivacyException[] = { + {"lcsPrivacyClass", s_sequenceTag, false, TcapXApplication::Sequence, s_LCSPrivacyClassSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_MOLRClassSeq[] = { + {"ss-Code", s_hexTag, false,TcapXApplication::Enumerated, s_SSCode}, + {"ss-Status", s_hexTag, false,TcapXApplication::Flags, s_ssStatus}, + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_MOLRClass[] = { + {"mOLRClass", s_sequenceTag, false, TcapXApplication::Sequence, s_MOLRClassSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LCSInformation[] = { + {"gmlc-List", s_ctxtCstr_0_Tag, true, TcapXApplication::SequenceOf, s_GMLC}, + {"lcs-PrivacyExceptionList",s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_LCSPrivacyException}, + {"molr-List", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_MOLRClass}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const Parameter s_contextId[] = { +// TS 100 974 v7.15.0 page 305 + {"contextId", s_intTag, false, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_GPRSSubscriptionDataWithdraw[] = { +// TS 100 974 v7.15.0 page 305 + {"allGPRSData", s_nullTag, false, TcapXApplication::Null, 0}, + {"contextIdList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_contextId}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LSAIdentity[] = { +// TS 100 974 v7.15.0 page 300 + {"lsaIdentity", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_LSAInformationWithdraw[] = { +// TS 100 974 v7.15.0 page 305 + {"allLSAData", s_nullTag, false, TcapXApplication::Null, 0}, + {"lsaIdentityList", s_sequenceTag, false, TcapXApplication::SequenceOf, s_LSAIdentity}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_regionalSubscriptionResponse[] = { +// TS 100 974 v7.15.0 page 305 + {"networkNode-AreaRestricted", 0}, + {"tooManyZoneCodes", 1}, + {"zoneCodesConflict", 2}, + {"regionalSubscNotSupported", 3}, + {0,0}, +}; + +static const Parameter s_SSForBSCode[] = { +// TS 100 974 v7.15.0 page 319 + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_ccbsFeature[] = { +// TS 100 974 v7.15.0 page 319 + {"ccbs-Index", s_ctxtPrim_0_Tag, true, TcapXApplication::Integer, 0}, + {"b-subscriberNumber", s_ctxtPrim_1_Tag, true, TcapXApplication::AddressString, 0}, + {"b-subscriberSubaddress", s_ctxtPrim_2_Tag, true, TcapXApplication::HexString , 0}, + {"basicServiceGroup", s_ctxtPrim_3_Tag, true, TcapXApplication::Choice, s_extBasicServiceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_CCBSFeature[] = { +// TS 100 974 v7.15.0 page 319 + {"CCBS-Feature", s_sequenceTag, false, TcapXApplication::Sequence, s_ccbsFeature}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_genericServiceInfo[] = { +// TS 100 974 v7.15.0 page 319 + {"ss-Status", s_hexTag, false, TcapXApplication::Flags, s_ssStatus}, + {"cliRestrictionOption", s_enumTag, true, TcapXApplication::Enumerated, s_cliRestrictionOption}, + {"maximumentitledPriority", s_intTag, true, TcapXApplication::Enumerated, s_EMLPPPriority}, + {"defaultPriority", s_intTag, true, TcapXApplication::Enumerated, s_EMLPPPriority}, + {"ccbs-FeatureList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_CCBSFeature}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_InterrogateSSRes[] = { +// TS 100 974 v7.15.0 page 319 + {"ss-Status", s_ctxtPrim_0_Tag, false, TcapXApplication::Flags, s_ssStatus}, + {"basicServiceGroupList", s_ctxtCstr_2_Tag, false, TcapXApplication::SequenceOf, s_basicServiceCodeType}, + {"forwardingFeatureList", s_ctxtCstr_3_Tag, false, TcapXApplication::SequenceOf, s_forwFeature}, + {"genericServiceInfo", s_ctxtCstr_4_Tag, false, TcapXApplication::Sequence, s_genericServiceInfo}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_guidanceInfo[] = { + {"enterPW", 0 }, + {"enterNewPW", 1 }, + {"enterNewPW-Again", 2 }, + {0, 0}, +}; + +static const Parameter s_hlrId[] = { + {"HLR-Id", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_additionalNumber[] = { + {"msc-Number", s_ctxtPrim_0_Tag, false, TcapXApplication::AddressString, 0}, + {"sgsn-Number", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_locationInfoWithLMSI[] = { +// TS 100 974 v7.15.0 page 324 + {"networkNode-Number", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"lmsi", s_hexTag, true, TcapXApplication::HexString, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"gprsNodeIndicator", s_ctxtPrim_5_Tag, true, TcapXApplication::Null, 0}, + {"additional-Number", s_noTag, true, TcapXApplication::Choice, s_additionalNumber}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const Parameter s_authenticationSetSeq[] = { +// TS 100 974 v7.15.0 page 298 + {"rand", s_hexTag, false, TcapXApplication::HexString, 0}, + {"sres", s_hexTag, false, TcapXApplication::HexString, 0}, + {"kc", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authenticationSet[] = { + {"set", s_sequenceTag, false, TcapXApplication::Sequence, s_authenticationSetSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authenticationTriplet[] = { + {"triplet", s_sequenceTag, false, TcapXApplication::Sequence, s_authenticationSetSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authenticationQuintupletSeq[] = { + {"rand", s_hexTag, false, TcapXApplication::HexString, 0}, + {"xres", s_hexTag, false, TcapXApplication::HexString, 0}, + {"ck", s_hexTag, false, TcapXApplication::HexString, 0}, + {"ik", s_hexTag, false, TcapXApplication::HexString, 0}, + {"autn", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authenticationQuintuplet[] = { + {"quintuplet", s_sequenceTag, false, TcapXApplication::Sequence, s_authenticationQuintupletSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authChoice[] = { + {"tripletList", s_ctxtCstr_0_Tag, false, TcapXApplication::SequenceOf, s_authenticationTriplet}, + {"quintupletList", s_ctxtCstr_1_Tag, false, TcapXApplication::SequenceOf, s_authenticationQuintuplet}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_epcAvSeq[] = { + {"rand", s_hexTag, false, TcapXApplication::HexString, 0}, + {"xres", s_hexTag, false, TcapXApplication::HexString, 0}, + {"autn", s_hexTag, false, TcapXApplication::HexString, 0}, + {"kasme", s_hexTag, false, TcapXApplication::HexString, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_EPCAV[] = { +// TS 129 002 V9.3.0 page 359 + {"EPC-AV", s_sequenceTag, false, TcapXApplication::Sequence, s_epcAvSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_authenticationRes[] = { +// TS 129 002 V9.3.0 page 352 + {"authenticationSetList", s_noTag, true, TcapXApplication::Choice, s_authChoice}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"eps-AuthenticationSetList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_EPCAV}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_alertReason[] = { +// TS 100 974 v7.15.0 page 326 + {"ms-Present", 0}, + {"memoryAvailable", 1}, + {0,0}, +}; + +static const Parameter s_subscriberIdentity[] = { +// TS 100 974 v7.15.0 page 335 + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"msisdn", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_requestedInfo[] = { +// TS 100 974 v7.15.0 page 309 + {"locationInformation", s_ctxtPrim_0_Tag, true, TcapXApplication::Null, 0}, + {"subscriberState", s_ctxtPrim_1_Tag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_cellIdOrLAI[] = { +// TS 100 974 v7.15.0 page 335 + {"cellIdFixedLength", s_ctxtPrim_0_Tag, false, TcapXApplication::CellIdFixedLength, 0}, + {"laiFixedLength", s_ctxtPrim_1_Tag, false, TcapXApplication::LAIFixedLength, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_locationInformation[] = { +// TS 100 974 v7.15.0 page 309 + {"ageOfLocationInformation", s_intTag, false, TcapXApplication::Integer, 0}, + {"geographicalInformation", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"vlr-Number", s_ctxtPrim_1_Tag, true, TcapXApplication::AddressString, 0}, + {"locationNumber", s_ctxtPrim_2_Tag, true, TcapXApplication::HexString, 0}, + {"cellIdOrLAI", s_ctxtCstr_3_Tag, true, TcapXApplication::Choice, s_cellIdOrLAI}, + {"extensionContainer", s_ctxtCstr_4_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_notReachableReason[] = { + {"msPurged", 0}, + {"imsiDetached", 1}, + {"restrictedArea", 2}, + {"notRegistered", 3}, + {0,0}, +}; + +static const Parameter s_subscriberState[] = { +// TS 100 974 v7.15.0 page 309 + {"assumedIdle", s_ctxtPrim_0_Tag, false, TcapXApplication::Null, 0}, + {"camelBusy", s_ctxtPrim_1_Tag, false, TcapXApplication::Null, 0}, + {"netDetNotReachable", s_enumTag, false, TcapXApplication::Enumerated, s_notReachableReason}, + {"notProvidedFromVLR", s_ctxtPrim_2_Tag, false, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_subscriberInfo[] = { +// TS 100 974 v7.15.0 page 309 + {"locationInformation", s_ctxtCstr_0_Tag, true, TcapXApplication::Sequence, s_locationInformation}, + {"subscriberState", s_ctxtCstr_1_Tag, true, TcapXApplication::Choice, s_subscriberState}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const TokenDict s_reportingState[] = { + {"stopMonitoring", 0}, + {"startMonitoring", 1}, + {0,0} +}; + +static const TokenDict s_CCBSSubscriberStatus[] = { + {"ccbsNotIdle", 0}, + {"ccbsIdle", 1}, + {"ccbsNotReachable", 2}, + {0,0} +}; + +static const Parameter s_eventReportData[] = { +// TS 100 974 v7.15.0 page 315 + {"ccbs-SubscriberStatus", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_CCBSSubscriberStatus}, + {"extensionContainer", s_ctxtCstr_1_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_monitoringMode[] = { +// TS 100 974 v7.15.0 page 315 + {"a-side", 0}, + {"b-side", 1}, + {0,0} +}; +static const TokenDict s_callOutcome[] = { +// TS 100 974 v7.15.0 page 316 + {"success", 0}, + {"failure", 1}, + {"busy", 2}, + {0,0} +}; + +static const Parameter s_callReportData[] = { +// TS 100 974 v7.15.0 page 315 + {"monitoringMode", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_monitoringMode}, + {"callOutcome", s_ctxtPrim_1_Tag, true, TcapXApplication::Enumerated, s_callOutcome}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_updateLocationArgs[] = { + // update location args + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"msc-Number", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"vlr-Number", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"lmsi", s_ctxtPrim_10_Tag, true, TcapXApplication::HexString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"vlr-Capability", s_ctxtCstr_6_Tag, true, TcapXApplication::Sequence, s_vlrCapability}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_updateLocationRes[] = { + {"hlr-Number", s_hexTag, false, TcapXApplication::AddressString,0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_cancelLocationArgs[] = { + {"identity", s_noTag, false, TcapXApplication::Choice, s_mapIdentity}, + {"cancellationType", s_enumTag, true, TcapXApplication::Enumerated, s_cancellationType}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_extensionContainerRes[] = { + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_provideRoamingNumberArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"msc-Number", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"msisdn", s_ctxtPrim_2_Tag, true, TcapXApplication::AddressString, 0}, + {"lmsi", s_ctxtPrim_4_Tag, true, TcapXApplication::HexString, 0}, + {"gsm-BearerCapability", s_ctxtCstr_5_Tag, true, TcapXApplication::Sequence, s_externalSignalInfo}, + {"networkSignalInfo", s_ctxtCstr_6_Tag, true, TcapXApplication::Sequence, s_externalSignalInfo}, + {"suppressionOfAnnouncement", s_ctxtPrim_7_Tag, true, TcapXApplication::Null, 0}, + {"gmsc-Address", s_ctxtPrim_8_Tag, true, TcapXApplication::AddressString, 0}, + {"callReferenceNumber", s_ctxtPrim_9_Tag, true, TcapXApplication::HexString, 0}, + {"or-Interrogation", s_ctxtPrim_10_Tag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_ctxtCstr_11_Tag, true, TcapXApplication::HexString, 0}, + {"alertingPattern", s_ctxtPrim_12_Tag, true, TcapXApplication::Enumerated, s_alertPattern}, + {"ccbs-Call", s_ctxtPrim_13_Tag, true, TcapXApplication::Null, 0}, + {"supportedCamelPhasesInGMSC",s_ctxtPrim_15_Tag, true, TcapXApplication::BitString, s_camelPhases}, + {"additionalSignalInfo", s_ctxtCstr_14_Tag, true, TcapXApplication::Sequence, s_extExtenalSignalInfo}, + {"orNotSupportedInGMSC", s_ctxtPrim_16_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_provideRoamingNumberRes[] = { + {"roamingNumber", s_hexTag, false,TcapXApplication::AddressString, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_insertSubscriberDataArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, true, TcapXApplication::TBCD, 0}, + {"msisdn", s_ctxtPrim_1_Tag, true, TcapXApplication::AddressString,0}, + {"category", s_ctxtPrim_2_Tag, true, TcapXApplication::Enumerated, s_category}, + {"subscriberStatus", s_ctxtPrim_3_Tag, true, TcapXApplication::Enumerated, s_subscriberStatus}, + {"bearerServiceList", s_ctxtCstr_4_Tag, true, TcapXApplication::SequenceOf, s_bearerService}, + {"teleserviceList", s_ctxtCstr_6_Tag, true, TcapXApplication::SequenceOf, s_teleservice}, + {"provisionedSS", s_ctxtCstr_7_Tag, true, TcapXApplication::SequenceOf, s_extSSInfo}, + {"odb-Data", s_ctxtCstr_8_Tag, true, TcapXApplication::Sequence, s_odbData}, + {"roamingRestrictionDueToUnsupportedFeature", s_ctxtPrim_9_Tag, true, TcapXApplication::Null, 0}, + {"regionalSubscriptionData", s_ctxtCstr_10_Tag, true, TcapXApplication::SequenceOf, s_zoneCode}, + {"vbsSubscriptionData", s_ctxtCstr_11_Tag, true, TcapXApplication::SequenceOf, s_voiceBroadcastData}, + {"vgcsSubscriptionData", s_ctxtCstr_12_Tag, true, TcapXApplication::SequenceOf, s_voiceGroupCallData}, + {"vlrCamelSubscriptionInfo", s_ctxtCstr_13_Tag, true, TcapXApplication::Sequence, s_VlrCamelSubscriptionInfo}, + {"extensionContainer", s_ctxtCstr_14_Tag, true, TcapXApplication::HexString, 0}, + {"naea-PreferredCI", s_ctxtCstr_15_Tag, true, TcapXApplication::Sequence, s_naeaPreferredCI}, + {"gprsSubscriptionData", s_ctxtCstr_16_Tag, true, TcapXApplication::Sequence, s_GPRSSubscriptionData}, + {"roamingRestrictedInSgsnDueToUnsupportedFeature", s_ctxtCstr_23_Tag, true, TcapXApplication::Null, 0}, + {"networkAccessMode", s_ctxtCstr_24_Tag, true, TcapXApplication::Enumerated, s_networkAccessMode}, + {"lsaInformation", s_ctxtCstr_25_Tag, true, TcapXApplication::Sequence, s_LSAInformation}, + {"lmu-Indicator", s_ctxtPrim_21_Tag, true, TcapXApplication::Null, 0}, + {"lcsInformation", s_ctxtCstr_22_Tag, true, TcapXApplication::Sequence, s_LCSInformation}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_insertSubscriberDataRes[] = { + {"teleserviceList", s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_teleservice}, + {"bearerServiceList", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_bearerService}, + {"ss-List", s_ctxtCstr_3_Tag, true, TcapXApplication::SequenceOf, s_ssCode}, + {"odb-GeneralData", s_ctxtPrim_4_Tag, true, TcapXApplication::BitString, s_odbGeneralData}, + {"regionalSubscriptionResponse",s_ctxtPrim_5_Tag, true, TcapXApplication::Enumerated, s_regionalSubscriptionResponse}, + {"supportedCamelPhases", s_ctxtPrim_6_Tag, true, TcapXApplication::BitString, s_camelPhases}, + {"extensionContainer", s_ctxtCstr_7_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_deleteSubscriberDataArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"basicServiceList", s_ctxtCstr_1_Tag, true, TcapXApplication::SequenceOf, s_basicServiceCodeType}, + {"ss-List", s_ctxtCstr_2_Tag, true, TcapXApplication::SequenceOf, s_ssCode}, + {"roamingRestrictionDueToUnsupportedFeature", s_ctxtPrim_4_Tag, true, TcapXApplication::Null, 0}, + {"regionalSubscriptionIdentifier", s_ctxtPrim_5_Tag, true, TcapXApplication::HexString, 0}, + {"vbsGroupIndication", s_ctxtPrim_7_Tag, true, TcapXApplication::Null, 0}, + {"vgcsGroupIndication", s_ctxtPrim_8_Tag, true, TcapXApplication::Null, 0}, + {"camelSubscriptionInfoWithdraw", s_ctxtPrim_9_Tag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_ctxtCstr_6_Tag, true, TcapXApplication::HexString, 0}, + {"gprsSubscriptionDataWithdraw", s_ctxtCstr_10_Tag,true, TcapXApplication::Choice, s_GPRSSubscriptionDataWithdraw}, + {"roamingRestrictedInSgsnDueToUnsuppportedFeature", s_ctxtPrim_11_Tag,true, TcapXApplication::Null, 0}, + {"lsaInformationWithdraw", s_ctxtCstr_12_Tag,true, TcapXApplication::Choice, s_LSAInformationWithdraw}, + {"gmlc-ListWithdraw", s_ctxtPrim_13_Tag,true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_deleteSubscriberDataRes[] = { + {"regionalSubscriptionResponse", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_regionalSubscriptionResponse}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_registerSSArgs[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"forwardedToNumber", s_ctxtPrim_4_Tag, true, TcapXApplication::AddressString, 0}, + {"forwardedToSubaddress", s_ctxtPrim_6_Tag, true, TcapXApplication::HexString, 0}, + {"noReplyConditionTime", s_ctxtPrim_5_Tag, true, TcapXApplication::Integer, 0}, + {"defaultPriority", s_ctxtPrim_7_Tag, true, TcapXApplication::Enumerated, s_EMLPPPriority}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_ssInfoRes[] = { + {"ss-Info", s_noTag, false, TcapXApplication::Choice, s_extSSInfoChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_ssCodeArgs[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_interrogateSSRes[] = { + {"InterrogateSS-Res", s_noTag, false, TcapXApplication::Choice, s_InterrogateSSRes}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_registerPasswordArgs[] = { + {"ss-Code", s_hexTag, false, TcapXApplication::Enumerated, s_SSCode}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_registerPasswordRes[] = { + {"newPassword", s_numStrTag, false, TcapXApplication::AppString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_getPasswordArgs[] = { + {"guidanceInfo", s_enumTag, false, TcapXApplication::Enumerated, s_guidanceInfo}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_getPasswordRes[] = { + {"currentPassword", s_numStrTag, false, TcapXApplication::AppString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_updateGprsLocationArgs[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"sgsn-Number", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"sgsn-Address", s_hexTag, false, TcapXApplication::HexString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_updateGprsLocationRes[] = { + {"hlr-Number", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false , TcapXApplication::None, 0}, +}; + +static const Parameter s_sendRoutingInfoForGprsArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"ggsn-Address", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"ggsn-Number", s_ctxtPrim_2_Tag, false, TcapXApplication::AddressString, 0}, + {"extensionContainer",s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendRoutingInfoForGprsRes[] = { + {"sgsn-Address", s_ctxtPrim_0_Tag, false, TcapXApplication::HexString, 0}, + {"ggsn-Address", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"mobileNotReachableReason", s_ctxtPrim_2_Tag, true, TcapXApplication::Integer, 0}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_failureReportArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"ggsn-Number", s_ctxtPrim_1_Tag, false, TcapXApplication::AddressString, 0}, + {"ggsn-Address", s_ctxtPrim_2_Tag, true, TcapXApplication::HexString, 0}, + {"extensionContainer",s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_failureReportRes[] = { + {"ggsn-Address", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"extensionContainer",s_ctxtCstr_1_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_resetArgs[] = { + {"hlr-Number", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"hlr-List", s_sequenceTag, true, TcapXApplication::SequenceOf, s_hlrId}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendRoutingInfoForSMArgs[] = { + {"msisdn", s_ctxtPrim_0_Tag, false, TcapXApplication::AddressString, 0}, + {"sm-RP-PRI", s_ctxtPrim_1_Tag, false, TcapXApplication::Bool, 0}, + {"serviceCentreAddress", s_ctxtPrim_2_Tag, false, TcapXApplication::AddressString, 0}, + {"extensionContainer", s_ctxtCstr_6_Tag, true, TcapXApplication::HexString, 0}, + {"gprsSupportIndicator", s_ctxtPrim_7_Tag, true, TcapXApplication::Null, 0}, + {"sm-RP-MTI", s_ctxtPrim_8_Tag, true, TcapXApplication::Integer, 0}, + {"sm-RP-SMEA", s_ctxtPrim_9_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendRoutingInfoForSMRes[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"locationInfoWithLMSI", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_locationInfoWithLMSI}, + {"extensionContainer", s_ctxtCstr_4_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_activateTraceModeArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, true, TcapXApplication::TBCD, 0}, + {"traceReference", s_ctxtPrim_1_Tag, false, TcapXApplication::HexString, 0}, + {"traceType", s_ctxtPrim_2_Tag, false, TcapXApplication::Integer, 0}, + {"omc-Id", s_ctxtPrim_3_Tag, true, TcapXApplication::AddressString, 0}, + {"extensionContainer",s_ctxtCstr_4_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_traceModeRes[] = { + {"extensionContainer",s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_deactivateTraceModeArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, true, TcapXApplication::TBCD, 0}, + {"traceReference", s_ctxtPrim_1_Tag, false, TcapXApplication::HexString, 0}, + {"extensionContainer",s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_resynchronisationInfo[] = { + {"rand", s_hexTag, false, TcapXApplication::HexString, 0}, + {"auts", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_requestingNodeType[] = { + {"vlr", 0}, + {"sgsn", 1}, + {"s-cscf", 2}, + {"bsf", 3}, + {"gan-aaa-server", 4}, + {"wlan-aaa-server", 5}, + {"mme", 16}, + {"mme-sgsn", 17}, + {0, 0}, +}; + +static const Parameter s_sendAuthenticationInfoArgs[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"numberOfRequestedVectors", s_intTag, true, TcapXApplication::Integer, 0}, + {"segmentationProhibited", s_nullTag, true, TcapXApplication::Null, 0}, + {"immediateResponsePreferred", s_ctxtPrim_1_Tag, true, TcapXApplication::Null, 0}, + {"re-synchronisationInfo", s_sequenceTag, true, TcapXApplication::Sequence, s_resynchronisationInfo}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"requestingNodeType", s_ctxtPrim_3_Tag, true, TcapXApplication::Enumerated, s_requestingNodeType}, + {"requestingPLMN-Id", s_ctxtPrim_4_Tag, true, TcapXApplication::TBCD, 0}, + {"numberOfRequestedAdditional-Vectors", s_ctxtPrim_5_Tag, true, TcapXApplication::Integer, 0}, + {"additionalVectorsAreForEPS", s_ctxtPrim_6_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendAuthenticationInfoRes[] = { + {"sendAuthenticationInfoRes-v2", s_sequenceTag, true, TcapXApplication::SequenceOf, s_authenticationSet}, + {"sendAuthenticationInfoRes-v3", s_ctxtCstr_3_Tag, true, TcapXApplication::Sequence, s_authenticationRes}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_restoreDataArgs[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"lmsi", s_hexTag, true, TcapXApplication::HexString, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"vlr-Capability", s_ctxtCstr_6_Tag, true, TcapXApplication::Sequence, s_vlrCapability}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_restoreDataRes[] = { + {"hlr-Number", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"msNotReachable", s_nullTag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendIMSIArgs[] = { + {"msisdn", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendIMSIRes[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_unstructuredSSArgs[] = { + {"ussd-DataCodingScheme", s_hexTag, false, TcapXApplication::HexString, 0}, + {"ussd-String", s_hexTag, false, TcapXApplication::GSMString, 0}, + {"alertingPattern", s_hexTag, true, TcapXApplication::Enumerated, s_alertPattern}, + {"msisdn", s_ctxtPrim_0_Tag, true, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_unstructuredSSRes[] = { + {"ussd-DataCodingScheme", s_hexTag, false, TcapXApplication::HexString, 0}, + {"ussd-String", s_hexTag, false, TcapXApplication::GSMString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_alertServiceCentreArgs[] = { + {"msisdn", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"serviceCentreAddress", s_hexTag, false, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_readyForSMArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"alertReason", s_enumTag, false, TcapXApplication::Enumerated, s_alertReason}, + {"alertReasonIndicator", s_nullTag, true, TcapXApplication::Null, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_purgeMSArgs[] = { + {"imsi", s_hexTag, false, TcapXApplication::TBCD, 0}, + {"vlr-Number", s_ctxtPrim_0_Tag, true, TcapXApplication::AddressString, 0}, + {"sgsn-Number", s_ctxtPrim_1_Tag, true, TcapXApplication::AddressString, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_purgeMSRes[] = { + {"freezeTMSI", s_ctxtPrim_0_Tag, true, TcapXApplication::Null, 0}, + {"freezeP-TMSI", s_ctxtPrim_1_Tag, true, TcapXApplication::Null, 0}, + {"extensionContainer",s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_anyTimeInterrogationArgs[] = { + {"subscriberIdentity", s_ctxtCstr_0_Tag, false, TcapXApplication::Choice, s_subscriberIdentity}, + {"requestedInfo", s_ctxtCstr_1_Tag, false, TcapXApplication::Sequence, s_requestedInfo}, + {"gsmSCF-Address", s_ctxtPrim_3_Tag, false, TcapXApplication::AddressString, 0}, + {"extensionContainer", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_anyTimeInterrogationRes[] = { + {"subscriberInfo", s_sequenceTag, false, TcapXApplication::Sequence, s_subscriberInfo}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_setReportingStateArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, true, TcapXApplication::TBCD, 0}, + {"lmsi", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"ccbs-Monitoring", s_ctxtPrim_2_Tag, true, TcapXApplication::Enumerated, s_reportingState}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_setReportingStateRes[] = { + {"subscriberInfo", s_sequenceTag, false, TcapXApplication::Sequence, s_subscriberInfo}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_statusReportArgs[] = { + {"imsi", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + {"eventReportData", s_ctxtCstr_1_Tag, true, TcapXApplication::Sequence, s_eventReportData}, + {"callReportdata", s_ctxtCstr_2_Tag, true, TcapXApplication::Sequence, s_callReportData}, + {"extensionContainer", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_statusReportRes[] = { + {"extensionContainer", s_ctxtCstr_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Operation s_mapOps[] = { + {"updateLocation", true, 2, + s_sequenceTag, s_updateLocationArgs, + s_sequenceTag, s_updateLocationRes + }, + {"cancelLocation", true, 3, + s_ctxtCstr_3_Tag, s_cancelLocationArgs, + s_sequenceTag, s_extensionContainerRes + }, + {"provideRoamingNumber", true, 4, + s_sequenceTag, s_provideRoamingNumberArgs, + s_sequenceTag, s_provideRoamingNumberRes + }, + {"insertSubscriberData", true, 7, + s_sequenceTag, s_insertSubscriberDataArgs, + s_sequenceTag, s_insertSubscriberDataRes + }, + {"deleteSubscriberData", true, 8, + s_sequenceTag, s_deleteSubscriberDataArgs, + s_sequenceTag, s_deleteSubscriberDataRes + }, + {"registerSS", true, 10, + s_sequenceTag, s_registerSSArgs, + s_noTag, s_extSSInfoChoice + }, + {"eraseSS", true, 11, + s_sequenceTag, s_ssCodeArgs, + s_noTag, s_extSSInfoChoice + }, + {"activateSS", true, 12, + s_sequenceTag, s_ssCodeArgs, + s_noTag, s_extSSInfoChoice + }, + {"deactivateSS", true, 13, + s_sequenceTag, s_ssCodeArgs, + s_noTag, s_extSSInfoChoice + }, + {"interrogateSS", true, 14, + s_sequenceTag, s_ssCodeArgs, + s_noTag, s_InterrogateSSRes + }, + {"registerPassword", true, 17, + s_noTag, s_registerPasswordArgs, + s_noTag, s_registerPasswordRes + }, + {"getPassword", true, 18, + s_noTag, s_getPasswordArgs, + s_noTag, s_getPasswordRes + }, + {"updateGprsLocation", true, 23, + s_sequenceTag, s_updateGprsLocationArgs, + s_sequenceTag, s_updateGprsLocationRes + }, + {"sendRoutingInfoForGprs", true, 24, + s_sequenceTag, s_sendRoutingInfoForGprsArgs, + s_sequenceTag, s_sendRoutingInfoForGprsRes + }, + {"failureReport", true, 25, + s_sequenceTag, s_failureReportArgs, + s_sequenceTag, s_failureReportRes + }, + {"reset", true, 37, + s_sequenceTag, s_resetArgs, + s_noTag, 0 + }, + {"forwardCheckSS-Indication", true, 38, + s_noTag, 0, + s_noTag, 0 + }, + {"sendRoutingInfoForSM", true, 45, + s_sequenceTag, s_sendRoutingInfoForSMArgs, + s_sequenceTag, s_sendRoutingInfoForSMRes + }, + {"activateTraceMode", true, 50, + s_sequenceTag, s_activateTraceModeArgs, + s_sequenceTag, s_traceModeRes + }, + {"deactivateTraceMode", true, 51, + s_sequenceTag, s_deactivateTraceModeArgs, + s_sequenceTag, s_traceModeRes + }, + {"sendAuthenticationInfo", true, 56, + s_noTag, s_sendAuthenticationInfoArgs, + s_noTag, s_sendAuthenticationInfoRes + }, + {"restoreData", true, 57, + s_sequenceTag, s_restoreDataArgs, + s_sequenceTag, s_restoreDataRes + }, + {"sendIMSI", true, 58, + s_noTag, s_sendIMSIArgs, + s_noTag, s_sendIMSIRes + }, + {"processUnstructuredSS-Request", true, 59, + s_sequenceTag, s_unstructuredSSArgs, + s_sequenceTag, s_unstructuredSSRes + }, + {"unstructuredSS-Request", true, 60, + s_sequenceTag, s_unstructuredSSArgs, + s_sequenceTag, s_unstructuredSSRes + }, + {"unstructuredSS-Notify", true, 61, + s_sequenceTag, s_unstructuredSSArgs, + s_noTag, 0 + }, + {"alertServiceCentre", true, 64, + s_sequenceTag, s_alertServiceCentreArgs, + s_noTag, 0 + }, + {"readyForSM", true, 66, + s_sequenceTag, s_readyForSMArgs, + s_sequenceTag, s_extensionContainerRes + }, + {"purgeMS", true, 67, + s_ctxtCstr_3_Tag, s_purgeMSArgs, + s_sequenceTag, s_purgeMSRes + }, + {"anyTimeInterrogation", true, 71, + s_sequenceTag, s_anyTimeInterrogationArgs, + s_sequenceTag, s_anyTimeInterrogationRes + }, + {"setReportingState", true, 73, + s_sequenceTag, s_setReportingStateArgs, + s_sequenceTag, s_setReportingStateRes + }, + {"statusReport", true, 74, + s_sequenceTag, s_statusReportArgs, + s_sequenceTag, s_statusReportRes + }, + {"", false, 0, + s_noTag, 0, + s_noTag, 0 + }, +}; + +static const Capability s_camelCapab[] = { + {"Camel", {"initialDP", "assistRequestInstructions", "establishTemporaryConnection", "disconnectForwardConnection", + "connectToResource", "connect", "releaseCall", "requestReportBCSMEvent","eventReportBCSM", "continue", "resetTimer", + "furnishChargingInformation", "applyCharging", "applyChargingReport", "callInformationReport", "callInformationRequest", + "sendChargingInformation", "playAnnouncement", "promptAndCollectUserInformation", "specializedResourceReport", + "cancel", "activityTest", ""}}, + {0, {""}}, +}; + +static TokenDict s_eventTypeBCSM[] = { + {"collectedInfo", 2}, + {"routeSelectFailure", 4}, + {"oCalledPartyBusy", 5}, + {"oNoAnswer", 6}, + {"oAnswer", 7}, + {"oDisconnect", 9}, + {"oAbandon", 10}, + {"termAttemptAuthorized", 12}, + {"tBusy", 13}, + {"tNoAnswer", 14}, + {"tAnswer", 15}, + {"tDisconnect", 17}, + {"tAbandon", 18}, + {"", 0} +}; + +static TokenDict s_naCICSelectionType[] = { + {"not-indicated", 0x00}, + {"subscribed-not-dialed", 0x01}, + {"subscribed-and-dialed", 0x02}, + {"subscribed-dialing-undeterminded", 0x03}, + {"dialed-CIC-not-subscribed", 0x04}, + {"", 0} +}; + +static const Parameter s_naCarrierInformationSeq[] = { + {"naCarrierId", s_ctxtPrim_0_Tag, true, TcapXApplication::TBCD, 0}, //Carrier digits + {"naCICSelectionType", s_ctxtPrim_1_Tag, true, TcapXApplication::Enumerated, s_naCICSelectionType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_initialDPArgExtension[] = { + {"naCarrierInformation", s_ctxtCstr_0_Tag, true, TcapXApplication::Sequence, s_naCarrierInformationSeq}, + {"gmscAddress", s_ctxtPrim_1_Tag, true, TcapXApplication::AddressString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static Parameter s_bearerCap[] = { + {"bearerCap", s_ctxtPrim_0_Tag, false, TcapXApplication::UserServiceInfo, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_initialDPArgs[] = { + {"serviceKey", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"calledPartyNumber", s_ctxtPrim_2_Tag, true, TcapXApplication::CalledPartyNumber, 0}, + {"callingPartyNumber", s_ctxtPrim_3_Tag, true, TcapXApplication::CallingPartyNumber, 0}, + {"callingPartysCategory", s_ctxtPrim_5_Tag, true, TcapXApplication::Enumerated, s_category}, + // TODO decode iPSSPCapabilities according to ETSI TS 101 046 V7.1.0 (2000-07) page 42 + {"iPSSPCapabilities", s_ctxtPrim_8_Tag, true, TcapXApplication::HexString, 0}, // might need further decoding + {"locationNumber", s_ctxtPrim_10_Tag, true, TcapXApplication::LocationNumber, 0}, + {"originalCalledPartyID", s_ctxtPrim_12_Tag, true, TcapXApplication::OriginalCalledNumber, 0}, + {"extensions", s_ctxtCstr_15_Tag, true, TcapXApplication::HexString, 0}, + {"highLayerCompatibility", s_ctxtPrim_23_Tag, true, TcapXApplication::HiLayerCompat, 0}, // might need further decoding + {"additionalCallingPartyNumber", s_ctxtPrim_25_Tag, true, TcapXApplication::TBCD, 0}, // not sure about this either + {"bearerCapability", s_ctxtPrim_27_Tag, true, TcapXApplication::Choice, s_bearerCap}, + {"eventTypeBCSM", s_ctxtPrim_28_Tag, true, TcapXApplication::Enumerated, s_eventTypeBCSM}, + {"redirectingPartyID", s_ctxtPrim_29_Tag, true, TcapXApplication::RedirectingNumber, 0}, + {"redirectionInformation", s_ctxtPrim_30_Tag, true, TcapXApplication::RedirectionInformation, 0}, + {"imsi", s_ctxtPrim_50_Tag, true, TcapXApplication::TBCD, 0}, + {"subscriberState", s_ctxtPrim_51_Tag, true, TcapXApplication::Choice, s_subscriberState}, + {"locationInformation", s_ctxtPrim_52_Tag, true, TcapXApplication::Sequence, s_locationInformation}, + {"ext-basicServiceCode", s_ctxtPrim_53_Tag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"callReferenceNumber", s_ctxtPrim_54_Tag, true, TcapXApplication::HexString, 0}, + {"mscAddress", s_ctxtPrim_55_Tag, true, TcapXApplication::AddressString, 0}, + {"calledPartyBCDNumber", s_ctxtPrim_56_Tag, true, TcapXApplication::AddressString, 0}, //should be checked + {"timeAndTimezone", s_ctxtPrim_57_Tag, true, TcapXApplication::TBCD, 0},//might need special decoding + {"gsm-ForwardingPending", s_ctxtPrim_58_Tag, true, TcapXApplication::Null, 0}, + {"initialDPArgExtension", s_ctxtCstr_59_Tag, true, TcapXApplication::Sequence, s_initialDPArgExtension}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_monitorMode[] = { + {"interrupted", 0x00}, + {"notifyAndContinue", 0x01}, + {"transparent", 0x02}, + {"", 0}, +}; + +static const TokenDict s_legType[] = { + {"leg1", 0x01}, + {"leg2", 0x02}, + {"", 0}, +}; + +static const Parameter s_legID[] = { + {"sendingSideID", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_legType}, + {"receivingSideID", s_ctxtPrim_1_Tag, false, TcapXApplication::Enumerated, s_legType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_DPSpecificCriteria[] = { + {"applicationTimer",s_ctxtPrim_1_Tag, false, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_bcsmEventSeq[] = { + {"eventTypeBCSM", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_eventTypeBCSM}, + {"monitorMode", s_ctxtPrim_1_Tag, false, TcapXApplication::Enumerated, s_monitorMode}, + {"legID", s_ctxtPrim_2_Tag, true, TcapXApplication::Choice, s_legID}, + {"dPSpecificCriteria", s_ctxtPrim_30_Tag,true, TcapXApplication::Choice, s_DPSpecificCriteria}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_bcsmEvent[] = { + {"bcsmEvent", s_sequenceTag, false, TcapXApplication::Sequence, s_bcsmEventSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_requestReportBCSMEventArgs[] = { + {"bcsmEvents", s_ctxtCstr_0_Tag, false, TcapXApplication::SequenceOf, s_bcsmEvent}, + {"extensions", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_receivingSideID[] = { + {"receivingSideID", s_ctxtPrim_1_Tag, false, TcapXApplication::Enumerated, s_legType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_failureCause[] = { +// failureCause := Cause (should find encoding, for now treated as hex string) + {"failureCause", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_busyCause[] = { +// busyCause := Cause (should find encoding, for now treated as hex string) + {"busyCause", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_releaseCause[] = { +// releaseCause := Cause (should find encoding, for now treated as hex string) + {"releaseCause", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_tNoAsnwerInfo[] = { + {"callForwarded", s_ctxtPrim_50_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_tBusyInfo[] = { +// busyCause := Cause (should find encoding, for now treated as hex string) + {"busyCause", s_ctxtPrim_0_Tag, true, TcapXApplication::HexString, 0}, + {"callForwarded", s_ctxtPrim_50_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_eventSpecificInformationBCSM[] = { + {"routeSelectFailureSpecificInfo", s_ctxtCstr_2_Tag, false, TcapXApplication::Sequence, s_failureCause}, + {"oCalledPartyBusySpecificInfo", s_ctxtCstr_3_Tag, false, TcapXApplication::Sequence, s_busyCause}, + {"oNoAnswerSpecificInfo", s_ctxtCstr_4_Tag, false, TcapXApplication::Sequence, 0}, + {"oAnswerSpecificInfo", s_ctxtCstr_5_Tag, false, TcapXApplication::Sequence, 0}, + {"oDisconnectSpecificInfo", s_ctxtCstr_7_Tag, false, TcapXApplication::Sequence, s_releaseCause}, + {"tBusySpecificInfo", s_ctxtCstr_8_Tag, false, TcapXApplication::Sequence, s_tBusyInfo}, + {"tNoAnswerSpecificInfo", s_ctxtCstr_9_Tag, false, TcapXApplication::Sequence, s_tNoAsnwerInfo}, + {"tAnswerSpecificInfo", s_ctxtCstr_10_Tag, false, TcapXApplication::Sequence, 0}, + {"tDisconnectSpecificInfo", s_ctxtCstr_12_Tag, false, TcapXApplication::Sequence, s_releaseCause}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_messageType[] = { + {"request", 0x00}, + {"notification", 0x01}, + {"", 0}, +}; + +static const Parameter s_miscCallInfoSeq[] = { + {"messageType", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_messageType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_eventReportBCSMArgs[] = { + {"eventTypeBCSM", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_eventTypeBCSM}, + {"eventSpecificInformationBCSM", s_ctxtPrim_2_Tag, true, TcapXApplication::Choice, s_eventSpecificInformationBCSM}, + {"legID", s_ctxtPrim_3_Tag, true, TcapXApplication::Choice, s_receivingSideID}, + {"miscCallInfo", s_ctxtCstr_4_Tag, false, TcapXApplication::Sequence, s_miscCallInfoSeq}, + {"extensions", s_ctxtCstr_5_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_calledPartyNumber[] = { + {"calledPartyNumber", s_hexTag, false, TcapXApplication::CalledPartyNumber, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_genericNumber[] = { + {"genericNumber", s_hexTag, false, TcapXApplication::GenericNumber, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_naInfoSeq[] = { + {"naCarrierInformation", s_ctxtCstr_0_Tag, true, TcapXApplication::Sequence, s_naCarrierInformationSeq}, +// NA Oli information takes the same value as defined in ANSI ISUP T1.113 + {"naOliInfo", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"naChargeNumber", s_ctxtPrim_2_Tag, true, TcapXApplication::ChargeNumber, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_connectArgs[] = { + {"destinationRoutingAddress", s_ctxtCstr_0_Tag, false, TcapXApplication::SequenceOf, s_calledPartyNumber}, + //alertingPattern decoded as hex string, encoding in GSM 09.02 (ref. 14) + {"alertingPattern", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"originalCalledPartyID", s_ctxtPrim_6_Tag, true, TcapXApplication::OriginalCalledNumber, 0}, + {"extensions", s_ctxtCstr_10_Tag, true, TcapXApplication::HexString, 0}, + {"callingPartysCategory", s_ctxtPrim_28_Tag, true, TcapXApplication::Enumerated, s_category}, + {"redirectingPartyID", s_ctxtPrim_29_Tag, true, TcapXApplication::RedirectingNumber, 0}, + {"redirectionInformation", s_ctxtPrim_30_Tag, true, TcapXApplication::RedirectionInformation, 0}, + {"genericNumbers", s_ctxtCstr_14_Tag, true, TcapXApplication::SetOf, s_genericNumber}, + {"suppressionOfAnnouncement", s_ctxtPrim_55_Tag, true, TcapXApplication::Null, 0}, + {"oCSIApplicable", s_ctxtPrim_56_Tag, true, TcapXApplication::Null, 0}, + {"na-Info", s_ctxtCstr_57_Tag, true, TcapXApplication::Sequence, s_naInfoSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_releaseCallArgs[] = { + // TODO - decode Cause (ETS 300 356-1 [3] Cause and Location values refer to Q.850). + {"cause", s_hexTag, false, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_assistRequestInstructionsArgs[] = { + // Defined as Digits - see for encoding ETS 300 356-1 [3] Generic Number + {"correlationID", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + // ETSI TS 101 046 - GSM CAP specification (CAMEL) page 42 for further decoding + {"iPSSPCapabilities", s_ctxtPrim_2_Tag, false, TcapXApplication::HexString, 0}, + {"extensions", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_bothwayThroughConnectionInd[] = { + {"bothwayPathRequired", 0x00}, + {"bothwayPathNotRequired", 0x01}, + {"", 0}, +}; + +static const Parameter s_serviceInteractionIndicatorsTwo[] = { +// FROM CS2-datatypes { ccitt(0) identified-organization(4) etsi(0) inDomain(1) +// in-network(1) CS2(20) modules(0) in-cs2-datatypes (0) version1(0)} + {"bothwayThroughConnectionInd", s_ctxtPrim_2_Tag, true, TcapXApplication::Enumerated, s_bothwayThroughConnectionInd}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_establishTemporaryConnectionArgs[] = { + //Digits - see for encoding ETS 300 356-1 [3] , definde ETSI TS 101 046 - GSM CAP specification (CAMEL) page 42 + {"assistingSSPIPRoutingAddress", s_ctxtPrim_0_Tag, false, TcapXApplication::TBCD, 0}, + // Defined as Digits - see for encoding ETS 300 356-1 [3] Generic Number + {"correlationID", s_ctxtPrim_1_Tag, true, TcapXApplication::TBCD, 0}, + {"scfID", s_ctxtPrim_3_Tag, true, TcapXApplication::HexString, 0}, + {"extensions", s_ctxtCstr_4_Tag, true, TcapXApplication::HexString, 0}, + {"serviceInteractionIndicatorsTwo",s_ctxtCstr_7_Tag, true, TcapXApplication::Sequence, s_serviceInteractionIndicatorsTwo}, + {"na-Info", s_ctxtCstr_50_Tag,true, TcapXApplication::Sequence, s_naInfoSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_resourceAddress[] = { + {"ipRoutingAddress", s_ctxtPrim_0_Tag, false, TcapXApplication::CalledPartyNumber, 0}, + {"none", s_ctxtPrim_3_Tag, false, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_connectToResourceArgs[] = { + {"resourceAddress", s_noTag, false, TcapXApplication::Choice, s_resourceAddress}, + {"extensions", s_ctxtCstr_4_Tag, true, TcapXApplication::HexString, 0}, + {"serviceInteractionIndicatorsTwo",s_ctxtCstr_7_Tag, true, TcapXApplication::Sequence, s_serviceInteractionIndicatorsTwo}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_timerID[] = { + {"tssf", 0x00}, + {"", 0x01}, +}; + +static const Parameter s_resetTimerArgs[] = { + {"timerID", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_timerID}, + {"timervalue", s_ctxtPrim_1_Tag, false, TcapXApplication::Integer, 0}, + {"extensions", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendingSideID[] = { + {"sendingSideID", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_legType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_fCIBCCCAMELsequenceSeq[] = { + {"freeFormatData", s_ctxtPrim_0_Tag, false, TcapXApplication::HexString, 0}, + {"partyToCharge", s_ctxtPrim_1_Tag, false, TcapXApplication::Choice, s_sendingSideID}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_fCIBillingChargingCharacteristicsChoice[] = { + {"fCIBCCCAMELsequence1", s_ctxtPrim_0_Tag, false, TcapXApplication::Sequence, s_fCIBCCCAMELsequenceSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_FCIBillingChargingCharacteristics[] = { + {"fCIBillingChargingCharacteristics", s_hexTag, false, TcapXApplication::Choice, s_fCIBillingChargingCharacteristicsChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_releaseIfdurationExceeded[] = { + {"tone", s_ctxtPrim_1_Tag, false, TcapXApplication::Bool, 0}, + {"extensions", s_ctxtCstr_10_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_timeDuratinChargingSeq[] = { + {"maxCallPeriodDuration", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"releaseIfdurationExceeded", s_ctxtCstr_1_Tag, true, TcapXApplication::Sequence, s_releaseIfdurationExceeded}, + {"tariffSwitchInterval", s_ctxtPrim_2_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const Parameter s_aChBillingChargingCharacteristics[] = { + {"timeDurationCharging", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_timeDuratinChargingSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_applyChargingArgs[] = { + {"aChBillingChargingCharacteristics", s_ctxtPrim_0_Tag, false, TcapXApplication::Choice, s_aChBillingChargingCharacteristics}, + {"partyToCharge", s_ctxtPrim_2_Tag, false, TcapXApplication::Choice, s_sendingSideID}, + {"extensions", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString,0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_timeIfTariffSwitchSeq[] = { + {"timeSinceTariffSwitch", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"tariffSwitchInterval", s_ctxtPrim_1_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_timeInformation[] = { + {"timeIfNoTariffSwitch", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"timeIfTariffSwitch", s_ctxtCstr_1_Tag, false, TcapXApplication::Sequence, s_timeIfTariffSwitchSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_timeDurationChargingResSeq[] = { + {"partyToCharge", s_ctxtPrim_0_Tag, false, TcapXApplication::Choice, s_receivingSideID}, + {"timeInformation", s_ctxtPrim_1_Tag, false, TcapXApplication::Choice, s_timeInformation}, + {"callActive", s_ctxtPrim_2_Tag, false, TcapXApplication::Bool, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_callResultChoice[] = { + {"timeDurationChargingResult", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_timeDurationChargingResSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_callResult[] = { + {"callResult", s_hexTag, false, TcapXApplication::Choice, s_callResultChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_requestedInformationType[] = { + {"callAttemptElapsedTime", 0x00}, + {"callStopTime", 0x01}, + {"callConnectedElapsedTime", 0x02}, + {"releaseCause", 0x1e}, + {"", 0xff}, +}; + +static const Parameter s_requestedInformationValue[] = { + {"callAttemptElapsedTimeValue", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"callStopTimeValue", s_ctxtPrim_1_Tag, false, TcapXApplication::TBCD, 0}, + {"callConnectedElapsedTimeValue",s_ctxtPrim_2_Tag, false, TcapXApplication::Integer, 0}, + {"releaseCauseValue", s_ctxtPrim_30_Tag,false, TcapXApplication::HexString,0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_requestedInformationSeq[] = { + {"requestedInformationType", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_requestedInformationType}, + {"requestedInformationValue", s_ctxtPrim_1_Tag, false, TcapXApplication::Choice, s_requestedInformationValue}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_requestedInformation[] = { + {"requestedInformation", s_sequenceTag, false, TcapXApplication::Sequence, s_requestedInformationSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_callInformationArgs[] = { + {"requestedInformationList", s_ctxtCstr_0_Tag, false,TcapXApplication::SequenceOf, s_requestedInformation}, + {"extensions", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"legID", s_ctxtPrim_3_Tag, true, TcapXApplication::Choice, s_receivingSideID}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_requestedInfoType[] = { + {"requestedInformationType", s_enumTag, false, TcapXApplication::Enumerated, s_requestedInformationType}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_callInformationRequestArgs[] = { + {"requestedInformationTypeList", s_ctxtCstr_0_Tag, false,TcapXApplication::SequenceOf, s_requestedInfoType}, + {"extensions", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"legID", s_ctxtPrim_3_Tag, true, TcapXApplication::Choice, s_sendingSideID}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_CAIGSM0224Seq[] = { + {"e1", s_ctxtPrim_0_Tag, true, TcapXApplication::Integer, 0}, + {"e2", s_ctxtPrim_1_Tag, true, TcapXApplication::Integer, 0}, + {"e3", s_ctxtPrim_2_Tag, true, TcapXApplication::Integer, 0}, + {"e4", s_ctxtPrim_3_Tag, true, TcapXApplication::Integer, 0}, + {"e5", s_ctxtPrim_4_Tag, true, TcapXApplication::Integer, 0}, + {"e6", s_ctxtPrim_5_Tag, true, TcapXApplication::Integer, 0}, + {"e7", s_ctxtPrim_6_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_AOCSubsequentSeq[] = { + {"cAI-GSM0224", s_ctxtCstr_0_Tag, false,TcapXApplication::Sequence, s_CAIGSM0224Seq}, + {"tariffSwitchInterval", s_ctxtPrim_1_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_AOCBeforeAnswerSeq[] = { + {"aOCInitial", s_ctxtCstr_0_Tag, false,TcapXApplication::Sequence, s_CAIGSM0224Seq}, + {"aOCSubsequent", s_ctxtCstr_1_Tag, true, TcapXApplication::Sequence, s_AOCSubsequentSeq}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_sCIBillingChargingCharacteristics[] = { + {"aOCBeforeAnswer", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_AOCBeforeAnswerSeq}, + {"aOCAfterAnswer", s_ctxtCstr_1_Tag, true, TcapXApplication::Sequence, s_AOCSubsequentSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_sendChargingInformationArgs[] = { + {"sCIBillingChargingCharacteristics", s_ctxtPrim_0_Tag, false, TcapXApplication::Choice, s_sCIBillingChargingCharacteristics}, + {"partyToCharge", s_ctxtPrim_1_Tag, false, TcapXApplication::Choice, s_sendingSideID}, + {"extensions", s_ctxtCstr_2_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_textSeq[] = { + {"messageContent", s_ctxtPrim_0_Tag, false, TcapXApplication::AppString, 0}, + {"attributes", s_ctxtPrim_1_Tag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_elementaryMessageID[] = { + {"elementaryMessageID", s_intTag, false, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_variablePartChoice[] = { + {"integer", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"number", s_ctxtPrim_1_Tag, false, TcapXApplication::TBCD, 0}, + {"time", s_ctxtPrim_2_Tag, false, TcapXApplication::TBCD, 0}, + {"date", s_ctxtPrim_3_Tag, false, TcapXApplication::TBCD, 0}, + {"price", s_ctxtPrim_4_Tag, false, TcapXApplication::TBCD, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_variablePart[] = { + {"variablePart", s_noTag, false, TcapXApplication::Choice, s_variablePartChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_variableMessageSeq[] = { + {"elementaryMessageID", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"variableParts", s_ctxtCstr_1_Tag, false, TcapXApplication::SequenceOf, s_variablePart}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_messageID[] = { + {"elementaryMessageID", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"text", s_ctxtCstr_1_Tag, false, TcapXApplication::Sequence, s_textSeq}, + {"elementaryMessageIDs",s_ctxtCstr_29_Tag,false, TcapXApplication::SequenceOf, s_elementaryMessageID}, + {"variableMessage", s_ctxtCstr_30_Tag,false, TcapXApplication::Sequence, s_variableMessageSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_inbandInfoSeq[] = { + {"messageID", s_ctxtPrim_0_Tag, false,TcapXApplication::Choice, s_messageID}, + {"numberOfRepetitions", s_ctxtPrim_1_Tag, true, TcapXApplication::Integer, 0}, + {"duration", s_ctxtPrim_2_Tag, true, TcapXApplication::Integer, 0}, + {"interval", s_ctxtPrim_3_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false,TcapXApplication::None, 0}, +}; + +static const Parameter s_toneSeq[] = { + {"toneID", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"duration", s_ctxtPrim_1_Tag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_informationToSend[] = { + {"inbandInfo", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_inbandInfoSeq}, + {"tone", s_ctxtCstr_1_Tag, false, TcapXApplication::Sequence, s_toneSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_playAnnouncementArgs[] = { + {"informationToSend", s_ctxtPrim_0_Tag, false, TcapXApplication::Choice, s_informationToSend}, + {"disconnectFromIPForbidden", s_ctxtPrim_1_Tag, false, TcapXApplication::Bool, 0}, + {"requestAnnouncementComplete", s_ctxtPrim_2_Tag, false, TcapXApplication::Bool, 0}, + {"extensions", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString,0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_errorTreatment[] = { + {"stdErrorAndInfo", 0x00}, + {"help", 0x01}, + {"repeatPrompt", 0x02}, + {"", 0xff}, +}; + +static const Parameter s_collectedInfoSeq[] = { + {"minimumNbOfDigits", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"maximumNbOfDigits", s_ctxtPrim_1_Tag, false, TcapXApplication::Integer, 0}, + {"endOfReplyDigit", s_ctxtPrim_2_Tag, true, TcapXApplication::HexString, 0}, + {"cancelDigit", s_ctxtPrim_3_Tag, true, TcapXApplication::HexString, 0}, + {"startDigit", s_ctxtPrim_4_Tag, true, TcapXApplication::HexString, 0}, + {"firstDigitTimeOut", s_ctxtPrim_5_Tag, false, TcapXApplication::Integer, 0}, + {"interDigitTimeOut", s_ctxtPrim_6_Tag, false, TcapXApplication::Integer, 0}, + {"errorTreatment", s_ctxtPrim_7_Tag, false, TcapXApplication::Enumerated,s_errorTreatment}, + {"interruptableAnnInd", s_ctxtPrim_8_Tag, false, TcapXApplication::Bool, 0}, + {"voiceInformation", s_ctxtPrim_9_Tag, false, TcapXApplication::Bool, 0}, + {"voiceBack", s_ctxtPrim_10_Tag, false, TcapXApplication::Bool, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_collectedInfo[] = { + {"collectedDigits", s_ctxtCstr_0_Tag, false, TcapXApplication::Sequence, s_collectedInfoSeq}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_promptAndCollectUserInformationArgs[] = { + {"collectedInfo", s_ctxtPrim_0_Tag, false, TcapXApplication::Choice, s_collectedInfo}, + {"disconnectFromIPForbidden", s_ctxtPrim_1_Tag, false, TcapXApplication::Bool, 0}, + {"informationToSend", s_ctxtPrim_2_Tag, true, TcapXApplication::Choice, s_informationToSend}, + {"extensions", s_ctxtCstr_3_Tag, true, TcapXApplication::HexString,0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_specializedResourceReportArgs[] = { + {"specializedResourceReportArgs", s_nullTag, false, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_cancelChoice[] = { + {"invokeID", s_ctxtPrim_0_Tag, false, TcapXApplication::Integer, 0}, + {"allRequests", s_ctxtPrim_1_Tag, false, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_cancelArgs[] = { + {"cancelArg", s_noTag, false, TcapXApplication::Choice, s_cancelChoice}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Operation s_camelOps[] = { + {"initialDP", true, 0, + s_sequenceTag, s_initialDPArgs, + s_noTag, 0 + }, + {"assistRequestInstructions", true, 16, + s_sequenceTag, s_assistRequestInstructionsArgs, + s_noTag, 0 + }, + {"establishTemporaryConnection", true, 17, + s_sequenceTag, s_establishTemporaryConnectionArgs, + s_noTag, 0 + }, + {"disconnectForwardConnection", true, 18, + s_noTag, 0, + s_noTag, 0 + }, + {"connectToResource", true, 19, + s_sequenceTag, s_connectToResourceArgs, + s_noTag, 0 + }, + {"connect", true, 20, + s_sequenceTag, s_connectArgs, + s_noTag, 0 + }, + {"releaseCall", true, 22, + s_noTag, s_releaseCallArgs, + s_noTag, 0 + }, + {"requestReportBCSMEvent", true, 23, + s_sequenceTag, s_requestReportBCSMEventArgs, + s_noTag, 0 + }, + {"eventReportBCSM", true, 24, + s_sequenceTag, s_eventReportBCSMArgs, + s_noTag, 0 + }, + {"continue", true, 31, + s_noTag, 0, + s_noTag, 0 + }, + {"resetTimer", true, 33, + s_sequenceTag, s_resetTimerArgs, + s_noTag, 0 + }, + {"furnishChargingInformation", true, 34, + s_noTag, s_FCIBillingChargingCharacteristics, + s_noTag, 0 + }, + {"applyCharging", true, 35, + s_sequenceTag, s_applyChargingArgs, + s_noTag, 0 + }, + {"applyChargingReport", true, 36, + s_noTag, s_callResult, + s_noTag, 0 + }, + {"callInformationReport", true, 44, + s_sequenceTag, s_callInformationArgs, + s_noTag, 0 + }, + {"callInformationRequest", true, 45, + s_sequenceTag, s_callInformationRequestArgs, + s_noTag, 0 + }, + {"sendChargingInformation", true, 46, + s_sequenceTag, s_sendChargingInformationArgs, + s_noTag, 0 + }, + {"playAnnouncement", true, 47, + s_sequenceTag, s_playAnnouncementArgs, + s_noTag, 0 + }, + {"promptAndCollectUserInformation", true, 48, + s_sequenceTag, s_promptAndCollectUserInformationArgs, + s_noTag, 0 + }, + {"specializedResourceReport", true, 49, + s_noTag, 0, + s_noTag, 0 + }, + {"cancel", true, 53, + s_noTag, s_cancelChoice, + s_noTag, 0 + }, + {"activityTest", true, 55, + s_noTag, 0, + s_noTag, 0 + }, + {"", false, 0, + s_noTag, 0, + s_noTag, 0 + }, + +}; + + +const TokenDict s_unknownSubscriberDiagnostic[] = { + {"imsiUnknown", 0}, + {"gprsSubscriptionUnknown", 1}, + {0, 0}, +}; + +const TokenDict s_roamingNotAllowedCause[] = { + {"plmnRoamingNotAllowed", 0}, + {"operatorDeterminedBarring", 3}, + {0, 0}, +}; + +const TokenDict s_absentSubscriberReason[] = { + {"imsiDetach", 0 }, + {"restrictedArea", 1 }, + {"noPageResponse", 2 }, + {0, 0}, +}; + +const TokenDict s_smDeliveryFailureCause[] = { + {"memoryCapacityExceeded", 0 }, + {"equipmentProtocolError", 1 }, + {"equipmentNotSM-Equipped ", 2 }, + {"unknownServiceCentre", 3 }, + {"sc-Congestion", 4 }, + {"invalidSME-Address", 5 }, + {"subscriberNotSC-Subscriber", 6 }, + {0, 0}, +}; + +const TokenDict s_networkResource[] = { + {"plmn", 0 }, + {"hlr", 1 }, + {"vlr ", 2 }, + {"pvlr", 3 }, + {"controllingMSC", 4 }, + {"vmsc", 5 }, + {"eir", 6 }, + {"rss", 7 }, + {0, 0}, +}; + +const Parameter s_extensibleSystemFailure[] = { + {"networkResource", s_enumTag, true, TcapXApplication::Enumerated, s_networkResource}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +const Parameter s_systemFailure[] = { + {"networkResource", s_enumTag, false, TcapXApplication::Enumerated, s_networkResource}, + {"extensibleSystemFailure", s_sequenceTag, false, TcapXApplication::Sequence, s_extensibleSystemFailure}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +const TokenDict s_pwRegistrationFailureCause[] = { + {"undetermined", 0 }, + {"invalidFormat", 1 }, + {"newPasswordsMismatch", 2 }, + {0, 0}, +}; + +const TokenDict s_callBarringCause[] = { + {"barringServiceActive", 0 }, + {"operatorBarring", 1 }, + {0, 0}, +}; + +const Parameter s_extensibleCallBarredParam[] = { + {"callBarringCause", s_enumTag, true, TcapXApplication::Enumerated, s_callBarringCause}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"unauthorisedMessageOriginator", s_nullTag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_unknownSubscriberErr[] = { + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"unknownSubscriberDiagnostic", s_enumTag, true, TcapXApplication::Enumerated, s_unknownSubscriberDiagnostic}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_absentsubscriberSMErr[] = { + {"absentSubscriberDiagnosticSM", s_intTag, true, TcapXApplication::Integer, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"additionalAbsentSubscriberDiagnosticSM", s_intTag, true, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_roamingNotAllowedErr[] = { + {"roamingNotAllowedCause", s_enumTag, true, TcapXApplication::Enumerated, s_roamingNotAllowedCause}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_callBarredErr[] = { + {"callBarringCause", s_enumTag, true, TcapXApplication::Enumerated, s_callBarringCause}, + {"extensibleCallBarredParam", s_sequenceTag, true, TcapXApplication::Sequence, s_extensibleCallBarredParam}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_ssIncompatibilityErr[] = { + {"ss-Code", s_ctxtPrim_1_Tag, true, TcapXApplication::Enumerated, s_SSCode}, + {"basicService", s_noTag, true, TcapXApplication::Choice, s_basicServiceCode}, + {"ss-Status", s_ctxtPrim_4_Tag, true, TcapXApplication::Flags, s_ssStatus}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_absentSubscriberErr[] = { + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"absentSubscriberReason", s_ctxtPrim_0_Tag, true, TcapXApplication::Enumerated, s_absentSubscriberReason}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_smDeliveryFailureErr[] = { + {"sm-EnumeratedDeliveryFailureCause", s_enumTag, true, TcapXApplication::Enumerated, s_smDeliveryFailureCause}, + {"diagnosticInfo", s_hexTag, true, TcapXApplication::HexString, 0}, + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_systemFailureErr[] = { + {"systemFailureParam", s_noTag, true, TcapXApplication::Choice, s_systemFailure}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_pwRegistrationFailureErr[] = { + {"pw-RegistrationFailureCause", s_enumTag, true, TcapXApplication::Enumerated, s_pwRegistrationFailureCause}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Parameter s_busySubscriberErr[] = { + {"extensionContainer", s_sequenceTag, true, TcapXApplication::HexString, 0}, + {"ccbs-Possible", s_ctxtPrim_0_Tag, true, TcapXApplication::Null, 0}, + {"ccbs-Busy", s_ctxtPrim_1_Tag, true, TcapXApplication::Null, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const Operation s_mapErrors[] = { + {"unknownSubscriber", true, 1, + s_sequenceTag, s_unknownSubscriberErr, + s_noTag, 0 + }, + {"unknownMSC", true, 3, + s_noTag, 0, + s_noTag, 0 + }, + {"unidentifiedSubscriber", true, 5, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"absentsubscriberSM", true, 6, + s_sequenceTag, s_absentsubscriberSMErr, + s_noTag, 0 + }, + {"unknownEquipment", true, 7, + s_noTag, 0, + s_noTag, 0 + }, + {"roamingNotAllowed", true, 8, + s_sequenceTag, s_roamingNotAllowedErr, + s_noTag, 0 + }, + {"illegalSubscriber", true, 9, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"bearerServiceNotProvisioned", true, 10, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"teleserviceNotProvisioned", true, 11, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"illegalEquipment", true, 12, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"callBarred", true, 13, + s_noTag, s_callBarredErr, + s_noTag, 0 + }, + {"forwardingViolation", true, 14, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"illegalSS-Operation", true, 16, + s_noTag, 0, + s_noTag, 0 + }, + {"ss-ErrorStatus", true, 17, + s_noTag, 0, + s_noTag, 0 + }, + {"ss-NotAvailable", true, 18, + s_noTag, 0, + s_noTag, 0 + }, + {"ss-SubscriptionViolation", true, 19, + s_noTag, 0, + s_noTag, 0 + }, + {"ss-Incompatibility", true, 20, + s_sequenceTag, s_ssIncompatibilityErr, + s_noTag, 0 + }, + {"facilityNotSupported", true, 21, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"absentSubscriber", true, 27, + s_sequenceTag, s_absentSubscriberErr, + s_noTag, 0 + }, + {"sm-DeliveryFailure", true, 32, + s_sequenceTag, s_smDeliveryFailureErr, + s_noTag, 0 + }, + {"messageWaitingListFull", true, 33, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"systemFailure", true, 34, + s_noTag, s_systemFailure, + s_noTag, 0 + }, + {"dataMissing", true, 35, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"unexpectedDataValue", true, 36, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"pw-RegistrationFailure", true, 37, + s_noTag, s_pwRegistrationFailureErr, + s_noTag, 0 + }, + {"negativePW-Check", true, 38, + s_noTag, 0, + s_noTag, 0 + }, + {"noRoamingNumberAvailable", true, 39, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"tracingBufferFull", true, 40, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"numberOfPW-AttemptsViolation", true, 43, + s_noTag, 0, + s_noTag, 0 + }, + {"busySubscriber", true, 45, + s_sequenceTag, s_busySubscriberErr, + s_noTag, 0 + }, + {"noSubscriberReply", true, 46, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"or-NotAllowed", true, 48, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"ati-NotAllowed", true, 49, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"resourceLimitation", true, 51, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"unauthorizedRequestingNetwork", true, 52, + s_sequenceTag, s_extensionContainerRes, + s_noTag, 0 + }, + {"unknownAlphabet", true, 71, + s_noTag, 0, + s_noTag, 0 + }, + {"ussd-Busy", true, 72, + s_noTag, 0, + s_noTag, 0 + }, + {"", false, 0, + s_noTag, 0, + s_noTag, 0 + }, +}; + +static const TokenDict s_problemEnum[] = { + {"unknownOperation", 0x00}, + {"tooLate", 0x01}, + {"operationNotCancellable", 0x02}, + {"", 0xff}, +}; + +static const Parameter s_cancelFailedErr[] = { + {"problem", s_ctxtPrim_0_Tag, false, TcapXApplication::Enumerated, s_problemEnum}, + {"operation", s_ctxtPrim_1_Tag, false, TcapXApplication::Integer, 0}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_requestedInfoEnum[] = { + {"unknownRequestedInfo", 0x01}, + {"requestedInfoNotAvailable", 0x02}, + {"", 0xff}, +}; + +static const Parameter s_requestedInfoErr[] = { + {"requestedInfoError", s_enumTag, false, TcapXApplication::Enumerated, s_requestedInfoEnum}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + +static const TokenDict s_systemFailureEnum[] = { + {"unavailableResources", 0x00}, + {"componentFailure", 0x01}, + {"basicCallProcessingException", 0x02}, + {"resourceStatusFailure", 0x03}, + {"endUserFailure", 0x04}, + {"", 0xff}, +}; + +static const Parameter s_systemFailureCamelErr[] = { + {"systemFailureError", s_enumTag, false, TcapXApplication::Enumerated, s_systemFailureEnum}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const TokenDict s_taskRefusedEnum[] = { + {"generic", 0x00}, + {"unobtainable", 0x01}, + {"congestion", 0x02}, + {"", 0xff}, +}; + +static const Parameter s_taskRefusedErr[] = { + {"taskRefusedError", s_enumTag, false, TcapXApplication::Enumerated, s_taskRefusedEnum}, + {"", s_noTag, false, TcapXApplication::None, 0}, +}; + + +static const Operation s_camelErrors[] = { + {"cancelled", true, 0, + s_noTag, 0, + s_noTag, 0 + }, + {"cancelFailed", true, 1, + s_sequenceTag, s_cancelFailedErr, + s_noTag, 0 + }, + {"eTCFailed", true, 3, + s_noTag, 0, + s_noTag, 0 + }, + {"improperCallerResponse", true, 4, + s_noTag, 0, + s_noTag, 0 + }, + {"missingCustomerRecord", true, 6, + s_noTag, 0, + s_noTag, 0 + }, + {"missingParameter", true, 7, + s_noTag, 0, + s_noTag, 0 + }, + {"parameterOutOfRange", true, 8, + s_noTag, 0, + s_noTag, 0 + }, + {"requestedInfoError", true, 10, + s_noTag, s_requestedInfoErr, + s_noTag, 0 + }, + {"systemFailure", true, 11, + s_noTag, s_systemFailureCamelErr, + s_noTag, 0 + }, + {"taskRefused", true, 12, + s_noTag, s_taskRefusedErr, + s_noTag, 0 + }, + {"unavailableResource", true, 13, + s_noTag, 0, + s_noTag, 0 + }, + {"unexpectedComponentSequence", true, 14, + s_noTag, 0, + s_noTag, 0 + }, + {"unexpectedDataValue", true, 15, + s_noTag, 0, + s_noTag, 0 + }, + {"unexpectedParameter", true, 16, + s_noTag, 0, + s_noTag, 0 + }, + {"unknownLegID", true, 17, + s_noTag, 0, + s_noTag, 0 + }, + {"", false, 0, + s_noTag, 0, + s_noTag, 0 + }, +}; + +static const TokenDict s_appStates[] = { + {"waiting", TcapXApplication::Waiting}, + {"active", TcapXApplication::Active}, + {"shutdown", TcapXApplication::ShutDown}, + {"inactive", TcapXApplication::Inactive}, + {"", 0}, +}; + +static const TokenDict s_userTypes[] = { + {"MAP", TcapXUser::MAP}, + {"CAMEL", TcapXUser::CAMEL}, + {"", 0}, +}; + +static void replace(String& str, char what, char with) +{ + char* c = (char*)str.c_str(); + while (c && *c) { + if(*c == what) + *c = with; + c++; + } +} + +static const Operation* findError(TcapXUser::UserType type, int opCode, bool opLocal = true) +{ + DDebug(&__plugin,DebugAll,"findError(opCode=%d, local=%s)",opCode,String::boolText(opLocal)); + const Operation* ops = (type == TcapXUser::MAP ? s_mapErrors : s_camelErrors); + while (!TelEngine::null(ops->name)) { + if (ops->code == opCode && ops->local == opLocal) + return ops; + ops++; + } + return 0; +} + +static const Operation* findError(TcapXUser::UserType type, const String& op) +{ + DDebug(&__plugin,DebugAll,"findError(opCode=%s)",op.c_str()); + const Operation* ops = (type == TcapXUser::MAP ? s_mapOps : s_camelOps); + while (!TelEngine::null(ops->name)) { + if (op == ops->name) + return ops; + ops++; + } + return 0; +} + +static const Operation* findOperation(TcapXUser::UserType type, int opCode, bool opLocal = true) +{ + DDebug(&__plugin,DebugAll,"findOperation(type=%s,opCode=%d, local=%s)",lookup(type,s_userTypes),opCode,String::boolText(opLocal)); + const Operation* ops = (type == TcapXUser::MAP ? s_mapOps : s_camelOps); + while (!TelEngine::null(ops->name)) { + if (ops->code == opCode && ops->local == opLocal) + return ops; + ops++; + } + return 0; +} + +static const Operation* findOperation(TcapXUser::UserType type, const String& op) +{ + DDebug(&__plugin,DebugAll,"findOperation(opCode=%s)",op.c_str()); + const Operation* ops = (type == TcapXUser::MAP ? s_mapOps : s_camelOps); + while (!TelEngine::null(ops->name)) { + if (op == ops->name) + return ops; + ops++; + } + return 0; +} + +static const Capability* findCapability(TcapXUser::UserType type, const String& opName) +{ + DDebug(&__plugin,DebugAll,"findCapability(opName=%s)",opName.c_str()); + const Capability* cap = (type == TcapXUser::MAP ? s_mapCapab : s_camelCapab); + while (cap->name) { + int index = 0; + while (!TelEngine::null(cap->ops[index])) { + if (opName == cap->ops[index]) + return cap; + index++; + } + cap++; + } + return 0; +} + +static bool findDefCapability(TcapXUser::UserType type, const String& cap) +{ + DDebug(&__plugin,DebugAll,"findDefCapability(opName=%s)",cap.c_str()); + const Capability* caps = (type == TcapXUser::MAP ? s_mapCapab : s_camelCapab); + while (caps->name) { + if (cap == caps->name) + return true; + caps++; + } + return false; +} + +static const AppCtxt* findCtxtFromOid(TcapXUser::UserType type, const String& oid) +{ + DDebug(&__plugin,DebugAll,"findCtxtFromOid(oid=%s)",oid.c_str()); + const AppCtxt* ctxt = (type == TcapXUser::MAP ? s_mapAppCtxt : s_camelAppCtxt); + while (ctxt->name) { + if (oid == ctxt->oid) + return ctxt; + ctxt++; + } + return 0; +} + +static const AppCtxt* findCtxtFromStr(TcapXUser::UserType type, const String& oid) +{ + DDebug(&__plugin,DebugAll,"findCtxtFromStr(ctxt=%s)",oid.c_str()); + const AppCtxt* ctxt = (type == TcapXUser::MAP ? s_mapAppCtxt : s_camelAppCtxt); + while (ctxt->name) { + if (oid == ctxt->name) + return ctxt; + ctxt++; + } + return 0; +} + + +/** + * IDMap + */ +void IDMap::appendID(const char* tcapID, const char* appID) +{ + DDebug(&__plugin,DebugAll,"IDMap::appendID(tcapID=%s,appID=%s)",tcapID,appID); + if (tcapID && appID) + append(new NamedString(appID,tcapID)); +} + +const String& IDMap::findTcapID(const char* appID) +{ + DDebug(&__plugin,DebugAll,"IDMap::findTcapID(appID=%s)",appID); + ObjList* obj = find(appID); + if (obj) { + NamedString* ns = static_cast(obj->get()); + if (!TelEngine::null(ns)) + return (*ns); + } + return String::empty(); +} + +const String& IDMap::findAppID(const char* tcapID) +{ + DDebug(&__plugin,DebugAll,"IDMap::findAppID(tcapID=%s)",tcapID); + for (ObjList* o = skipNull(); o; o = o->skipNext()) { + NamedString* ns = static_cast(o->get()); + if (!TelEngine::null(ns) && (*ns) == tcapID) + return ns->name(); + } + return String::empty(); +} + +void IDMap::removeAppID(const char* appID) +{ + DDebug(&__plugin,DebugAll,"IDMap::removeAppID(appID=%s)",appID); + remove(appID); +} + +/** + * XMLConnection + */ +XMLConnection::XMLConnection(Socket* skt, TcapXApplication* app) + : Thread("XMLConnection"), + m_socket(skt), m_app(app) +{ + Debug(&__plugin,DebugAll,"XMLConnection created with socket=[%p] for application=%s[%p] [%p]",socket,app->toString().c_str(),app,this); + m_parser = new XmlDomParser(app->toString() + "Parser",true); + m_app->ref(); + start(); +} + +XMLConnection::~XMLConnection() +{ + Debug(&__plugin,DebugAll,"XMLConnection destroyed [%p]",this); + if (m_parser) { + delete m_parser; + m_parser = 0; + } + if (m_socket){ + delete m_socket; + m_socket = 0; + } + TelEngine::destruct(m_app); +} + +void XMLConnection::start() +{ + Debug(&__plugin,DebugAll,"XMLConnection start [%p]",this); + m_socket->setBlocking(false); +} + +void XMLConnection::run() +{ + if (!m_socket) + return; + char buffer[2048]; + bool print = false; + for (;;) { + if (!(m_socket && m_socket->valid() && m_parser)) + break; + + Thread::check(); + bool readOk = false, error = false; + if (!m_socket->select(&readOk,0,&error,idleUsec())) + continue; + + if (!readOk || error) { + if (error) { + Debug(&__plugin,DebugInfo,"XMLConnection[%p] : Reading data error: %s (%d)",this,strerror(m_socket->error()), + m_socket->error()); + return; + } + continue; + } + int readSize = m_socket->readData(buffer,sizeof(buffer)); + if (!readSize) { + if (m_socket->canRetry()) { + idle(true); + continue; + } + return; + } + else if (readSize < 0) { + if (m_socket->canRetry()) { + idle(true); + continue; + } + cancel(); + Debug(&__plugin,DebugWarn,"Read error %s(%d) on socket %p in XMLConnection[%p]",strerror(m_socket->error()), + m_socket->error(),m_socket,this); + break; + } + + buffer[readSize] = 0; + XDebug(&__plugin,DebugAll,"READ %d : %s",readSize,buffer); + + int bufferSize = readSize; + while (bufferSize) { + int len = bufferSize; + char* end = strstr(buffer,""); + if (end) { + len = end + strlen("") - buffer + 1; + if (len > bufferSize) + len = bufferSize; + } + String str(buffer,len); + bufferSize -= len; + if (!m_parser) + break; + XDebug(&__plugin,DebugAll,"PUSH = %d, REST = %d, TOTAL = %d, push to parser %s",len,bufferSize,readSize,str.c_str()); + if(!m_parser->parse(str)) { + if (m_parser->error() != XmlSaxParser::Incomplete) { + print = true; + Debug(&__plugin,DebugWarn,"Parser error %s in read data [%p] unparsed type %d, buffer = %s, pushed = %s", + m_parser->getError(),this,m_parser->unparsed(),m_parser->getBuffer().c_str(),str.c_str()); + } + } + else { + XmlFragment* frag = m_parser->fragment(); + if (frag && frag->findElement(frag->getChildren().skipNull(),&s_msgTag,0,false) && m_app) + m_app->receivedXML(frag); + } + ::memmove(buffer,buffer + len,bufferSize + 1); + } + } +} + +void XMLConnection::cleanup() +{ + DDebug(&__plugin,DebugAll,"XMLConnection::cleanup() [%p]",this); + m_app->setIO(0); +} + +bool XMLConnection::writeData(XmlFragment* elem) +{ + if (!elem) + return false; + + String xml; + elem->toString(xml,true); + XDebug(&__plugin,DebugAll,"WRITE : %s",xml.c_str()); + int len = xml.length(); + const char* buffer = xml.c_str(); + while (m_socket && (len > 0)) { + bool writeOk = false,error = false; + if (!m_socket->select(0,&writeOk,&error,idleUsec())) + continue; + if (!writeOk || error) + continue; + int w = m_socket->writeData(buffer,len); + if (w < 0) { + if (!m_socket->canRetry()) { + Debug(&__plugin,DebugWarn,"XMLConnection::writeData(xml=[%p]) [%p] on socket [%p] could not write error : %s", + elem,this,m_socket,strerror(m_socket->error())); + cancel(); + return false; + } + } + else { + buffer += w; + len -= w; + } + } + return true; +} + + + +/** + * XMLConnListener + */ +XMLConnListener::XMLConnListener(TcapXUser* user, const NamedList& sect) + : Thread("XMLConnListener"), + m_user(user) +{ + Debug(&__plugin,DebugAll,"XMLConnListener [%p] created",this); + m_host = sect.getValue(YSTRING("host"),"127.0.0.1"); + m_port = sect.getIntValue(YSTRING("port"),5555); +} + +XMLConnListener::~XMLConnListener() +{ + Debug(&__plugin,DebugAll,"XMLConnListener [%p] destroyed",this); + m_user = 0; +} + +bool XMLConnListener::init() +{ + SocketAddr addr; + + if (!addr.assign(AF_INET) || !addr.host(m_host) || !addr.port(m_port)) { + Debug(m_user,DebugWarn,"Could not assign address=%s:%d for user listener=%s [%p]",m_host.c_str(),m_port, + m_user->toString().c_str(),this); + return false; + } + + if (!m_socket.create(addr.family(),SOCK_STREAM)) { + Debug(m_user,DebugWarn, "Could not create socket for user listener=%s [%p] error %d: %s", + m_user->toString().c_str(),this,m_socket.error(),strerror(m_socket.error())); + return false; + } + + m_socket.setReuse(); + + if (!m_socket.bind(addr)) { + Debug(m_user,DebugWarn,"Could not bind user listener=%s [%p] error %d: %s", + m_user->toString().c_str(),this,m_socket.error(),strerror(m_socket.error())); + return false; + } + if (!m_socket.setBlocking(false) || !m_socket.listen()) + return false; + + return startup(); +} + +void XMLConnListener::run() +{ + for (;;) { + Thread::check(); + idle(); + SocketAddr address; + Socket* newSocket = m_socket.accept(address); + if (!newSocket) { + if (m_socket.canRetry()) + continue; + Debug(m_user,DebugWarn,"Accept error: %s",strerror(m_socket.error())); + break; + } + else { + String addr(address.host()); + addr << ":" << address.port(); + if (!createConn(newSocket,addr)) + Debug(m_user,DebugInfo,"Connection from %s rejected",addr.c_str()); + } + } +} + +bool XMLConnListener::createConn(Socket* skt, String& addr) +{ + if (!skt->valid()) { + delete skt; + return false; + } + if (!skt->setBlocking(false)) { + Debug(m_user,DebugGoOn, "Failed to set TCP socket to nonblocking mode: %s", + strerror(skt->error())); + delete skt; + return false; + } + if (m_user && !m_user->createApplication(skt,addr)) { + delete skt; + return false; + } + return true; +} + +void XMLConnListener::cleanup() +{ + DDebug(m_user,DebugAll,"XMLConnListener::cleanup() [%p]",this); + m_user->setListener(0); +} + +/** + * TcapToXml + */ +const XMLMap TcapToXml::s_xmlMap[] = { + {Regexp("^state$"), "state", "", TcapToXml::Value}, + {Regexp("^error$"), "error", "", TcapToXml::Value}, + {Regexp("^LocalPC$"), "transport.mtp", "", TcapToXml::Element}, + {Regexp("^RemotePC$"), "transport.mtp", "", TcapToXml::Element}, + {Regexp("^sls$"), "transport.mtp", "", TcapToXml::Element}, + {Regexp("^ReturnCause$"), "transport.sccp", "ReturnCause", TcapToXml::Element}, + {Regexp("^CallingPartyAddress\\.gt\\.encoding$"), "transport.sccp.CallingPartyAddress.gt", "encoding", TcapToXml::Attribute}, + {Regexp("^CallingPartyAddress\\.gt\\.np$"), "transport.sccp.CallingPartyAddress.gt", "plan", TcapToXml::Attribute}, + {Regexp("^CallingPartyAddress\\.gt\\.nai$"), "transport.sccp.CallingPartyAddress.gt", "nature", TcapToXml::Attribute}, + {Regexp("^CallingPartyAddress\\.gt\\.tt$"), "transport.sccp.CallingPartyAddress.gt", "translation", TcapToXml::Attribute}, + {Regexp("^CallingPartyAddress\\.gt$"), "transport.sccp.CallingPartyAddress", "gt", TcapToXml::Element}, + {Regexp("^CallingPartyAddress\\.ssn$"), "transport.sccp.CallingPartyAddress", "ssn", TcapToXml::Element}, + {Regexp("^CallingPartyAddress\\.route$"), "transport.sccp.CallingPartyAddress", "route", TcapToXml::Element}, + {Regexp("^CallingPartyAddress\\.pointcode$"), "transport.sccp.CallingPartyAddress", "pointcode", TcapToXml::Element}, + {Regexp("^CallingPartyAddress\\..\\+$"), "transport.sccp.CallingPartyAddress", "", TcapToXml::Element}, + {Regexp("^CalledPartyAddress\\.gt\\.encoding$"), "transport.sccp.CalledPartyAddress.gt", "encoding", TcapToXml::Attribute}, + {Regexp("^CalledPartyAddress\\.gt\\.np$"), "transport.sccp.CalledPartyAddress.gt", "plan", TcapToXml::Attribute}, + {Regexp("^CalledPartyAddress\\.gt\\.nai$"), "transport.sccp.CalledPartyAddress.gt", "nature", TcapToXml::Attribute}, + {Regexp("^CalledPartyAddress\\.gt\\.tt$"), "transport.sccp.CalledPartyAddress.gt", "translation", TcapToXml::Attribute}, + {Regexp("^CalledPartyAddress\\.gt$"), "transport.sccp.CalledPartyAddress", "gt", TcapToXml::Element}, + {Regexp("^CalledPartyAddress\\.ssn$"), "transport.sccp.CalledPartyAddress", "ssn", TcapToXml::Element}, + {Regexp("^CalledPartyAddress\\.route$"), "transport.sccp.CalledPartyAddress", "route", TcapToXml::Element}, + {Regexp("^CalledPartyAddress\\.pointcode$"), "transport.sccp.CalledPartyAddress", "pointcode", TcapToXml::Element}, + {Regexp("^CalledPartyAddress\\..\\+$"), "transport.sccp.CalledPartyAddress", "", TcapToXml::Element}, + {Regexp("^tcap\\.request\\.type$"), "transport.tcap", "request-type", TcapToXml::Element}, + {Regexp("^tcap\\.transaction\\.localTID$"), "transport.tcap", "localTID", TcapToXml::Element}, + {Regexp("^tcap\\.transaction\\.remoteTID$"), "transport.tcap", "remoteTID", TcapToXml::Element}, + {Regexp("^tcap\\.transaction\\.abort\\.cause$"), "transport.tcap", "abort-cause", TcapToXml::Element}, + {Regexp("^tcap\\.transaction\\.abort\\.information$"), "transport.tcap", "abort-information", TcapToXml::Element}, + {Regexp("^tcap\\.transaction\\..\\+$"), "transport.tcap", "", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.application-context-name$"), "application", "", TcapToXml::Value}, + {Regexp("^tcap\\.dialogPDU\\.dialog-pdu-type$"), "transport.tcap.dialog", "type", TcapToXml::Attribute}, + {Regexp("^tcap\\.dialogPDU\\.abort-source$"), "transport.tcap.dialog", "abort-source", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.result$"), "transport.tcap.dialog", "result", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.result-source-diagnostic$"), "transport.tcap.dialog", "result-source-diagnostic", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.userInformation\\.direct-reference$"), "transport.tcap.dialog.userInformation", "direct-reference", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.userInformation\\.encoding-contents$"),"transport.tcap.dialog.userInformation", "encoding-contents",TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.userInformation\\.encoding-type$"), "transport.tcap.dialog.userInformation", "encoding-type", TcapToXml::Element}, + {Regexp("^tcap\\.dialogPDU\\.userInformation\\..\\+$"), "transport.tcap.dialog.userInformation", "", TcapToXml::Element}, + {Regexp("^tcap\\.component\\.count$"), "", "", TcapToXml::None}, + {Regexp("^tcap\\.component\\..\\+\\.localCID$"), "component", "", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\.remoteCID$"), "component", "", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\.componentType$"), "component", "type", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\.operationCode$"), "component", "", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\.operationCodeType$"), "", "", TcapToXml::None}, + {Regexp("^tcap\\.component\\..\\+\\.errorCode$"), "component", "", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\.errorCodeType$"), "", "", TcapToXml::None}, + {Regexp("^tcap\\.component\\..\\+\\.problemCode$"), "component", "", TcapToXml::Attribute}, + {Regexp("^tcap\\.component\\..\\+\\..\\+"), "component", "", TcapToXml::Element}, + {Regexp(""), "", "", TcapToXml::End}, +}; + + +TcapToXml::TcapToXml(TcapXApplication* app) + : Mutex(false,"TcapToXml"), + m_app(app), m_type(Unknown) +{ + DDebug(&__plugin,DebugAll,"TcapToXml created for application=%s[%p] [%p]",m_app->toString().c_str(),m_app,this); +} + +TcapToXml::~TcapToXml() +{ + DDebug(&__plugin,DebugAll,"TcapToXml destroyed [%p]",this); + reset(); +} + +void TcapToXml::reset() +{ + m_type = Unknown; +} + +const XMLMap* TcapToXml::findMap(String& what) +{ + XDebug(&__plugin,DebugAll,"TcapToXml::findMap(%s) [%p]",what.c_str(),this); + const XMLMap* map = s_xmlMap; + while (map->type != End) { + if (what.matches(map->name)) + return map; + map++; + } + return 0; +} + +bool TcapToXml::buildXMLMessage(NamedList& params, XmlFragment* msg, MsgType type) +{ + DDebug(&__plugin,DebugAll,"TcapToXML::buildXMLMessage() [%p]",this); + if (!msg) + return false; + XmlDeclaration* decl = new XmlDeclaration(); + msg->addChild(decl); + XmlElement* el = new XmlElement(s_msgTag); + el->setXmlns("",true,s_namespace); + msg->addChild(el); + + AppCtxt* appCtxt = 0; + NamedString* ctxt = params.getParam(s_tcapAppCtxt); + if (!TelEngine::null(ctxt)) + appCtxt = (AppCtxt*)findCtxtFromOid(m_app->type(),*ctxt); + if (appCtxt) + params.setParam(s_tcapAppCtxt,appCtxt->name); + + // translate P-Abort causes + ctxt = params.getParam(s_tcapAbortCause); + if (!TelEngine::null(ctxt) && (*ctxt) == "pAbort") { + int code = params.getIntValue(s_tcapAbortInfo); + params.setParam(s_tcapAbortInfo,lookup(code,SS7TCAPError::s_errorTypes,*ctxt)); + } + + for (unsigned int i = 0; i < params.count(); i++) { + NamedString* ns = params.getParam(i); + if (TelEngine::null(ns)) + continue; + if (ns->name().startsWith(s_tcapCompPrefixSep)) + continue; + const XMLMap* map = findMap((String&)ns->name()); + if (!map) + continue; + addToXml(el,map,ns); + } + + + addComponentsToXml(el,params,appCtxt); + return true; +} + +void TcapToXml::addToXml(XmlElement* root, const XMLMap* map, NamedString* val) +{ + if (!(root && map && !TelEngine::null(val))) + return; + if (map->type == None) + return; + XDebug(&__plugin,DebugAll,"TcapToXml::addToXml(frag=%p, map=%s[%p], val=%s[%p]) [%p]",root,map->map,map,val->name().c_str(),val,this); + String mapStr = map->map; + ObjList* path = mapStr.split('.',false); + XmlElement* parent = root; + + for (ObjList* o = path->skipNull(); o; o = o->skipNext()) { + String* elem = static_cast(o->get()); + if (TelEngine::null(elem)) + continue; + XmlElement* child = parent->findFirstChild(elem); + if (!child) { + child = new XmlElement(*elem); + parent->addChild(child); + } + parent = child; + } + + if (parent) { + // add to parent child element if map is elem, or attr if map si attribute + XmlElement* child = 0; + + String tag; + if (TelEngine::null(map->tag)) { + tag = val->name(); + if (tag.find('.') > -1 && tag.startsWith(map->name)) + tag.startSkip(map->name,false); + replace(tag,'.','-'); + } + else + tag = map->tag; + switch (map->type) { + case Element: + child = new XmlElement(tag); + child->addText(*val); + parent->addChild(child); + break; + case Value: + parent->addText(*val); + break; + case Attribute: + parent->setAttributeValid(tag,*val); + break; + case None: + default: + break; + } + } + TelEngine::destruct(path); +} + +void TcapToXml::addComponentsToXml(XmlElement* el, NamedList& params, AppCtxt* ctxt) +{ + if (!el) + return; + DDebug(&__plugin,DebugAll,"TcapToXml::addComponentsToXml(el=%p, params=%p) [%p]",el,¶ms,this); + int count = params.getIntValue(s_tcapCompCount); + for (int i = 1; i <= count; i++) { + XmlElement* comp = new XmlElement(s_component); + el->addChild(comp); + + String root; + root << s_tcapCompPrefix << "." << String(i); + NamedList compParams(""); + compParams.copyParam(params,root,'.'); + + NamedString* opCode = params.getParam(root + "." + s_tcapOpCode); + NamedString* opType = params.getParam(root + "." + s_tcapOpCodeType); + Operation* op = 0; + if (!TelEngine::null(opCode) && !TelEngine::null(opType)) + op = (Operation*)findOperation(m_app->type(),opCode->toInteger(),(*opType == "local" ? true : false)); + if (op) + compParams.setParam(root + "." + s_tcapOpCode,op->name); + + int compType = SS7TCAP::lookupComponent(params.getValue(root + "." + s_tcapCompType)); + + bool searchArgs = true; + switch (compType) { + case SS7TCAP::TC_Invoke: + case SS7TCAP::TC_ResultLast: + case SS7TCAP::TC_ResultNotLast: + searchArgs = (compType == SS7TCAP::TC_Invoke); + break; + case SS7TCAP::TC_U_Error: + opCode = params.getParam(root + "." + s_tcapErrCode); + opType = params.getParam(root + "." + s_tcapErrCodeType); + if (!TelEngine::null(opCode) && !TelEngine::null(opType)) + op = (Operation*)findError(m_app->type(),opCode->toInteger(),(*opType == "local" ? true : false)); + if (op) + compParams.setParam(root + "." + s_tcapErrCode,op->name); + break; + case SS7TCAP::TC_R_Reject: + case SS7TCAP::TC_U_Reject: + case SS7TCAP::TC_L_Reject: + compParams.setParam(root + "." + s_tcapProblemCode, + lookup(params.getIntValue(root + "." + s_tcapProblemCode),SS7TCAPError::s_errorTypes)); + break; + default: + break; + } + for (unsigned int j = 0; j < compParams.count(); j++) { + NamedString* ns = compParams.getParam(j); + if (TelEngine::null(ns)) + continue; + + const XMLMap* map = findMap((String&)ns->name()); + if (!map) + continue; + XmlElement* child; + int pos = ns->name().rfind('.'); + String tag = ns->name().substr(pos + 1); + tag = (TelEngine::null(map->tag) ? tag : (String)map->tag); + switch (map->type) { + case Element: + child = new XmlElement(tag); + child->addText(*ns); + comp->addChild(child); + break; + case Value: + comp->addText(*ns); + break; + case Attribute: + comp->setAttributeValid(tag,*ns); + break; + case None: + default: + break; + } + } + NamedString* payloadHex = params.getParam(root); + if (TelEngine::null(payloadHex)) + continue; + addParametersToXml(comp,*payloadHex,op,searchArgs); + } +} + +void TcapToXml::addParametersToXml(XmlElement* elem, String& payloadHex, Operation* op, bool searchArgs) +{ + if (!elem) + return; + DDebug(&__plugin,DebugAll,"TcapToXml::addParametersToXml(elem=%s[%p], payload=%s, op=%s[%p], searchArgs=%s) [%p]", + elem->getTag().c_str(),elem,payloadHex.c_str(),(op ? op->name.c_str() : ""),op,String::boolText(searchArgs),this); + + DataBlock data; + if (!data.unHexify(payloadHex.c_str(),payloadHex.length(),' ')) { + DDebug(&__plugin,DebugAll,"TcapToXml::addParamtersToXml() invalid hexified payload=%s [%p]",payloadHex.c_str(),this); + return; + } + if (elem->getTag() == s_component) { + AsnTag tag = (op ? (searchArgs ? op->argTag : op->retTag) : s_noTag); + AsnTag decTag; + AsnTag::decode(decTag,data); + if (op && tag != decTag) { + if (tag != s_noTag) + op = 0; + } + if (decTag.type() == AsnTag::Constructor && tag == decTag) { // initial constructor + data.cut(-decTag.coding().length()); + int len = ASNLib::decodeLength(data); + if (len != (int)data.length()) + return; + } + + } + decodeTcapToXml(elem,data,op,0,searchArgs); +} + +void TcapToXml::decodeTcapToXml(XmlElement* elem, DataBlock& data, Operation* op, unsigned int index, bool searchArgs) +{ + DDebug(&__plugin,DebugAll,"TcapToXml::decodeTcapToXml(elem=%s[%p],op=%s[%p], searchArgs=%s) [%p]", + elem->getTag().c_str(),elem,(op ? op->name.c_str() : ""),op,String::boolText(searchArgs),this); + if (!data.length() || !elem) + return; + + if (op) + decodeOperation(op,elem,data,searchArgs); + else + decodeRaw(elem,data); +} + +bool TcapToXml::decodeOperation(Operation* op, XmlElement* elem, DataBlock& data, bool searchArgs) +{ + if (!(op && elem && m_app)) + return false; + const Parameter* param = (searchArgs ? op->args : op->res); + AsnTag opTag = (searchArgs ? op->argTag : op->retTag); + int err = TcapXApplication::NoError; + while (param && !TelEngine::null(param->name)) { + AsnTag tag; + AsnTag::decode(tag,data); + if (!decodeParam(param,tag,data,elem,m_app->addEncoding(),err)) { + if (!param->isOptional) + err = TcapXApplication::DataMissing; + } + else if (opTag == s_noTag) // should be only one child + break; + param++; + } + if (data.length()) + decodeRaw(elem,data); + return true; +} + +/** + * XmlToTcap + */ + +const TCAPMap XmlToTcap::s_tcapMap[] = { + {"c", false, ""}, + {"transport.mtp.", true, ""}, + {"transport.sccp.CallingPartyAddress.gt.encoding", false, "CallingPartyAddress.gt.encoding"}, + {"transport.sccp.CallingPartyAddress.gt.plan", false, "CallingPartyAddress.gt.np"}, + {"transport.sccp.CallingPartyAddress.gt.nature", false, "CallingPartyAddress.gt.nai"}, + {"transport.sccp.CallingPartyAddress.gt.translation", false, "CallingPartyAddress.gt.tt"}, + {"transport.sccp.CallingPartyAddress.", true, "CallingPartyAddress"}, + {"transport.sccp.CalledPartyAddress.gt.encoding", false, "CalledPartyAddress.gt.encoding"}, + {"transport.sccp.CalledPartyAddress.gt.plan", false, "CalledPartyAddress.gt.np"}, + {"transport.sccp.CalledPartyAddress.gt.nature", false, "CalledPartyAddress.gt.nai"}, + {"transport.sccp.CalledPartyAddress.gt.translation", false, "CalledPartyAddress.gt.tt"}, + {"transport.sccp.CalledPartyAddress.", true, "CalledPartyAddress"}, + {"transport.tcap.request-type", false, "tcap.request.type"}, + {"transport.tcap.abort-cause", false, "tcap.transaction.abort.cause"}, + {"transport.tcap.abort-information", false, "tcap.transaction.abort.information"}, + {"transport.tcap.dialog.type", false, "tcap.dialogPDU.dialog-pdu-type"}, + {"transport.tcap.dialog.userInformation", true, "tcap.dialogPDU.userInformation"}, + {"transport.tcap.dialog.", false, "tcap.dialogPDU"}, + {"transport.tcap.", true, "tcap.transaction"}, + {"application", false, "tcap.dialogPDU.application-context-name"}, + {0, ""}, +}; + +XmlToTcap::XmlToTcap(TcapXApplication* app) + : Mutex(false,"XmlToTcap"), + m_app(app), m_frag(0), m_decl(0), m_elem(0) +{ + DDebug(&__plugin,DebugAll,"XmlToTcap created for application=%s[%p] [%p]",m_app->toString().c_str(),m_app,this); +} +XmlToTcap::~XmlToTcap() +{ + DDebug(&__plugin,DebugAll,"XmlToTcap destroyed [%p]",this); + reset(); +} + +void XmlToTcap::reset() +{ + DDebug(&__plugin,DebugAll,"XmlToTcap::reset() m_elem = %s[%p], m_decl=%p",(m_elem ? m_elem->tag() : ""),m_elem,m_decl); + TelEngine::destruct(m_decl); + TelEngine::destruct(m_elem); + m_type = Unknown; +} + +const TCAPMap* XmlToTcap::findMap(String& path) +{ + XDebug(&__plugin,DebugAll,"XmlToTcap::findMap(%s) [%p]",path.c_str(),this); + const TCAPMap* map = s_tcapMap; + while (map && map->path) { + if (path == map->path || path.startsWith(map->path)) + return map; + map++; + } + return 0; +} + +bool XmlToTcap::validDeclaration() +{ + Lock l(this); + if (!m_decl) + return false; + DDebug(&__plugin,DebugAll,"XmlToTcap::validDeclaration() [%p]",this); + const NamedList& decl = m_decl->getDec(); + NamedString* vers = decl.getParam(YSTRING("version")); + NamedString* enc = decl.getParam(YSTRING("encoding")); + if (TelEngine::null(vers) || (*vers != "1.0") || TelEngine::null(enc) || (*enc != "UTF-8")) + return false; + return true; +} + +bool XmlToTcap::checkXmlns() +{ + Lock l(this); + if (!m_elem) + return false; + String* xmlns = m_elem->xmlns(); + if (TelEngine::null(xmlns)) { + if (m_app->state() == TcapXApplication::Waiting) + return false; + } + else { + if (s_namespace != *xmlns) + return false; + } + return true; +} + + +bool XmlToTcap::valid() +{ + Lock l(this); + if (!m_frag) + return false; + DDebug(&__plugin,DebugAll,"XmlToTcap::valid() [%p]",this); + while (XmlChild* child = m_frag->pop()) { + if (XmlDeclaration* decl = child->xmlDeclaration()) { + if (!m_decl) + m_decl = decl; + else + return false; + } + else if (XmlElement* elem = child->xmlElement()) { + if (!m_elem) { + if (s_msgTag != elem->tag()) { + Debug(&__plugin,DebugInfo,"XmlToTcap::valid() - missing root tag %s [%p]",s_msgTag.c_str(),this); + return false; + } + m_elem = elem; + break; + } + else + return false; + } + else + TelEngine::destruct(child); + } + return true; +} + +void XmlToTcap::setXmlFragment(XmlFragment* frag) +{ + Lock l(this); + reset(); + m_frag = frag; +} + +void XmlToTcap::encodeOperation(Operation* op, XmlElement* elem, DataBlock& payload, int& err, bool searchArgs) +{ + if (!(op && elem)) + return; + const Parameter* param = (searchArgs ? op->args : op->res); + AsnTag opTag = (searchArgs ? op->argTag : op->retTag); + while (param && !TelEngine::null(param->name)) { + DataBlock db; + if (!encodeParam(param,db,elem,err)) { + if (!param->isOptional) + err = TcapXApplication::DataMissing; + } + else { + payload.append(db); + if (opTag == s_noTag) + break; + } + param++; + } + XmlElement* child = elem->pop(); + while (child) { + DataBlock db; + encodeRaw(param,db,child,err); + payload.append(db); + TelEngine::destruct(child); + child = elem->pop(); + } + return; +} + +bool XmlToTcap::encodeComponent(DataBlock& payload, XmlElement* elem, bool searchArgs, int& err, Operation* op) +{ + DDebug(&__plugin,DebugAll,"XmlToTcap::encodeComponent(elem=%p) [%p]",elem,this); + if (!elem) + return false; + + if (op) + encodeOperation(op,elem,payload,err,searchArgs); + else + encodeRaw(0,payload,elem,err); + + if (elem->getTag() == s_component) { + AsnTag tag = ( op ? (searchArgs ? op->argTag : op->retTag) : s_sequenceTag); + if (tag != s_noTag) { + payload.insert(ASNLib::buildLength(payload)); + payload.insert(tag.coding()); + } + } + return true; +} + +bool XmlToTcap::handleComponent(NamedList& tcapParams, XmlElement* elem) +{ + DDebug(&__plugin,DebugAll,"XMLToTcap::handleComponent(params=%p, elem=%p) [%p]",&tcapParams,elem,this); + if (!elem && elem->getTag() == s_component) + return false; + unsigned int index = tcapParams.getIntValue(s_tcapCompCount) + 1; + String prefix = s_tcapCompPrefix; + prefix << "." << index; + + Operation* op = 0; + int type = 0; + const NamedList& comp = elem->attributes(); + for (unsigned int i = 0; i < comp.count(); i++) { + NamedString* ns = comp.getParam(i); + if (TelEngine::null(ns)) + continue; + + if (ns->name() == s_typeStr) { + tcapParams.setParam(prefix + "." + s_tcapCompType,*ns); + type = SS7TCAP::lookupComponent(*ns); + } + else if (ns->name() == s_tcapOpCode) { + op = (Operation*)findOperation(m_app->type(),*ns); + if (!op) + continue; + tcapParams.setParam(prefix + "." + s_tcapOpCode,String(op->code)); + tcapParams.setParam(prefix + "." + s_tcapOpCodeType,(op->local ? "local" : "global")); + } + else if (ns->name() == s_tcapErrCode) { + op = (Operation*)findError(m_app->type(),*ns); + if (!op) + continue; + tcapParams.setParam(prefix + "." + s_tcapErrCode,String(op->code)); + tcapParams.setParam(prefix + "." + s_tcapErrCodeType,(op->local ? "local" : "global")); + } + else if (ns->name() == s_tcapProblemCode) + tcapParams.setParam(prefix + "." + s_tcapProblemCode,String(lookup(*ns,SS7TCAPError::s_errorTypes))); + else + tcapParams.setParam(prefix + "." + ns->name(),*ns); + + } + DataBlock payload; + bool searchArgs = (type == SS7TCAP::TC_Invoke || type == SS7TCAP::TC_U_Error ? true : false); + + int err = TcapXApplication::NoError; + if (!encodeComponent(payload,elem,searchArgs,err,op)) + return false; + + String str; + str.hexify(payload.data(),payload.length(),' '); + tcapParams.setParam(prefix,str); + + tcapParams.setParam(s_tcapCompCount,String(index)); + return true; +} + +bool XmlToTcap::parse(NamedList& tcapParams) +{ + Lock l(this); + XDebug(&__plugin,DebugAll,"XmlToTcap::parse()"); + tcapParams.setParam(s_tcapCompCount,String(0)); + bool ok = parse(tcapParams,m_elem,""); + NamedString* c = tcapParams.getParam(s_capabTag); + + if (!c) { + c = tcapParams.getParam(s_tcapReqType); + if (c) { + m_type = Tcap; + AppCtxt* appCtxt = 0; + NamedString* ctxt = tcapParams.getParam(s_tcapAppCtxt); + if (!TelEngine::null(ctxt)) + appCtxt = (AppCtxt*)findCtxtFromStr(m_app->type(),*ctxt); + if (appCtxt) + tcapParams.setParam(s_tcapAppCtxt,appCtxt->oid); + // we shoudn't receive P_Abort from application, but make sure anyway + ctxt = tcapParams.getParam(s_tcapAbortCause); + if (!TelEngine::null(ctxt) && (*ctxt) == "pAbort") { + ctxt = tcapParams.getParam(s_tcapAbortInfo); + int code = lookup(*ctxt,SS7TCAPError::s_errorTypes); + *ctxt = String(code); + } + } + } + else + m_type = Capability; + return ok; +} + +bool XmlToTcap::parse(NamedList& tcapParams, XmlElement* elem, String prefix) +{ + XDebug(&__plugin,DebugAll,"XmlToTcap::parse(elem=%p, prefix=%s) [%p]",elem,prefix.c_str(),this); + if (!elem) + return true; + + bool status = true; + bool hasChildren = false; + while (XmlElement* child = elem->pop()) { + hasChildren = true; + if (child->getTag() == s_component) + status = handleComponent(tcapParams,child); + else + status = parse(tcapParams,child, (!TelEngine::null(prefix) ? prefix + "." + child->getTag() : child->getTag())); + TelEngine::destruct(child); + if (!status) + break; + } + const NamedList& attrs = elem->attributes(); + for (unsigned int i = 0; i < attrs.count(); i++) { + NamedString* ns = attrs.getParam(i); + if (TelEngine::null(ns)) + continue; + + String find = (!TelEngine::null(prefix) ? prefix + "." + ns->name() : ns->name()); + const TCAPMap* map = findMap(find); + if (map) { + if (!TelEngine::null(map->name)) + tcapParams.addParam(map->name,*ns); + else + tcapParams.addParam(ns->name(),elem->getText()); + } + } + if (!hasChildren) { + const TCAPMap* map = findMap(prefix); + if (map) { + if (map->isPrefix) { + if (!TelEngine::null(map->name)) + tcapParams.addParam(map->name + "." + elem->getTag(),elem->getText()); + else + tcapParams.addParam(elem->getTag(),elem->getText()); + } + else { + if (!TelEngine::null(map->name)) + tcapParams.addParam(map->name,elem->getText()); + else + tcapParams.addParam(elem->getTag(),elem->getText()); + } + } + } + return status; +} + +/** + * TcapXApplication + */ +TcapXApplication::TcapXApplication(const char* name, Socket* skt, TcapXUser* user) + : Mutex(true,name), + m_io(0), m_name(name), m_user(user), + m_sentXml(0), m_receivedXml(0), + m_sentTcap(0), m_receivedTcap(0), + m_state(Waiting), + m_tcap2Xml(this), + m_xml2Tcap(this) +{ + if (skt) { + m_io = new XMLConnection(skt,this); + if (!m_io->startup()) { + delete m_io; + m_io = 0; + } + } + m_type = user->type(); + Debug(&__plugin,DebugAll,"TcapXApplication created with name=%s and connection=%p [%p]",m_name.c_str(),m_io,this); +} + +TcapXApplication::~TcapXApplication() +{ + Debug(&__plugin,DebugAll,"TcapXApplication with name=%s destroyed [%p]",m_name.c_str(),this); + closeConnection(); + while (m_io) + Thread::idle(); + m_user = 0; +} + +bool TcapXApplication::hasCapability(const char* cap) +{ + if (!cap) + return false; + DDebug(&__plugin,DebugAll,"TcapXApplication::hasCapability(cap=%s) [%p]",cap,this); + + Lock l(this); + ObjList* o = m_capab.find(cap); + if (!o) + return false; + String* str = static_cast(o->get()); + if (!(str && (*str == cap))) + return false; + return true; +} + +bool TcapXApplication::canHandle(NamedList& params) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::canHandle(params=%p) [%p]",¶ms,this); + if (m_state != Active) + return false; + int compCount = params.getIntValue(s_tcapCompCount,0); + + for (int i = 1; i <= compCount; i++) { + + NamedString* opCode = params.getParam(s_tcapCompPrefixSep + String(i) + "." + s_tcapOpCode); + NamedString* opType = params.getParam(s_tcapCompPrefixSep + String(i) + "." + s_tcapOpCodeType); + if (TelEngine::null(opCode) || TelEngine::null(opType)) + continue; + const Operation* op = findOperation(m_type,opCode->toInteger(),(*opType == "local" ? true : false)); + if (!op) + continue; + const Capability* cap = findCapability(m_type,op->name); + if (!cap) + continue; + if (!hasCapability(cap->name)) + return false; + } + return true; +} + +void TcapXApplication::closeConnection() +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::closeConnection() - app=%s closing [%p]",m_name.c_str(),this); + Lock l(this); + if (m_io) + m_io->cancel(); + l.drop(); +} + +void TcapXApplication::setIO(XMLConnection* io) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::setIO(io=%p) - app=%s[%p]",io,m_name.c_str(),this); + Lock l(this); + m_io = io; + if (!m_io && m_user) + m_user->removeApp(this); +} + +bool TcapXApplication::supportCapability(const String& capab) +{ + if (!findDefCapability(m_type,capab)) + return false; + return true; +} + +bool TcapXApplication::handleXML() +{ + Debug(&__plugin,DebugAll,"TcapXApplication::handleXML() - %s[%p]",m_name.c_str(),this); + + if (!m_xml2Tcap.checkXmlns()) { + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - XMLNS mismatch, closing the connection [%p]",m_name.c_str(),this); + closeConnection(); + return false; + } + + NamedList params("xml"); + if (!m_xml2Tcap.parse(params)) { + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - parse error, closing the connection [%p]",m_name.c_str(),this); + closeConnection(); + return false; + }; + if (m_user->printMessages()) { + String tmp; + params.dump(tmp,"\r\n ",'\'',true); + Debug(&__plugin,DebugAll,"App=%s[%p] parsed params %s from xml",m_name.c_str(),this,tmp.c_str()); + } + switch (m_xml2Tcap.type()) { + case XmlToTcap::Capability: + return handleCapability(params); + case XmlToTcap::Tcap: + return handleTcap(params); + case XmlToTcap::Unknown: + default: + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - unknown XML message [%p]",m_name.c_str(),this); + closeConnection(); + return false; + } + return true; +} + +bool TcapXApplication::sendTcapMsg(NamedList& params) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::sentTcapMsg(params=%p) [%p]",¶ms,this); + XmlFragment* msg = new XmlFragment(); + bool ok = m_tcap2Xml.buildXMLMessage(params,msg,TcapToXml::Tcap); + + if (m_user->printMessages()) { + String tmp; + msg->toString(tmp,false,"\r\n"," ",false); + Debug(&__plugin,DebugInfo,"App=%s[%p] is sending XML \n%s",m_name.c_str(),this,tmp.c_str()); + } + if (ok && m_io) { + m_io->writeData(msg); + m_sentXml++; + } + delete msg; + return ok; +} + +bool TcapXApplication::handleCapability(NamedList& params) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::handleCapability() - app=%s [%p]",m_name.c_str(),this); + Lock l(this); + bool firstCap = true; + for (unsigned int i = 0; i < params.count(); i++) { + NamedString* ns = params.getParam(i); + if (!ns) + continue; + if (ns->name() == s_capabTag) { + if (TelEngine::null(ns)) { + m_capab.clear(); + reportState(ShutDown); + return true; + } + else { + if (!supportCapability(*ns)) { + reportState(Inactive,String("Unsupported: ") + *ns); + return false; + } + if (firstCap && m_state == Active) { + m_capab.clear(); + firstCap = false; + } + m_capab.append(new String(*ns)); + } + } + } + if (m_state == Waiting) + reportState(Active); + return true; +} + +bool TcapXApplication::handleIndication(NamedList& tcap) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::handleIndication() - app=%s state=%s [%p]",m_name.c_str(),lookup(m_state,s_appStates),this); + + if (m_user->printMessages()) { + String tmp; + tcap.dump(tmp,"\r\n ",'\'',true); + Debug(&__plugin,DebugInfo,"App=%s[%p] received TCAP indication %s",m_name.c_str(),this,tmp.c_str()); + } + + int dialog = SS7TCAP::lookupTransaction(tcap.getValue(s_tcapReqType)); + String ltid = tcap.getValue(s_tcapLocalTID); + NamedString* rtid = tcap.getParam(s_tcapRemoteTID); + + bool saveID = false, removeID = false; + String appID; + switch (dialog) { + case SS7TCAP::TC_Unidirectional: + if (state() != Active) + return false; + tcap.setParam(s_tcapLocalTID,""); + break; + case SS7TCAP::TC_Begin: + case SS7TCAP::TC_QueryWithPerm: + case SS7TCAP::TC_QueryWithoutPerm: + if (state() != Active || TelEngine::null(rtid)) + return false; + tcap.setParam(s_tcapLocalTID,""); + saveID = true; + break; + case SS7TCAP::TC_Continue: + case SS7TCAP::TC_ConversationWithPerm: + case SS7TCAP::TC_ConversationWithoutPerm: + case SS7TCAP::TC_Notice: + case SS7TCAP::TC_Unknown: + if (TelEngine::null(ltid)) + return false; + lock(); + appID = m_ids.findAppID(ltid); + if (TelEngine::null(appID)) { + appID = m_pending.findTcapID(*rtid); + if (TelEngine::null(appID)) { + unlock(); + reportError("Unknown request ID"); + return false; + } + m_pending.remove(appID); + } + unlock(); + break; + case SS7TCAP::TC_End: + case SS7TCAP::TC_Response: + case SS7TCAP::TC_U_Abort: + case SS7TCAP::TC_P_Abort: + if (TelEngine::null(ltid)) + return false; + lock(); + appID = m_ids.findAppID(ltid); + if (TelEngine::null(appID)) { + appID = m_pending.findTcapID(ltid); + if (TelEngine::null(appID)) { + unlock(); + reportError("Unknown request ID"); + return false; + } + m_pending.remove(appID); + } + unlock(); + removeID = true; + break; + default: + return false; + } + + tcap.setParam(s_tcapLocalTID,appID); + bool ok = sendTcapMsg(tcap); + + Lock l(this); + if (saveID) + m_pending.appendID(ltid,*rtid); + if (removeID) { + m_ids.removeAppID(appID); + if (m_state == ShutDown && !trCount()) + reportState(Inactive); + } + m_receivedTcap++; + return ok; +} + +bool TcapXApplication::handleTcap(NamedList& tcap) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::handleTcap() - app=%s state=%s [%p]",m_name.c_str(),lookup(m_state,s_appStates),this); + + int dialog = SS7TCAP::lookupTransaction(tcap.getValue(s_tcapReqType)); + String ltid = tcap.getValue(s_tcapLocalTID); + String rtid = tcap.getValue(s_tcapRemoteTID); + + bool saveID = false; + bool removeID = false; + lock(); + String tcapID = m_ids.findTcapID(ltid); + unlock(); + switch (dialog) { + case SS7TCAP::TC_Unknown: + case SS7TCAP::TC_Unidirectional: + break; + case SS7TCAP::TC_Begin: + case SS7TCAP::TC_QueryWithPerm: + case SS7TCAP::TC_QueryWithoutPerm: + if (TelEngine::null(ltid)) { + reportError("Missing request ID"); + return false; + } + if (!TelEngine::null(tcapID)) { + reportError("Duplicate request ID"); + return false; + } + saveID = true; + break; + case SS7TCAP::TC_Continue: + case SS7TCAP::TC_ConversationWithPerm: + case SS7TCAP::TC_ConversationWithoutPerm: + if (TelEngine::null(ltid)) { + reportError("Missing request ID"); + return false; + } + if (TelEngine::null(tcapID)) { + if (!TelEngine::null(rtid)) { + lock(); + tcapID = m_pending.findTcapID(rtid); + unlock(); + if (TelEngine::null(tcapID)) { + reportError("Unknown request ID"); + return false; + } + lock(); + m_pending.removeAppID(tcapID); + unlock(); + saveID = true; + } + else { + reportError("Unknown request ID"); + return false; + } + } + break; + case SS7TCAP::TC_End: + case SS7TCAP::TC_Response: + case SS7TCAP::TC_U_Abort: + if (TelEngine::null(ltid)) { + reportError("Missing request ID"); + return false; + } + if (TelEngine::null(tcapID)) { + if (!TelEngine::null(rtid)) { + lock(); + tcapID = m_pending.findTcapID(rtid); + unlock(); + if (TelEngine::null(tcapID)) { + reportError("Unknown request ID"); + return false; + } + lock(); + m_pending.removeAppID(tcapID); + unlock(); + } + else { + reportError("Unknown request ID"); + return false; + } + } + removeID = true; + break; + case SS7TCAP::TC_P_Abort: + case SS7TCAP::TC_Notice: + default: + reportError("Invalid request"); + return false; + } + if (!m_user) + return false; + tcap.setParam(s_tcapLocalTID,tcapID); + + if (m_user->printMessages()) { + String tmp; + tcap.dump(tmp,"\r\n ",'\'',true); + Debug(&__plugin,DebugInfo,"App=%s[%p] is sending TCAP request %s",m_name.c_str(),this,tmp.c_str()); + } + + SS7TCAPError error = m_user->applicationRequest(this,tcap,dialog); + if (error.error() != SS7TCAPError::NoError) { + NamedString* err = tcap.getParam(s_tcapRequestError); + reportError(TelEngine::null(err) ? error.errorName() : *err); + return false; + } + + Lock l(this); + if (removeID) { + m_ids.removeAppID(ltid); + if (m_state == ShutDown && !trCount()) + reportState(Inactive); + } + if (saveID) + m_ids.appendID(tcap.getValue(s_tcapLocalTID),ltid); + m_sentTcap++; + return true; +} + +void TcapXApplication::receivedXML(XmlFragment* frag) +{ + + Debug(&__plugin,DebugAll,"TcapXApplication::receivedXML(frag=%p) - %s[%p]",frag,m_name.c_str(),this); + if (!frag) + return; + + if (m_user->printMessages()) { + String tmp; + frag->toString(tmp,false,"\r\n"," ",false); + Debug(&__plugin,DebugInfo,"App=%s[%p] received XML \n%s",m_name.c_str(),this,tmp.c_str()); + } + + m_xml2Tcap.setXmlFragment(frag); + if (!m_xml2Tcap.valid()) { + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - invalid message, closing the connection [%p]",m_name.c_str(),this); + closeConnection(); + return; + } + if (m_state == Waiting && !m_xml2Tcap.hasDeclaration()) { + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - initial XML declaration missing, closing the connection [%p]",m_name.c_str(),this); + closeConnection(); + return; + } + if (m_xml2Tcap.hasDeclaration() && !m_xml2Tcap.validDeclaration()) { + Debug(&__plugin,DebugInfo,"TcapXApplication=%s - XML declaration mismatch, closing the connection [%p]",m_name.c_str(),this); + closeConnection(); + return; + } + if (handleXML()) + m_receivedXml++; +} + +void TcapXApplication::reportState(State state, const char* error) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::reportState(state=%s, error=%s) [%p]",lookup(state,s_appStates),error,this); + m_state = state; + switch (m_state) { + case Waiting: + break; + case Active: + sendStateResponse(); + break; + case ShutDown: + Debug(&__plugin,DebugInfo,"Requested shutdown, %d transactions pending [%p]",trCount(),this); + if (trCount()) + break; + m_state = Inactive; + case Inactive: + sendStateResponse(error); + closeConnection(); + default: + break; + } +} + +void TcapXApplication::sendStateResponse(const char* error) +{ + DDebug(&__plugin,DebugAll,"TcapXApplication::sendStateResponse(error=%s) [%p]",error,this); + + NamedList params("xml"); + params.setParam("state",lookup(m_state,s_appStates)); + if (error) + params.setParam("error",error); + XmlFragment* msg = new XmlFragment(); + bool ok = m_tcap2Xml.buildXMLMessage(params,msg,TcapToXml::State); + + if (m_user->printMessages()) { + String tmp; + msg->toString(tmp,false,"\r\n"," ",false); + Debug(&__plugin,DebugInfo,"App=%s[%p] is sending XML \n%s",m_name.c_str(),this,tmp.c_str()); + } + if (ok && m_io) { + m_io->writeData(msg); + m_sentXml++; + } + delete msg; +} + +void TcapXApplication::reportError(const char* err) +{ + if (!err) + return; + DDebug(&__plugin,DebugInfo,"TcapXApplication::reportError(error=%s) [%p]",err,this); +} + +void TcapXApplication::status(NamedList& status) +{ + DDebug(&__plugin,DebugInfo,"TcapXApplication::status() [%p]",this); + + Lock l(this); + status.setParam("receivedXML",String(m_receivedXml)); + status.setParam("sentXML",String(m_sentXml)); + status.setParam("receivedTcap",String(m_receivedTcap)); + status.setParam("sentTcap",String(m_sentTcap)); +} + +/** + * TcapXUser + */ +TcapXUser::TcapXUser(const char* name) + : TCAPUser(name), + Mutex(true,name), + m_appsMtx(true,"TCAPXApps"), + m_listener(0), m_type(MAP), + m_printMsg(false), m_addEnc(false) +{ + Debug(&__plugin,DebugAll,"TcapXUser '%s' created [%p]",toString().c_str(),this); +} + +TcapXUser::~TcapXUser() +{ + Debug(&__plugin,DebugAll,"TcapXUser '%s' destroyed [%p]",toString().c_str(),this); + lock(); + if (m_listener) + m_listener->cancel(); + if (tcap()) + attach(0); + unlock(); + + m_appsMtx.lock(); + for (ObjList* o = m_apps.skipNull(); o; o = o->skipNext()) { + TcapXApplication* app = static_cast(o->get()); + if (app) + app->closeConnection(); + } + m_appsMtx.unlock(); + + while (m_listener) + Thread::idle(); +} + +bool TcapXUser::initialize(NamedList& sect) +{ + Debug(this,DebugAll,"TcapXUser::initialize() [%p]",this); + + Lock l(this); + if (!m_listener) { + m_listener = new XMLConnListener(this,sect); + if (!m_listener->init()) { + delete m_listener; + m_listener = 0; + return false; + } + } + + m_type = (UserType)lookup(sect.getValue(s_typeStr,"MAP"),s_userTypes,m_type); + m_printMsg = sect.getBoolValue("print-messages",false); + m_addEnc = sect.getBoolValue("add-encoding",false); + if (!tcap() && !findTCAP(sect.getValue("tcap",0))) + return false; + return true; +} + +void TcapXUser::removeApp(TcapXApplication* app) +{ + Debug(this,DebugAll,"Removing application=%s[%p] [%p]",(app ? app->toString().c_str() : ""),app,this); + Lock l(m_appsMtx); + m_apps.remove(app); +} + +bool TcapXUser::tcapIndication(NamedList& params) +{ + DDebug(this,DebugAll,"TcapXUser::tcapIndication() [%p]",this); + + NamedString* ltid = params.getParam(s_tcapLocalTID); + if (TelEngine::null(ltid)) + return false; + int dialog = SS7TCAP::lookupTransaction(params.getValue(s_tcapReqType)); + + ObjList* o = m_trIDs.find(*ltid); + NamedString* tcapID = 0; + if (o) + tcapID = static_cast(o->get()); + bool searchApp = false, removeID = false; + switch (dialog) { + case SS7TCAP::TC_Unidirectional: + return sendToApp(params); + case SS7TCAP::TC_Begin: + case SS7TCAP::TC_QueryWithPerm: + case SS7TCAP::TC_QueryWithoutPerm: + if (TelEngine::null(ltid) || !TelEngine::null(tcapID)) + return false; + return sendToApp(params); + case SS7TCAP::TC_Continue: + case SS7TCAP::TC_ConversationWithPerm: + case SS7TCAP::TC_ConversationWithoutPerm: + if (TelEngine::null(ltid) || TelEngine::null(tcapID)) + return false; + searchApp = true; + break; + case SS7TCAP::TC_End: + case SS7TCAP::TC_Response: + case SS7TCAP::TC_U_Abort: + case SS7TCAP::TC_P_Abort: + case SS7TCAP::TC_Notice: + case SS7TCAP::TC_Unknown: + if (TelEngine::null(ltid) || TelEngine::null(tcapID)) + return false; + searchApp = true; + removeID = true; + break; + default: + return false; + } + + Lock la(m_appsMtx); + o = m_apps.find(*tcapID); + if (!o && searchApp) + return false; + + TcapXApplication* app = static_cast(o->get()); + if (searchApp && !app) + return false; + + if (removeID) { + reorderApps(app); + m_trIDs.remove(tcapID); + } + la.drop(); + return sendToApp(params,app); +} + +bool TcapXUser::sendToApp(NamedList& params, TcapXApplication* app) +{ + DDebug(this,DebugAll,"TcapXUser::sendToApp(params=%p,app=%s[%p]) [%p]",¶ms,(app ? app->toString().c_str() : ""),app,this); + + Lock l(m_appsMtx); + if (!app) + app = findApplication(params); + if (!app) + return false; + m_trIDs.append(new NamedString(params.getValue(s_tcapLocalTID),app->toString())); + return (app && app->handleIndication(params)); +} + +TcapXApplication* TcapXUser::findApplication(NamedList& params) +{ + DDebug(this,DebugAll,"TcapXUser::findApplication() [%p]",this); + TcapXApplication* app = 0; + for (ObjList* o = m_apps.skipNull(); o; o = o->skipNext()) { + app = static_cast(o->get()); + if (app->canHandle(params)) + break; + } + // reorder list + reorderApps(app); + return app; +} + +void TcapXUser::reorderApps(TcapXApplication* app) +{ + if (!app) + return; + ObjList* appObj = m_apps.find(app); + if (!appObj) + return; + ObjList* next = appObj->next(); + TcapXApplication* ins = 0; + while (next) { + TcapXApplication* nextApp = static_cast(next->get()); + if (nextApp) { + if (app->trCount() + 1 > nextApp->trCount()) { + if (!ins) { + ins = app; + m_apps.remove(app,false); + } + next = next->next(); + } + else { + if (ins) { + next->insert(app); + ins = 0; + } + break; + } + } + else + break; + } + if (ins) + m_apps.append(app); +} + +void TcapXUser::statusString(String& str) +{ + DDebug(this,DebugAll,"TcapXUser::statusString() [%p]",this); + Lock l(m_appsMtx); + NamedList params(""); + for (ObjList* o = m_apps.skipNull(); o; o = o->skipNext()) { + TcapXApplication* app = static_cast(o->get()); + if (!app) + continue; + str.append(app->toString(),",") << "=" << toString() << "|" << lookup(m_type,s_userTypes); + app->status(params); + str << "|" << params.getIntValue(YSTRING("receivedXML")); + str << "|" << params.getIntValue(YSTRING("sentXML")); + str << "|" << params.getIntValue(YSTRING("receivedTcap")); + str << "|" << params.getIntValue(YSTRING("sentTcap")); + } +} + +bool TcapXUser::managementNotify(SCCP::Type type, NamedList& params) +{ +// TODO +// check docs if they say anything about management + return true; +} + +bool TcapXUser::findTCAP(const char* name) +{ + if (!name) + return false; + SignallingComponent* tcap = 0; + SignallingEngine* engine = SignallingEngine::self(true); + if (engine) + tcap = engine->find(name,"SS7TCAPITU",tcap); + if (tcap) { + Debug(this,DebugAll,"TcapXUser '%s' attaching to TCAP=%s [%p]",toString().c_str(),name,this); + attach(YOBJECT(SS7TCAPITU,tcap)); + } + return (tcap != 0); +} + +bool TcapXUser::createApplication(Socket* skt, String& addr) +{ + if (!skt) + return false; + + String appName = toString() + ":" + addr; + Lock l(m_appsMtx); + // it's new, put it at the top of the list + m_apps.insert(new TcapXApplication(appName,skt,this)); + return true; +} + +int TcapXUser::managementState() +{ + DDebug(this,DebugAll,"TcapXUser::managementState() - user=%s[%p]",toString().c_str(),this); + Lock l(m_appsMtx); + for (ObjList* o = m_apps.skipNull(); o; o = o->skipNext()) { + TcapXApplication* app = static_cast(o->get()); + if (!app) + continue; + if (app->state() == TcapXApplication::Active) + return SCCPManagement::UserInService; + } + return SCCPManagement::UserOutOfService; +} + +void TcapXUser::setListener(XMLConnListener* list) +{ + Lock l(this); + m_listener = list; +} + +SS7TCAPError TcapXUser::applicationRequest(TcapXApplication* app, NamedList& params, int reqType) +{ + DDebug(this,DebugAll,"TcapXUser::applicationRequest() - user=%s, request from app=%s[%p] [%p]", + toString().c_str(),(app ? app->toString().c_str() : ""),app,this); + + SS7TCAPError error((tcap() ? tcap()->tcapType() : SS7TCAP::ITUTCAP)); + if (!app) + return error; + if (tcap()) { + params.setParam(s_tcapUser,toString()); + error = tcap()->userRequest(params); + } + else { + params.setParam(s_tcapRequestError,"No TCAP attached"); + error.setError(SS7TCAPError::Transact_UnassignedTransactionID); + return error; + } + bool saveID = false; + bool removeID = false; + switch (reqType) { + case SS7TCAP::TC_Begin: + case SS7TCAP::TC_QueryWithPerm: + case SS7TCAP::TC_QueryWithoutPerm: + saveID = true; + break; + case SS7TCAP::TC_End: + case SS7TCAP::TC_Response: + case SS7TCAP::TC_U_Abort: + removeID = true; + break; + case SS7TCAP::TC_P_Abort: + case SS7TCAP::TC_Notice: + case SS7TCAP::TC_Unknown: + case SS7TCAP::TC_Unidirectional: + case SS7TCAP::TC_Continue: + case SS7TCAP::TC_ConversationWithPerm: + case SS7TCAP::TC_ConversationWithoutPerm: + default: + break; + } + + Lock la(m_appsMtx); + NamedString* ltid = params.getParam(s_tcapLocalTID); + if (saveID) { + reorderApps(app); + if (TelEngine::null(ltid)) { + params.setParam(s_tcapRequestError,"TCAP error"); + error.setError(SS7TCAPError::Transact_UnassignedTransactionID); + } + else + m_trIDs.append(new NamedString(*ltid,app->toString())); + } + if (removeID) { + reorderApps(app); + if (TelEngine::null(ltid) ||!m_trIDs.find(*ltid)) + error.setError(SS7TCAPError::Transact_UnassignedTransactionID); + else + m_trIDs.remove(*ltid); + } + return error; +} + +/** + * TcapXModule + */ +TcapXModule::TcapXModule() + : Module("camel_map","misc"), + m_usersMtx(true,"TCAPXUsers") +{ + Output("Loaded TCAPXML module"); +} + +TcapXModule::~TcapXModule() +{ + Output("Unloaded module TCAPXML"); +} + +void TcapXModule::initialize() +{ + Output("Initializing module TCAPXML"); + Module::initialize(); + + Configuration cfg(Engine::configFile(name())); + cfg.load(); + initUsers(cfg); +} + +bool TcapXModule::unload() +{ + if (!lock(500000)) + return false; + + uninstallRelays(); + return true; +} + +void TcapXModule::initUsers(Configuration& cfg) +{ + DDebug(&__plugin,DebugAll,"TcapXModule::initUsers() [%p]",this); + int n = cfg.sections(); + Lock l(m_usersMtx); + for (int i = 0; i < n; i++) { + NamedList* sect = cfg.getSection(i); + if (!sect) + continue; + String name(*sect); + if (name.startSkip("tcap") && name) { + if (!sect->getBoolValue("enable",true)) { + m_users.remove(name); + continue; + } + ObjList* o = m_users.find(name); + TcapXUser* usr = (o ? static_cast(o->get()) : 0); + if (!usr) { + usr = new TcapXUser(name); + m_users.append(usr); + } + if (!usr->initialize(*sect)) { + Debug(&__plugin,DebugInfo,"TcapXModule::initUsers() - user '%s' failed to initialize [%p]",name.c_str(),this); + m_users.remove(name); + } + } + } +} + +bool TcapXModule::received(Message& msg, int id) +{ + return Module::received(msg,id); +} + +unsigned int TcapXModule::applicationCount() +{ + Lock l(m_usersMtx); + unsigned int count = 0; + for (ObjList* o = m_users.skipNull(); o; o = o->skipNext()) { + TcapXUser* user = static_cast(o->get()); + count += user->applicationCount(); + } + return count; +} + +void TcapXModule::statusModule(String& str) +{ + Module::statusModule(str); + str.append("format=User|Type|ReceivedXML|SentXML|ReceivedTCAP|SentTcap",","); +} + +void TcapXModule::statusParams(String& str) +{ + str.append("count=",",") << applicationCount(); +} + +void TcapXModule::statusDetail(String& str) +{ + Lock l(m_usersMtx); + for (ObjList* o = m_users.skipNull(); o; o = o->skipNext()) { + TcapXUser* user = static_cast(o->get()); + if (!user) + continue; + user->statusString(str); + } +} + +}; // anonymous namespace + +/* vi: set ts=8 sw=4 sts=4 noet: */ \ No newline at end of file