From 579bf3eb524d1001d5d786d0207568b487b60ba2 Mon Sep 17 00:00:00 2001 From: pescuma Date: Sat, 30 Jan 2010 06:05:24 +0000 Subject: sip: + Added info popups + Added SRTP option - Remove TCP connection for protocol (everybody seems to use UDP/TLS only) git-svn-id: http://pescuma.googlecode.com/svn/trunk/Miranda@219 c086bb3d-8645-0410-b8da-73a8550f86e7 --- Protocols/SIP/SIPClient.cpp | 27 +++++--- Protocols/SIP/SIPClient.h | 2 +- Protocols/SIP/SIPProto.cpp | 157 +++++++++++++++++++++++++++++--------------- Protocols/SIP/SIPProto.h | 9 ++- Protocols/SIP/popup.cpp | 26 ++++++-- Protocols/SIP/popup.h | 6 +- Protocols/SIP/resource.h | 2 + Protocols/SIP/resource.rc | 9 +-- Protocols/SIP/strutils.h | 2 + 9 files changed, 163 insertions(+), 77 deletions(-) diff --git a/Protocols/SIP/SIPClient.cpp b/Protocols/SIP/SIPClient.cpp index 86dc64c..8fee5c1 100644 --- a/Protocols/SIP/SIPClient.cpp +++ b/Protocols/SIP/SIPClient.cpp @@ -181,8 +181,6 @@ static void static_on_log(int level, const char *data, int len) } -#define TransportName(_T_) SipToTchar(pj_cstr(pjsip_transport_get_type_name(_T_))).get() - void SIPClient::RegisterTransport(pjsip_transport_type_e type, int port, ta *ta) { ta->transport_id = -1; @@ -248,9 +246,8 @@ int SIPClient::Connect(SIP_REGISTRATION *reg) pjsua_config cfg; pjsua_config_default(&cfg); -#ifndef _DEBUG cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL; -#endif + cfg.srtp_secure_signaling = 0; cfg.cb.on_incoming_call = &static_on_incoming_call; cfg.cb.on_call_media_state = &static_on_call_media_state; cfg.cb.on_call_state = &static_on_call_state; @@ -291,6 +288,20 @@ int SIPClient::Connect(SIP_REGISTRATION *reg) if (udp.port <= 0 && tcp.port <= 0 && tls.port <= 0) return 1; + + pjsua_transport_config cfg; + pjsua_transport_config_default(&cfg); + + enum { START_PORT=4000 }; + unsigned range = (65535-START_PORT-PJSUA_MAX_CALLS*2); + cfg.port = START_PORT + ((pj_rand() % range) & 0xFFFE); + + pj_status_t status = pjsua_media_transports_create(&cfg); + if (status != PJ_SUCCESS) + { + Error(status, _T("Error creating media transports")); + return 1; + } } { @@ -582,13 +593,13 @@ void SIPClient::CleanupURI(TCHAR *out, int outSize, const TCHAR *url) } -void SIPClient::BuildURI(TCHAR *out, int outSize, const TCHAR *host, int port, int protocol) +void SIPClient::BuildURI(TCHAR *out, int outSize, const TCHAR *host, int port, pjsip_transport_type_e transport) { - if (protocol == PJSIP_TRANSPORT_UDP) + if (transport == PJSIP_TRANSPORT_UDP) mir_sntprintf(out, outSize, _T(""), host, port); else mir_sntprintf(out, outSize, _T(""), host, port, - TransportName((pjsip_transport_type_e) protocol)); + TransportName(transport)); } pjsua_call_id SIPClient::Call(const TCHAR *host, int port, int protocol) @@ -605,7 +616,7 @@ pjsua_call_id SIPClient::Call(const TCHAR *host, int port, int protocol) return -1; TCHAR uri[1024]; - BuildURI(uri, MAX_REGS(uri), host, port, protocol); + BuildURI(uri, MAX_REGS(uri), host, port, (pjsip_transport_type_e) protocol); pjsua_call_id call_id; pj_str_t ret; diff --git a/Protocols/SIP/SIPClient.h b/Protocols/SIP/SIPClient.h index bbcb3ef..a00a763 100644 --- a/Protocols/SIP/SIPClient.h +++ b/Protocols/SIP/SIPClient.h @@ -74,7 +74,7 @@ private: void RegisterTransport(pjsip_transport_type_e type, int port, ta *ta); void ConfigureDevices(); - void BuildURI(TCHAR *out, int outSize, const TCHAR *host, int port, int protocol); + void BuildURI(TCHAR *out, int outSize, const TCHAR *host, int port, pjsip_transport_type_e transport); void CleanupURI(TCHAR *out, int outSize, const TCHAR *url); void NotifyCall(pjsua_call_id call_id, int state, const TCHAR *host_port = NULL); diff --git a/Protocols/SIP/SIPProto.cpp b/Protocols/SIP/SIPProto.cpp index 5004d90..3f8e888 100644 --- a/Protocols/SIP/SIPProto.cpp +++ b/Protocols/SIP/SIPProto.cpp @@ -75,6 +75,7 @@ SIPProto::SIPProto(const char *aProtoName, const TCHAR *aUserName) { NULL, CONTROL_INT, IDC_STUN_PORT, "STUNPort", PJ_STUN_PORT, 0, 0 }, { NULL, CONTROL_CHECKBOX, IDC_PUBLISH, "Publish", (BYTE) FALSE }, { NULL, CONTROL_CHECKBOX, IDC_KEEPALIVE, "SendKeepAlive", (BYTE) TRUE }, + { NULL, CONTROL_CHECKBOX, IDC_SRTP, "UseSRTP", (BYTE) FALSE }, }; memmove(optionsCtrls, oCtrls, sizeof(optionsCtrls)); @@ -92,6 +93,7 @@ SIPProto::SIPProto(const char *aProtoName, const TCHAR *aUserName) optionsCtrls[11].var = &opts.stun.port; optionsCtrls[12].var = &opts.publish; optionsCtrls[13].var = &opts.sendKeepAlive; + optionsCtrls[14].var = &opts.srtp; LoadOpts(optionsCtrls, MAX_REGS(optionsCtrls), m_szModuleName); @@ -528,9 +530,11 @@ int SIPProto::Connect() pjsua_config cfg; pjsua_config_default(&cfg); -//#ifndef _DEBUG -// cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL; -//#endif + if (opts.srtp) + { + cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL; + cfg.srtp_secure_signaling = 0; + } cfg.cb.on_incoming_call = &static_on_incoming_call; cfg.cb.on_call_media_state = &static_on_call_media_state; cfg.cb.on_call_state = &static_on_call_state; @@ -595,6 +599,7 @@ int SIPProto::Connect() { pjsua_transport_config cfg; pjsua_transport_config_default(&cfg); + pj_status_t status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &udp_transport_id); if (status != PJ_SUCCESS) { @@ -602,19 +607,26 @@ int SIPProto::Connect() Disconnect(); return 2; } - - status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, &tcp_transport_id); - if (status != PJ_SUCCESS) - Error(status, _T("Error creating TCP transport")); - status = pjsua_transport_create(PJSIP_TRANSPORT_TLS, &cfg, &udp_transport_id); + //status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, &tcp_transport_id); + //if (status != PJ_SUCCESS) + // Error(status, _T("Error creating TCP transport")); + + status = pjsua_transport_create(PJSIP_TRANSPORT_TLS, &cfg, &tls_transport_id); if (status != PJ_SUCCESS) Error(status, _T("Error creating TLS transport")); - cfg.port = 4000; + enum { START_PORT=4000 }; + unsigned range = (65535-START_PORT-PJSUA_MAX_CALLS*2); + cfg.port = START_PORT + ((pj_rand() % range) & 0xFFFE); + status = pjsua_media_transports_create(&cfg); if (status != PJ_SUCCESS) + { Error(status, _T("Error creating media transports")); + Disconnect(); + return 2; + } } pjsua_get_snd_dev(&defaultInput, &defaultOutput); @@ -639,9 +651,8 @@ int SIPProto::Connect() pjsua_acc_config_default(&cfg); cfg.user_data = this; // cfg.transport_id = transport_id; -//#ifndef _DEBUG // cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL; -//#endif +// cfg.srtp_secure_signaling = 0; BuildURI(tmp, MAX_REGS(tmp), opts.username, opts.domain); TcharToSip id(tmp); @@ -917,14 +928,24 @@ void SIPProto::ShowMessage(int type, TCHAR *fmt, va_list args) mir_vsntprintf(&buff[7], MAX_REGS(buff)-7, fmt, args); + for(size_t i = lstrlen(buff) - 1; i >= 7; --i) + { + if (buff[i] == _T('\r') || buff[i] == _T('\n')) + buff[i] = 0; + else + break; + } + + if (type == MESSAGE_TYPE_ERROR) + ShowErrPopup(&buff[7], m_tszUserName); + else if (type == MESSAGE_TYPE_INFO) + ShowInfoPopup(&buff[7], m_tszUserName); + #ifdef _DEBUG OutputDebugString(buff); OutputDebugString(_T("\n")); #endif - if (type == MESSAGE_TYPE_ERROR) - ShowErrPopup(buff, m_tszUserName); - CallService(MS_NETLIB_LOG, (WPARAM) hNetlibUser, (LPARAM) TcharToChar(buff).get()); } @@ -1053,13 +1074,19 @@ void SIPProto::NotifyCall(pjsua_call_id call_id, int state, HANDLE hContact, TCH { Trace(_T("NotifyCall %d -> %d"), call_id, state); + bool secure = false; + + pjsua_call_info info; + if (state < VOICE_STATE_ENDED && pjsua_call_get_info(call_id, &info) == PJ_SUCCESS) + secure = (_tcsstr(SipToTchar(info.local_contact), _T("transport=TLS")) != NULL); + char tmp[16]; VOICE_CALL vc = {0}; vc.cbSize = sizeof(vc); vc.moduleName = m_szModuleName; vc.id = itoa((int) call_id, tmp, 10); - vc.flags = VOICE_TCHAR; + vc.flags = VOICE_TCHAR | (secure ? VOICE_SECURE : 0); vc.hContact = hContact; vc.ptszName = name; vc.ptszNumber = number; @@ -1193,7 +1220,7 @@ void SIPProto::on_incoming_call(pjsua_call_id call_id) void SIPProto::on_call_state(pjsua_call_id call_id, const pjsua_call_info &info) { Trace(_T("on_call_state: %d"), call_id); - Trace(_T("Call info: %d / last: %d %s"), info.state, info.last_status, info.last_status_text); + Trace(_T("Call info: %d / last: %d"), info.state, info.last_status); switch(info.state) { @@ -1348,52 +1375,77 @@ void SIPProto::CleanupURI(TCHAR *out, int outSize, const TCHAR *url) *host = 0; } +bool SIPProto::HasTransportEnabled(pjsip_transport_type_e transport) +{ + switch(transport) + { + case PJSIP_TRANSPORT_UDP: return udp_transport_id >= 0; + case PJSIP_TRANSPORT_TCP: return tcp_transport_id >= 0; + case PJSIP_TRANSPORT_TLS: return tls_transport_id >= 0; + default: return false; + } +} + -void SIPProto::BuildTelURI(TCHAR *out, int outSize, const TCHAR *number) +void SIPProto::BuildTelURI(TCHAR *out, int outSize, const TCHAR *number, pjsip_transport_type_e transport) { - BuildURI(out, outSize, number, NULL, 0, true); + BuildURI(out, outSize, number, NULL, 0, transport, true); } -void SIPProto::BuildURI(TCHAR *out, int outSize, const TCHAR *user, const TCHAR *aHost, int port, bool isTel) +void SIPProto::BuildURI(TCHAR *out, int outSize, const TCHAR *user, const TCHAR *aHost, int port, + pjsip_transport_type_e transport, bool isTel) { - if (user == NULL) + mir_sntprintf(out, outSize, _T(" 0) - mir_sntprintf(out, outSize, _T(""), host, port); - else - mir_sntprintf(out, outSize, _T(""), host); + TCHAR *host = _tcschr(tmp, _T('@')); + if (host != NULL) + { + *host = 0; + host++; + } - return; - } + if (host != NULL && aHost != NULL && lstrcmp(host, aHost) != 0) + Error(_T("Two conflicting hosts: %s / %s , ignoring one in argument"), host, aHost); - TCHAR tmp[1024]; - CleanupURI(tmp, MAX_REGS(tmp), user); + host = FirstNotEmpty(host, (TCHAR *) aHost, opts.domain); - TCHAR *host = _tcschr(tmp, _T('@')); - if (host != NULL) + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T("%s@%s"), tmp, host); + } + else { - *host = 0; - host++; + TCHAR *host = FirstNotEmpty((TCHAR *) aHost, opts.domain); + + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T("%s"), host); } - if (host != NULL && aHost != NULL && lstrcmp(host, aHost) != 0) - Error(_T("Two conflicting hosts: %s / %s , ignoring one in argument"), host, aHost); + if (port > 0) + { + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T(":%d"), port); + } - host = FirstNotEmpty(host, (TCHAR *) aHost, opts.domain); + if (isTel) + { + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T(";user=phone")); + } - + if (transport != PJSIP_TRANSPORT_UDP && HasTransportEnabled(transport)) + { + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T(";transport=%s"), TransportName(transport)); + } - if (isTel && port > 0) - mir_sntprintf(out, outSize, _T(""), tmp, host, port); - else if (isTel) - mir_sntprintf(out, outSize, _T(""), tmp, host); - else if (port > 0) - mir_sntprintf(out, outSize, _T(""), tmp, host, port); - else - mir_sntprintf(out, outSize, _T(""), tmp, host); + size_t len = lstrlen(out); + mir_sntprintf(out + len, outSize - len, _T(">")); } @@ -1409,10 +1461,9 @@ int __cdecl SIPProto::VoiceCall(WPARAM wParam, LPARAM lParam) if (!VoiceCallStringValid((WPARAM) number, 0)) return 1; - if (_tcsncmp(_T("sip:"), number, 4) == 0) - { + if (_tcsncmp(_T("sip:"), number, 4) == 0 || _tcsncmp(_T("sips:"), number, 5) == 0) mir_sntprintf(uri, MAX_REGS(uri), _T("<%s>"), number); - } + else BuildTelURI(uri, MAX_REGS(uri), number); } @@ -1615,18 +1666,18 @@ void __cdecl SIPProto::SearchUserThread(void *param) return; } + TCHAR name[1024]; + CleanupURI(name, MAX_REGS(name), uri); + TcharToChar name_char(name); + pj_str_t ret; if (pjsua_buddy_find(pj_cstr(&ret, sip_uri)) != PJSUA_INVALID_ID) { - Info(_T("Contact already in your contact list")); + Info(_T("Contact already in your contact list: %s"), name); SendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, param, 0); return; } - TCHAR name[1024]; - CleanupURI(name, MAX_REGS(name), uri); - TcharToChar name_char(name); - PROTOSEARCHRESULT isr = {0}; isr.cbSize = sizeof(isr); isr.nick = (char *) name_char.get(); diff --git a/Protocols/SIP/SIPProto.h b/Protocols/SIP/SIPProto.h index 889d633..bc3d11d 100644 --- a/Protocols/SIP/SIPProto.h +++ b/Protocols/SIP/SIPProto.h @@ -67,12 +67,13 @@ public: } proxy; BYTE publish; BYTE sendKeepAlive; + BYTE srtp; } opts; CRITICAL_SECTION cs; std::vector events; OptPageControl accountManagerCtrls[4]; - OptPageControl optionsCtrls[14]; + OptPageControl optionsCtrls[15]; SIPProto(const char *aProtoName, const TCHAR *aUserName); virtual ~SIPProto(); @@ -176,9 +177,11 @@ private: INT_PTR __cdecl CreateAccMgrUI(WPARAM wParam, LPARAM lParam); void ConfigureDevices(); - void BuildTelURI(TCHAR *out, int outSize, const TCHAR *number); - void BuildURI(TCHAR *out, int outSize, const TCHAR *user, const TCHAR *host = NULL, int port = 0, bool isTel = false); + void BuildTelURI(TCHAR *out, int outSize, const TCHAR *number, pjsip_transport_type_e transport = PJSIP_TRANSPORT_UDP); + void BuildURI(TCHAR *out, int outSize, const TCHAR *user, const TCHAR *host = NULL, int port = 0, + pjsip_transport_type_e transport = PJSIP_TRANSPORT_UDP, bool isTel = false); void CleanupURI(TCHAR *out, int outSize, const TCHAR *url); + bool HasTransportEnabled(pjsip_transport_type_e transport); // Voice services void NotifyCall(pjsua_call_id call_id, int state, HANDLE hContact = NULL, TCHAR *name = NULL, TCHAR *number = NULL); diff --git a/Protocols/SIP/popup.cpp b/Protocols/SIP/popup.cpp index 9a10593..0d2d71c 100644 --- a/Protocols/SIP/popup.cpp +++ b/Protocols/SIP/popup.cpp @@ -57,7 +57,6 @@ void DeInitPopups() } -// Show an error popup void ShowErrPopup(const TCHAR *description, const TCHAR *title) { ShowPopupEx(NULL, title == NULL ? _T(MODULE_NAME) _T(" Error") : title, description, @@ -65,6 +64,13 @@ void ShowErrPopup(const TCHAR *description, const TCHAR *title) } +void ShowInfoPopup(const TCHAR *description, const TCHAR *title) +{ + ShowPopupEx(NULL, title == NULL ? _T(MODULE_NAME) _T(" Information") : title, description, + NULL, POPUP_TYPE_INFO, NULL); +} + + void ShowTestPopup(const TCHAR *title, const TCHAR *description, const Options *op) { ShowPopupEx(NULL, title, description, NULL, POPUP_TYPE_TEST, op); @@ -118,11 +124,16 @@ void ShowPopupEx(HANDLE hContact, const TCHAR *title, const TCHAR *description, ppd.colorText = op->popup_text_color; } */ } - else // if (type == POPUP_TYPE_ERROR) + else if (type == POPUP_TYPE_ERROR) { ppd.colorBack = RGB(200,0,0); ppd.colorText = RGB(255,255,255); } + else // if (type == POPUP_TYPE_INFO) + { + ppd.colorBack = RGB(255,255,128); + ppd.colorText = RGB(0,0,0); + } if (type == POPUP_TYPE_NORMAL) { @@ -152,7 +163,7 @@ void ShowPopupEx(HANDLE hContact, const TCHAR *title, const TCHAR *description, break; } */ } - else // if (type == POPUP_TYPE_ERROR) + else // if (type == POPUP_TYPE_ERROR || type == POPUP_TYPE_INFO) { ppd.iSeconds = 0; } @@ -199,11 +210,16 @@ void ShowPopupEx(HANDLE hContact, const TCHAR *title, const TCHAR *description, } */ } - else // if (type == POPUP_TYPE_ERROR) + else if (type == POPUP_TYPE_ERROR) { ppd.colorBack = RGB(200,0,0); ppd.colorText = RGB(255,255,255); } + else // if (type == POPUP_TYPE_INFO) + { + ppd.colorBack = RGB(255,255,128); + ppd.colorText = RGB(0,0,0); + } if (type == POPUP_TYPE_NORMAL) { @@ -233,7 +249,7 @@ void ShowPopupEx(HANDLE hContact, const TCHAR *title, const TCHAR *description, break; } */ } - else // if (type == POPUP_TYPE_ERROR) + else // if (type == POPUP_TYPE_ERROR || type == POPUP_TYPE_INFO) { ppd.iSeconds = 0; } diff --git a/Protocols/SIP/popup.h b/Protocols/SIP/popup.h index 3a97b08..0ed6db2 100644 --- a/Protocols/SIP/popup.h +++ b/Protocols/SIP/popup.h @@ -41,16 +41,16 @@ void DeInitPopups(); #define POPUP_TYPE_NORMAL 0 #define POPUP_TYPE_TEST 1 #define POPUP_TYPE_ERROR 2 +#define POPUP_TYPE_INFO 3 -// Show an popup void ShowPopup(HANDLE hContact, const TCHAR *title, const TCHAR *description); -// Show an test void ShowTestPopup(const TCHAR *title, const TCHAR *description, const Options *op); -// Show an error popup void ShowErrPopup(const TCHAR *description, const TCHAR *title = NULL); +void ShowInfoPopup(const TCHAR *description, const TCHAR *title = NULL); + void ShowPopupEx(HANDLE hContact, const TCHAR *title, const TCHAR *description, void *plugin_data, int type, const Options *op); diff --git a/Protocols/SIP/resource.h b/Protocols/SIP/resource.h index 2cd12ae..8841258 100644 --- a/Protocols/SIP/resource.h +++ b/Protocols/SIP/resource.h @@ -34,6 +34,8 @@ #define IDC_VIDEO 1088 #define IDC_PUBLISH2 1088 #define IDC_KEEPALIVE 1088 +#define IDC_KEEPALIVE2 1089 +#define IDC_SRTP 1089 #define IDC_DOMAIN 1091 #define IDC_STATIC -1 diff --git a/Protocols/SIP/resource.rc b/Protocols/SIP/resource.rc index 570661a..c7418a7 100644 --- a/Protocols/SIP/resource.rc +++ b/Protocols/SIP/resource.rc @@ -43,7 +43,7 @@ BEGIN CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,48,131,10 END -IDD_OPTIONS DIALOGEX 0, 0, 216, 205 +IDD_OPTIONS DIALOGEX 0, 0, 216, 215 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 0, 0, 0x1 @@ -56,7 +56,7 @@ BEGIN LTEXT "Password:",-1,14,48,53,12,SS_CENTERIMAGE EDITTEXT IDC_PASSWORD,68,49,131,12,ES_PASSWORD | ES_AUTOHSCROLL CONTROL "Save password",IDC_SAVEPASSWORD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,68,65,131,10 - GROUPBOX "Advanced",-1,3,84,209,115 + GROUPBOX "Advanced",-1,3,84,209,128 LTEXT "Registrar:",-1,14,99,53,12,SS_CENTERIMAGE EDITTEXT IDC_REG_HOST,68,99,92,12,ES_AUTOHSCROLL CTEXT ":",-1,161,99,8,12,SS_CENTERIMAGE @@ -74,7 +74,8 @@ BEGIN CTEXT ":",-1,161,147,8,12,SS_CENTERIMAGE EDITTEXT IDC_STUN_PORT,169,147,30,12,ES_AUTOHSCROLL | ES_NUMBER CONTROL "Publish status",IDC_PUBLISH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,166,185,10 - CONTROL "Send keep-alives",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,182,185,10 + CONTROL "Send keep-alives",IDC_KEEPALIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,181,185,10 + CONTROL "Use SRTP",IDC_SRTP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,196,185,10 END @@ -88,7 +89,7 @@ GUIDELINES DESIGNINFO BEGIN IDD_OPTIONS, DIALOG BEGIN - BOTTOMMARGIN, 204 + BOTTOMMARGIN, 214 END END #endif // APSTUDIO_INVOKED diff --git a/Protocols/SIP/strutils.h b/Protocols/SIP/strutils.h index b534ac2..9a67362 100644 --- a/Protocols/SIP/strutils.h +++ b/Protocols/SIP/strutils.h @@ -196,5 +196,7 @@ static const pj_str_t pj_cstr(const char *s) return str; } +#define TransportName(_T_) SipToTchar(pj_cstr(pjsip_transport_get_type_name(_T_))).get() + #endif // __STRUTILS_H__ -- cgit v1.2.3