/* * Copyright (C) 2011-2018 MicroSIP (http://www.microsip.org) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "global.h" #include "settings.h" #include "utf.h" #include "langpack.h" #include #ifdef UNICODE #define CF_TEXT_T CF_UNICODETEXT #else #define CF_TEXT_T CF_TEXT #endif struct call_tonegen_data *tone_gen = NULL; int transport; pjsua_acc_id account; pjsua_acc_id account_local; CString lastTransferNumber; pjsua_conf_port_id msip_conf_port_id; pjsua_call_id msip_conf_port_call_id; int msip_audio_input; int msip_audio_output; int msip_audio_ring; CList DTMFTonegens; CString GetErrorMessage(pj_status_t status) { CStringA str; char *buf = str.GetBuffer(PJ_ERR_MSG_SIZE-1); pj_strerror(status, buf, PJ_ERR_MSG_SIZE); str.ReleaseBuffer(); int i = str.ReverseFind( '(' ); if (i!=-1) { str = str.Left(i-1); } if (str == "Invalid Request URI" || str == "Invalid URI") { str = "Invalid number"; } return Translate(CString(str).GetBuffer()); } BOOL ShowErrorMessage(pj_status_t status) { if (status!=PJ_SUCCESS) { AfxMessageBox(GetErrorMessage(status)); return TRUE; } else { return FALSE; } } CString RemovePort(CString domain) { int pos = domain.Find(_T(":")); if (pos != -1) { return domain.Mid(0,pos); } else { return domain; } } BOOL IsIP(CString host) { CStringA hostA(host); char *pHost = hostA.GetBuffer(); unsigned long ulAddr = inet_addr(pHost); if (ulAddr !=INADDR_NONE && ulAddr != INADDR_ANY) { struct in_addr antelope; antelope.S_un.S_addr = ulAddr; if (strcmp(inet_ntoa(antelope),pHost)==0) { return TRUE; } } return FALSE; } void ParseSIPURI(CString in, SIPURI* out) { // tone_gen.toneslot = -1; // tone_gen = NULL; // "WEwewew rewewe" // sip:qqweqwe@qwerer.com;rrrr=tttt;qweqwe=rrr?qweqwr=rqwrqwr if (in.Right(1) == _T(">")) { in = in.Left(in.GetLength()-1); } out->name = _T(""); out->user = _T(""); out->domain = _T(""); out->parameters = _T(""); int start = in.Find( _T("sip:") ); int end; if (start>0) { out->name = in.Left(start); out->name.Trim(_T(" \" <")); if (!out->name.CompareNoCase(_T("unknown"))) { out->name = _T(""); } } if (start>=0) { start+=4; } else { start = 0; } end = in.Find( _T("@"), start ); if (end>=0) { out->user=in.Mid(start,end-start); start=end+1; } end = in.Find( _T(";"), start ); if (end>=0) { out->domain = in.Mid(start,end-start); start=end; out->parameters = in.Mid(start); } else { end = in.Find( _T("?"), start ); if (end>=0) { out->domain = in.Mid(start,end-start); start=end; out->parameters = in.Mid(start); } else { out->domain = in.Mid(start); } } } CString PjToStr(const pj_str_t* str, BOOL utf) { CStringA rab; rab.Format("%.*s", str->slen, str->ptr); if (utf) { #ifdef _UNICODE WCHAR* msg; Utf8DecodeCP(rab.GetBuffer(), CP_ACP, &msg); return msg; #else return Utf8DecodeCP(rab.GetBuffer(), CP_ACP, NULL); #endif } else { return CString(rab); } } pj_str_t StrToPjStr(CString str) { return pj_str(StrToPj(str)); } char* StrToPj(CString str) { #ifdef _UNICODE return Utf8EncodeUcs2(str.GetBuffer()); #else return Utf8EncodeCP(str.GetBuffer(), CP_ACP); #endif } CString Utf8DecodeUni(CStringA str) { #ifdef _UNICODE LPTSTR msg; Utf8DecodeCP(str.GetBuffer(), CP_ACP, &msg); return msg; #else return Utf8DecodeCP(str.GetBuffer(), CP_ACP, NULL); #endif } CStringA UnicodeToAnsi(CString str) { CStringA res; int nCount = str.GetLength(); for( int nIdx =0; nIdx < nCount; nIdx++ ) { res+=str[nIdx]; } return res; } CString AnsiToUnicode(CStringA str) { CString res; int nCount = str.GetLength(); for( int nIdx =0; nIdx < nCount; nIdx++ ) { res+=str[nIdx]; } return res; } CString XMLEntityDecode(CString str) { str.Replace(_T("<"),_T("<")); str.Replace(_T(">"),_T(">")); str.Replace(_T("""),_T("\"")); str.Replace(_T("&"),_T("&")); return str; } CString XMLEntityEncode(CString str) { str.Replace(_T("&"),_T("&")); str.Replace(_T("<"),_T("<")); str.Replace(_T(">"),_T(">")); str.Replace(_T("\""),_T(""")); return str; } void OpenURL(CString url) { CString param; param.Format(_T("url.dll,FileProtocolHandler %s"),url); ShellExecute(NULL, NULL, _T("rundll32.exe"), param, NULL, SW_SHOWNORMAL); } CString GetDuration(int sec, bool zero) { CString duration; if (sec || zero) { int h,m,s; s = sec; h = s/3600; s = s%3600; m = s/60; s = s%60; if (h) { duration.Format(_T("%d:%02d:%02d"),h,m,s); } else { duration.Format(_T("%d:%02d"),m,s); } } return duration; } void AddTransportSuffix(CString &str) { switch (transport) { case MSIP_TRANSPORT_TCP: str.Append(_T(";transport=tcp")); break; case MSIP_TRANSPORT_TLS: str.Append(_T(";transport=tls")); break; } } CString GetSIPURI(CString str, bool isSimple, bool isLocal, CString domain) { CString rab = str; rab.MakeLower(); int pos = rab.Find(_T("sip:")); if (pos==-1) { str=_T("sip:")+str; } if (!isLocal) { pos = str.Find(_T("@")); if (accountSettings.accountId && pos == -1) { str.Append(_T("@") + (!domain.IsEmpty() ? domain : accountSettings.account.domain)); } } if (str.GetAt(str.GetLength()-1)=='>') { str = str.Left(str.GetLength()-1); if (!isSimple) { if (!isLocal || !accountSettings.accountId) { AddTransportSuffix(str); } } str += _T(">"); } else { if (!isSimple) { if (!isLocal || !accountSettings.accountId) { AddTransportSuffix(str); } } str = _T("<") + str + _T(">"); } return str; } bool SelectSIPAccount(CString number, pjsua_acc_id &acc_id, pj_str_t &pj_uri) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return false; } SIPURI sipuri; ParseSIPURI(number, &sipuri); if (pjsua_acc_is_valid(account) && pjsua_acc_is_valid(account_local)) { acc_id = account; if (accountSettings.account.domain != sipuri.domain) { int pos = sipuri.domain.Find(_T(":")); CString domainWithoutPort = RemovePort(sipuri.domain); if (domainWithoutPort.CompareNoCase(_T("localhost"))==0 || IsIP(domainWithoutPort)) { acc_id = account_local; } } } else if (pjsua_acc_is_valid(account)) { acc_id = account; } else if (pjsua_acc_is_valid(account_local)) { acc_id = account_local; } else { return false; } pj_uri = StrToPjStr ( GetSIPURI(number, acc_id == account_local, acc_id == account_local) ); return true; } bool IsPSTNNnmber(CString number) { bool isDigits = true; for (int i = 0; i < number.GetLength(); i++) { if ((number[i] > '9' || number[i] < '0') && number[i] != '*' && number[i] != '#' && number[i] != '.' && number[i] != '-' && number[i] != '(' && number[i] != ')' && number[i] != ' ' && number[0] != '+') { isDigits = false; break; } } return isDigits; } CString FormatNumber(CString number, CString *commands) { int pos = number.Find(','); if (pos>0 && posleft = GetSystemMetrics (SM_XVIRTUALSCREEN); rect->top = GetSystemMetrics (SM_YVIRTUALSCREEN); rect->right = GetSystemMetrics (SM_CXVIRTUALSCREEN) - rect->left; rect->bottom = GetSystemMetrics (SM_CYVIRTUALSCREEN) - rect->top; } struct call_tonegen_data *call_init_tonegen(pjsua_call_id call_id) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return NULL; } pj_status_t status; pj_pool_t *pool; struct call_tonegen_data *cd; pjsua_call_info ci; if (call_id !=-1 ) { pjsua_call_get_info(call_id, &ci); if (ci.media_status != PJSUA_CALL_MEDIA_ACTIVE) return NULL; } pool = pjsua_pool_create("mycall", 512, 512); cd = PJ_POOL_ZALLOC_T(pool, struct call_tonegen_data); cd->pool = pool; status = pjmedia_tonegen_create(cd->pool, 8000, 1, 64, 16, 0, &cd->tonegen); if (status != PJ_SUCCESS) { return NULL; } pjsua_conf_add_port(cd->pool, cd->tonegen, &cd->toneslot); if (call_id !=-1 ) { pjsua_conf_connect(cd->toneslot, ci.conf_slot); } if (accountSettings.localDTMF || call_id==-1) { pjsua_conf_connect(cd->toneslot, 0); } if (call_id !=-1 ) { call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_id); if (!user_data) { user_data = new call_user_data(call_id); pjsua_call_set_user_data(call_id, user_data); } user_data->tonegen_data = cd; } return cd; } static UINT_PTR destroyDTMFPlayerTimer = NULL; static UINT_PTR tonegenBusyTimer = NULL; void destroyDTMFPlayerTimerHandler( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { if (!tone_gen || pjsua_var.state!=PJSUA_STATE_RUNNING ||!pjmedia_tonegen_is_busy(tone_gen->tonegen)) { if (destroyDTMFPlayerTimer) { KillTimer(NULL,destroyDTMFPlayerTimer); destroyDTMFPlayerTimer = NULL; } call_deinit_tonegen(-1); } } void DTMFQueueTimerHandler( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { KillTimer(hwnd, idEvent); pjsua_call_id call_id = (pjsua_call_id) idEvent; if (pjsua_var.state==PJSUA_STATE_RUNNING && pjsua_call_is_active(call_id)) { call_user_data *user_data = (call_user_data *) pjsua_call_get_user_data(call_id); if (user_data && !user_data->commands.IsEmpty()) { CString dtmf; int pos = user_data->commands.Find(','); if (pos!=-1) { dtmf = user_data->commands.Mid(0,pos); user_data->commands = user_data->commands.Mid(pos+1); } else { dtmf = user_data->commands; user_data->commands.Empty(); } if (!dtmf.IsEmpty()) { msip_call_dial_dtmf(call_id, dtmf); } if (!user_data->commands.IsEmpty()) { ::SetTimer(hwnd, idEvent, 1000 + 200 * dtmf.GetLength() , (TIMERPROC)DTMFQueueTimerHandler); } } } } void tonegenBusyHandler( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { POSITION pos = DTMFTonegens.GetHeadPosition(); while (pos) { POSITION posKey = pos; pjmedia_port *port = DTMFTonegens.GetNext(pos); if (pjsua_var.state!=PJSUA_STATE_RUNNING || pjmedia_tonegen_is_busy(port) == PJ_FALSE) { DTMFTonegens.RemoveAt(posKey); } }; if (DTMFTonegens.IsEmpty()) { KillTimer(NULL,tonegenBusyTimer); tonegenBusyTimer = NULL; CWnd *hWnd = AfxGetApp()->m_pMainWnd; if (hWnd) { hWnd->PostMessage(UM_REFRESH_LEVELS, NULL, NULL); } } } void msip_set_sound_device(int outDev, bool forse){ if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } int in,out; if (forse || pjsua_get_snd_dev(&in,&out)!=PJ_SUCCESS || msip_audio_input!=in || outDev!=out ) { pjsua_set_snd_dev(msip_audio_input, outDev); } } void msip_call_dial_dtmf(pjsua_call_id call_id, CString digits) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } bool simulate = true; if (call_id != PJSUA_INVALID_ID) { pjsua_call_info call_info; pjsua_call_get_info(call_id, &call_info); if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { pj_str_t pj_digits = StrToPjStr ( digits ); if (accountSettings.DTMFMethod == 1) { // in-band simulate = !call_play_digit(call_id, StrToPj(digits)); } else if (accountSettings.DTMFMethod == 2) { // RFC2833 pjsua_call_dial_dtmf(call_id, &pj_digits); } else if (accountSettings.DTMFMethod == 3) { // sip-info msip_call_send_dtmf_info(call_id, pj_digits); } else { // auto if (pjsua_call_dial_dtmf(call_id, &pj_digits) != PJ_SUCCESS) { simulate = !call_play_digit(call_id, StrToPj(digits)); } } } } if (simulate && accountSettings.localDTMF) { msip_set_sound_device(msip_audio_output); call_play_digit(-1, StrToPj(digits)); } } BOOL call_play_digit(pjsua_call_id call_id, const char *digits, int duration) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return FALSE; } pjmedia_tone_digit d[16]; unsigned i, count = strlen(digits); struct call_tonegen_data *cd; call_user_data *user_data = NULL; if (call_id !=-1 ) { user_data = (call_user_data *)pjsua_call_get_user_data(call_id); if (user_data && user_data->tonegen_data) { cd = user_data->tonegen_data; } else { cd = NULL; } } else { cd = tone_gen; } if (!cd) cd = call_init_tonegen(call_id); if (!cd) return FALSE; if (call_id == -1 ) { tone_gen = cd; } if (count > PJ_ARRAY_SIZE(d)) count = PJ_ARRAY_SIZE(d); pj_bzero(d, sizeof(d)); for (i=0; itonegen)==NULL) { DTMFTonegens.AddTail(cd->tonegen); } if (tonegenBusyTimer) { KillTimer(NULL,tonegenBusyTimer); } tonegenBusyTimer = SetTimer(NULL, NULL, 800, (TIMERPROC)tonegenBusyHandler); } pjmedia_tonegen_play_digits(cd->tonegen, count, d, 0); if (call_id == -1 ) { if (destroyDTMFPlayerTimer) { KillTimer(NULL,destroyDTMFPlayerTimer); } destroyDTMFPlayerTimer = SetTimer(NULL, NULL, 5000, (TIMERPROC)destroyDTMFPlayerTimerHandler); } return TRUE; } void call_deinit_tonegen(pjsua_call_id call_id) { struct call_tonegen_data *cd; call_user_data *user_data = NULL; if (call_id !=-1 ) { if (pjsua_var.state==PJSUA_STATE_RUNNING) { user_data = (call_user_data *)pjsua_call_get_user_data(call_id); } if (user_data && user_data->tonegen_data) { cd = user_data->tonegen_data; POSITION position = DTMFTonegens.Find(cd->tonegen); if (position!=NULL) { DTMFTonegens.RemoveAt(position); } } else { cd = NULL; } } else { cd = tone_gen; } if (!cd) return; if (pjsua_var.state==PJSUA_STATE_RUNNING) { pjsua_conf_remove_port(cd->toneslot); pjmedia_port_destroy(cd->tonegen); pj_pool_release(cd->pool); } if (call_id !=-1 ) { if (user_data) { user_data->tonegen_data = NULL; } } else { tone_gen = NULL; } } unsigned call_get_count_noincoming() { unsigned noincoming_count = 0; pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_var.state==PJSUA_STATE_RUNNING && pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { pjsua_call_info call_info; pjsua_call_get_info(call_ids[i], &call_info); if (call_info.role!=PJSIP_ROLE_UAS || (call_info.state!=PJSIP_INV_STATE_INCOMING && call_info.state!=PJSIP_INV_STATE_EARLY)) { noincoming_count++; } } } return noincoming_count; } void call_hangup_all_noincoming(bool onHold) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_var.state==PJSUA_STATE_RUNNING && pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { pjsua_call_info call_info; pjsua_call_get_info(call_ids[i], &call_info); if (call_info.role!=PJSIP_ROLE_UAS || (call_info.state!=PJSIP_INV_STATE_INCOMING && call_info.state!=PJSIP_INV_STATE_EARLY)) { if (onHold && call_info.media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) { continue; } msip_call_hangup_fast(call_ids[i]); } } } } CStringA urlencode(CStringA str) { CStringA escaped; int max = str.GetLength(); for(int i=0; i>4; char dig2 = (dec&0x0F); if ( 0<= dig1 && dig1<= 9) dig1+=48; //0,48inascii if (10<= dig1 && dig1<=15) dig1+=97-10; //a,97inascii if ( 0<= dig2 && dig2<= 9) dig2+=48; if (10<= dig2 && dig2<=15) dig2+=97-10; CStringA r; r.AppendFormat ("%c", dig1); r.AppendFormat ("%c", dig2); return r; } static DWORD WINAPI URLGetAsyncThread( LPVOID lpParam ) { URLGetAsyncData *data = (URLGetAsyncData *)lpParam; data->body.Empty(); data->headers.Empty(); data->statusCode = 0; if (!data->url.IsEmpty()) { try { CInternetSession session; CHttpConnection* pHttp = NULL; CHttpFile* pFile = NULL; DWORD dwServiceType; CString strServer; CString strObject; INTERNET_PORT nPort; if (AfxParseURL(data->url, dwServiceType, strServer, strObject, nPort)) { pHttp = session.GetHttpConnection(strServer, (dwServiceType==AFX_INET_SERVICE_HTTPS ? INTERNET_FLAG_SECURE : 0), nPort); pFile = pHttp->OpenRequest(CHttpConnection::HTTP_VERB_GET,strObject, 0, 1, 0, 0, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | (dwServiceType==AFX_INET_SERVICE_HTTPS ? INTERNET_FLAG_SECURE : 0)); if (dwServiceType==AFX_INET_SERVICE_HTTPS) { pFile->SetOption(INTERNET_OPTION_SECURITY_FLAGS, SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_WRONG_USAGE ); } pFile->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,10000); if (pFile->SendRequest()) { pFile->QueryInfoStatusCode(data->statusCode); CStringA buf; int i; UINT len = 0; do { LPSTR p = data->body.GetBuffer(len+1024); i = pFile->Read(p+len,1024); len+=i; data->body.ReleaseBuffer(len); } while (i>0); //-- pFile->QueryInfo( HTTP_QUERY_RAW_HEADERS_CRLF, data->headers ); pFile->Close(); } session.Close(); } else { data->statusCode = 0; } } catch (CInternetException *e) { data->statusCode = 0; } } if (data->message) { if (data->hWnd) { PostMessage(data->hWnd, data->message, (WPARAM)data, 0); } } else { delete data; } return 0; } void URLGetAsync(CString url, HWND hWnd, UINT message) { HANDLE hThread; URLGetAsyncData *data = new URLGetAsyncData(); data->hWnd = hWnd; data->message = message; data->statusCode = 0; data->url = url; if (!CreateThread(NULL,0, URLGetAsyncThread, data, 0, NULL)) { data->url.Empty(); URLGetAsyncThread(data); } } URLGetAsyncData URLGetSync(CString url) { URLGetAsyncData data; data.hWnd = 0; data.message = 1; data.url = url; URLGetAsyncThread(&data); return data; } CString Bin2String(CByteArray *ca) { CString res; int k=ca->GetSize(); for(int i=0;iGetAt(i); res.AppendFormat(_T("%02x"),ca->GetAt(i)); } return res; } void String2Bin(CString str, CByteArray *res) { res->RemoveAll(); int k=str.GetLength(); CStringA rab; for(int i=0;iAdd(bin); } } void CommandLineToShell(CString cmd, CString &command, CString ¶ms) { cmd.Trim(); command.Empty(); params.Empty(); int nArgs; LPWSTR *szArglist = CommandLineToArgvW(cmd, &nArgs); if (NULL == szArglist) { AfxMessageBox(_T("Wrong command: ") + cmd); } else for (int i = 0; i < nArgs; i++) { if (!i) { command = szArglist[i]; } else { params.AppendFormat(_T("%s "), szArglist[i]); } } params.TrimRight(); LocalFree(szArglist); } CString get_account_username() { CString res = accountSettings.account.username; return res; } CString get_account_password() { CString res = accountSettings.account.password; return res; } CString get_account_server() { CString res = accountSettings.account.server; return res; } CString URLMask(CString url, SIPURI* sipuri, pjsua_acc_id acc) { //-- replace server CString str; if (pjsua_acc_is_valid(acc) && !get_account_server().IsEmpty()) { str = get_account_server(); } else { str = _T("localhost"); } url.Replace(_T("{server}"),str); //-- CTime t = CTime::GetCurrentTime(); time_t time = t.GetTime(); str.Format(_T("%d"), time); url.Replace(_T("{time}"), str); //-- if (sipuri) { //-- replace callerid CString num = !sipuri->name.IsEmpty()?sipuri->name:sipuri->user; url.Replace(_T("{callerid}"),CString(urlencode(Utf8EncodeUcs2(num)))); //-- replace url.Replace(_T("{user}"),CString(urlencode(Utf8EncodeUcs2(sipuri->user)))); url.Replace(_T("{domain}"),CString(urlencode(Utf8EncodeUcs2(sipuri->domain)))); url.Replace(_T("{name}"),CString(urlencode(Utf8EncodeUcs2(sipuri->name)))); //-- } return url; } HICON LoadImageIcon(int i) { return (HICON)LoadImage( AfxGetInstanceHandle(), MAKEINTRESOURCE(i), IMAGE_ICON, 0, 0, LR_SHARED); } void msip_call_send_dtmf_info(pjsua_call_id current_call, pj_str_t digits) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } if (current_call == -1) { PJ_LOG(3,(THIS_FILE, "No current call")); } else { const pj_str_t SIP_INFO = pj_str("INFO"); int call = current_call; pj_status_t status; for (int i=0; istate==PJSIP_INV_STATE_CALLING || (p_call_info->role==PJSIP_ROLE_UAS && p_call_info->state==PJSIP_INV_STATE_CONNECTING) ) { pjsua_call *call = &pjsua_var.calls[call_id]; pjsip_tx_data *tdata = NULL; // Generate an INVITE END message if (pjsip_inv_end_session(call->inv, 487, NULL, &tdata) != PJ_SUCCESS || !tdata) { pjsip_inv_terminate(call->inv,487,PJ_TRUE); } else { // Send that END request if (pjsip_endpt_send_request(pjsua_get_pjsip_endpt(), tdata, -1, NULL, NULL) != PJ_SUCCESS) { pjsip_inv_terminate(call->inv,487,PJ_TRUE); } } return; } } pjsua_call_hangup(call_id, 0, NULL, NULL); } void msip_call_end(pjsua_call_id call_id) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_id); if (user_data && user_data->inConference) { pjsua_call_info call_info; if (pjsua_call_get_info(call_id, &call_info) == PJ_SUCCESS && call_info.state == PJSIP_INV_STATE_CONFIRMED) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { if (call_id == call_ids[i]) { continue; } call_user_data *curr_user_data = (call_user_data *) pjsua_call_get_user_data(call_ids[i]); if (curr_user_data && curr_user_data->inConference) { msip_call_hangup_fast(call_ids[i]); } } } } } msip_call_hangup_fast(call_id); } void msip_conference_join(pjsua_call_info *call_info) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info->id); if (user_data && user_data->inConference) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { if (call_info->id == call_ids[i]) { continue; } if (!pjsua_call_has_media(call_ids[i])) { continue; } call_user_data *curr_user_data = (call_user_data *) pjsua_call_get_user_data(call_ids[i]); if (curr_user_data && curr_user_data->inConference) { if (call_info->conf_slot!=PJSUA_INVALID_ID) { pjsua_conf_port_id conf_port_id = pjsua_call_get_conf_port(call_ids[i]); if (conf_port_id!=PJSUA_INVALID_ID) { pjsua_conf_connect(call_info->conf_slot, conf_port_id); pjsua_conf_connect(conf_port_id, call_info->conf_slot); } } CWnd *hWnd = AfxGetApp()->m_pMainWnd; if (hWnd) { hWnd->PostMessage(UM_TAB_ICON_UPDATE, (WPARAM) call_ids[i], NULL); } } } } } } void msip_conference_leave(pjsua_call_info *call_info, bool hold) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info->id); if (user_data && user_data->inConference) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { int qty = 0; call_user_data *last_conf_user_data = NULL; for (unsigned i = 0; i < count; ++i) { if (call_info->id == call_ids[i]) { continue; } call_user_data *curr_user_data = (call_user_data *) pjsua_call_get_user_data(call_ids[i]); if (curr_user_data && curr_user_data->inConference) { last_conf_user_data = curr_user_data; qty++; if (call_info->conf_slot!=PJSUA_INVALID_ID) { pjsua_conf_port_id conf_port_id = pjsua_call_get_conf_port(call_ids[i]); if (conf_port_id!=PJSUA_INVALID_ID) { pjsua_conf_disconnect(call_info->conf_slot, conf_port_id); pjsua_conf_disconnect(conf_port_id, call_info->conf_slot); } } if (!hold) { CWnd *hWnd = AfxGetApp()->m_pMainWnd; if (hWnd) { hWnd->PostMessage(UM_TAB_ICON_UPDATE, (WPARAM) call_ids[i], NULL); } } } } if (qty == 1) { if (!hold) { last_conf_user_data->inConference = false; CWnd *hWnd = AfxGetApp()->m_pMainWnd; if (hWnd) { hWnd->PostMessage(UM_TAB_ICON_UPDATE, (WPARAM) call_info->id, NULL); } } } } if (!hold) { user_data->inConference = false; } } } void msip_call_hold(pjsua_call_info *call_info) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } call_user_data *user_data = (call_user_data *) pjsua_call_get_user_data(call_info->id); if (user_data && user_data->inConference) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { if (call_ids[i] != call_info->id ) { call_user_data *user_data_curr = (call_user_data *) pjsua_call_get_user_data(call_ids[i]); if (user_data_curr && user_data_curr->inConference) { pjsua_call_info call_info_curr; pjsua_call_get_info(call_ids[i], &call_info_curr); if (call_info_curr.state == PJSIP_INV_STATE_CONFIRMED) { if (call_info_curr.media_status != PJSUA_CALL_MEDIA_LOCAL_HOLD && call_info_curr.media_status != PJSUA_CALL_MEDIA_NONE) { pjsua_call_set_hold(call_info_curr.id, NULL); } } } } } } } if (call_info->state == PJSIP_INV_STATE_CONFIRMED) { if (call_info->media_status != PJSUA_CALL_MEDIA_LOCAL_HOLD && call_info->media_status != PJSUA_CALL_MEDIA_NONE) { pjsua_call_set_hold(call_info->id, NULL); } } } void msip_call_unhold(pjsua_call_info *call_info) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } call_user_data *user_data = NULL; if (call_info) { user_data = (call_user_data *) pjsua_call_get_user_data(call_info->id); } bool inConference = user_data && user_data->inConference; pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { if (!call_info || call_ids[i] != call_info->id ) { pjsua_call_info call_info_curr; pjsua_call_get_info(call_ids[i], &call_info_curr); if (call_info_curr.state == PJSIP_INV_STATE_CONFIRMED) { call_user_data *user_data_curr = (call_user_data *) pjsua_call_get_user_data(call_ids[i]); bool inConferenceCurr = user_data_curr && user_data_curr->inConference; if (inConference && inConferenceCurr) { // unhold if (call_info_curr.media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD || call_info_curr.media_status == PJSUA_CALL_MEDIA_NONE) { pjsua_call_reinvite(call_ids[i], PJSUA_CALL_UNHOLD, NULL); } } else { // hold if (call_info_curr.media_status != PJSUA_CALL_MEDIA_LOCAL_HOLD && call_info_curr.media_status != PJSUA_CALL_MEDIA_NONE) { pjsua_call_set_hold(call_ids[i], NULL); } } } } } } if (call_info && call_info->state == PJSIP_INV_STATE_CONFIRMED) { if (call_info->media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD || call_info->media_status == PJSUA_CALL_MEDIA_NONE) { pjsua_call_reinvite(call_info->id, PJSUA_CALL_UNHOLD, NULL); } } } void msip_call_answer(pjsua_call_id call_id) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned calls_count = PJSUA_MAX_CALLS; unsigned calls_count_cmp = 0; if (pjsua_enum_calls ( call_ids, &calls_count)==PJ_SUCCESS) { for (unsigned i = 0; i < calls_count; ++i) { pjsua_call_info call_info; if (pjsua_call_get_info(call_ids[i], &call_info) == PJ_SUCCESS) { if (call_info.role==PJSIP_ROLE_UAS && (call_info.state==PJSIP_INV_STATE_INCOMING || call_info.state==PJSIP_INV_STATE_EARLY)) { CWnd *hWnd = AfxGetApp()->m_pMainWnd; if (hWnd) { hWnd->PostMessage(UM_CALL_ANSWER, (WPARAM) call_ids[i], NULL); } break; } } } } } CStringA msip_md5sum(CString *str) { CStringA md5sum; CStringA utf8 = Utf8EncodeUcs2(str->GetBuffer()); DWORD cbContent= utf8.GetLength(); BYTE* pbContent= (BYTE*)utf8.GetBuffer(cbContent); pj_md5_context ctx; pj_uint8_t digest[16]; pj_md5_init(&ctx); pj_md5_update(&ctx, (pj_uint8_t*)pbContent,cbContent); pj_md5_final(&ctx, digest); char *p = md5sum.GetBuffer(32); for (int i = 0; i<16; ++i) { pj_val_to_hex_digit(digest[i], p); p += 2; } md5sum.ReleaseBuffer(); return md5sum; } CString msip_url_mask(CString url) { if (accountSettings.accountId) { url.Replace(_T("{server}"),get_account_server()); url.Replace(_T("{username}"),CString(urlencode(Utf8EncodeUcs2(accountSettings.account.username)))); url.Replace(_T("{password}"),CString(urlencode(Utf8EncodeUcs2(accountSettings.account.password)))); url.Replace(_T("{md5_password}"),CString(msip_md5sum(&accountSettings.account.password))); } else { url.Replace(_T("{server}"),_T("localhost")); url.Replace(_T("{username}"),_T("")); url.Replace(_T("{password}"),_T("")); url.Replace(_T("{md5_password}"),_T("")); } return url; } //void msip_audio_output_set_volume(int val, bool mute) //{ // if (mute) { // val = 0; // } else { // pj_status_t status = // pjsua_snd_set_setting( // PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, // &val, PJ_TRUE); // if (status == PJ_SUCCESS) { // val = 100; // } // } // pjsua_conf_adjust_tx_level(0, (float)val/100); //} void msip_audio_conf_set_volume(int val, bool mute) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } if (mute) { val = 0; } pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned count = PJSUA_MAX_CALLS; if (pjsua_enum_calls ( call_ids, &count)==PJ_SUCCESS) { for (unsigned i = 0; i < count; ++i) { pjsua_conf_port_id conf_port_id = pjsua_call_get_conf_port(call_ids[i]); if (conf_port_id!=PJSUA_INVALID_ID) { pjsua_conf_adjust_rx_level(conf_port_id, (float)val/100); } } } } void msip_audio_input_set_volume(int val, bool mute) { if (pjsua_var.state!=PJSUA_STATE_RUNNING) { return; } if (mute) { val = 0; } else { pj_status_t status = -1; if (!accountSettings.swLevelAdjustment) { int valHW; if (accountSettings.micAmplification) { valHW = val>=50 ? 100 : val*2; } else { valHW = val; } status = pjsua_snd_set_setting( PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, &valHW, PJ_TRUE); } if (status==PJ_SUCCESS) { if (accountSettings.micAmplification && val>50) { val = 100 + pow((float)val-50,1.68f); } else { val = 100; } } else { if (accountSettings.micAmplification) { if (val>50) { val = 50+pow((float)val-50,1.7f); } } } } pjsua_conf_adjust_rx_level(0, (float)val/100); }