mirror of
https://github.com/voiceip/tinyphone
synced 2026-08-07 02:26:03 -04:00
4007 lines
108 KiB
C++
4007 lines
108 KiB
C++
/*
|
|
* 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 "mainDlg.h"
|
|
|
|
#include "microsip.h"
|
|
|
|
#include "Mmsystem.h"
|
|
#include "settings.h"
|
|
#include "global.h"
|
|
#include "ModelessMessageBox.h"
|
|
#include "utf.h"
|
|
#include "langpack.h"
|
|
#include "jumplist.h"
|
|
#include "atlenc.h"
|
|
|
|
#include <io.h>
|
|
#include <afxinet.h>
|
|
#include <ws2tcpip.h>
|
|
#include <Dbt.h>
|
|
#include <Strsafe.h>
|
|
#include <locale.h>
|
|
#include <Wtsapi32.h>
|
|
#include <afxsock.h>
|
|
#include "atlrx.h"
|
|
|
|
using namespace MSIP;
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
CmainDlg *mainDlg;
|
|
|
|
static UINT WM_SHELLHOOKMESSAGE;
|
|
|
|
static UINT BASED_CODE indicators[] =
|
|
{
|
|
IDS_STATUSBAR,
|
|
IDS_STATUSBAR2
|
|
};
|
|
|
|
static bool timerContactBlinkState = false;
|
|
|
|
static CString gethostbyaddrThreadResult;
|
|
static DWORD WINAPI gethostbyaddrThread(LPVOID lpParam)
|
|
{
|
|
CString *addr = (CString *)lpParam;
|
|
gethostbyaddrThreadResult = *addr;
|
|
struct hostent *he = NULL;
|
|
struct in_addr inaddr;
|
|
inaddr.S_un.S_addr = inet_addr(CStringA(*addr));
|
|
if (inaddr.S_un.S_addr != INADDR_NONE && inaddr.S_un.S_addr != INADDR_ANY) {
|
|
he = gethostbyaddr((char *)&inaddr, 4, AF_INET);
|
|
if (he) {
|
|
gethostbyaddrThreadResult = he->h_name;
|
|
}
|
|
}
|
|
delete addr;
|
|
return 0;
|
|
}
|
|
|
|
static void on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info)
|
|
{
|
|
if (!IsWindow(mainDlg->m_hWnd)) {
|
|
return;
|
|
}
|
|
CString *str = NULL;
|
|
PostMessage(mainDlg->m_hWnd, UM_ON_REG_STATE2, (WPARAM)info->cbparam->code, (LPARAM)str);
|
|
}
|
|
|
|
LRESULT CmainDlg::onRegState2(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int code = wParam;
|
|
|
|
if (code == 200) {
|
|
if (accountSettings.usersDirectory.Find(_T("%s")) != -1 || accountSettings.usersDirectory.Find(_T("{")) != -1) {
|
|
UsersDirectoryLoad();
|
|
}
|
|
}
|
|
|
|
UpdateWindowText(_T(""), IDI_DEFAULT, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Callback from timer when the maximum call duration has been
|
|
* exceeded.
|
|
*/
|
|
static void call_timeout_callback(pj_timer_heap_t *timer_heap,
|
|
struct pj_timer_entry *entry)
|
|
{
|
|
pjsua_call_id call_id = entry->id;
|
|
pjsua_msg_data msg_data_;
|
|
pjsip_generic_string_hdr warn;
|
|
pj_str_t hname = pj_str("Warning");
|
|
pj_str_t hvalue = pj_str("399 localhost \"Call duration exceeded\"");
|
|
|
|
PJ_UNUSED_ARG(timer_heap);
|
|
|
|
if (call_id == PJSUA_INVALID_ID) {
|
|
PJ_LOG(1, (THIS_FILE, "Invalid call ID in timer callback"));
|
|
return;
|
|
}
|
|
|
|
/* Add warning header */
|
|
pjsua_msg_data_init(&msg_data_);
|
|
pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue);
|
|
pj_list_push_back(&msg_data_.hdr_list, &warn);
|
|
|
|
/* Call duration has been exceeded; disconnect the call */
|
|
PJ_LOG(3, (THIS_FILE, "Duration (%d seconds) has been exceeded "
|
|
"for call %d, disconnecting the call",
|
|
accountSettings.autoHangUpTime, call_id));
|
|
entry->id = PJSUA_INVALID_ID;
|
|
pjsua_call_hangup(call_id, 200, NULL, &msg_data_);
|
|
}
|
|
|
|
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
|
|
{
|
|
if (!IsWindow(mainDlg->m_hWnd)) {
|
|
return;
|
|
}
|
|
pjsua_call_info *call_info = new pjsua_call_info();
|
|
if (pjsua_call_get_info(call_id, call_info) != PJ_SUCCESS || call_info->state == PJSIP_INV_STATE_NULL) {
|
|
return;
|
|
}
|
|
|
|
call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info->id);
|
|
// reset user_data after call transfer
|
|
if (user_data && user_data->call_id != PJSUA_INVALID_ID && user_data->call_id != call_info->id) {
|
|
pjsua_call_set_user_data(call_info->id, NULL);
|
|
user_data = NULL;
|
|
}
|
|
if (!user_data) {
|
|
user_data = new call_user_data(call_info->id);
|
|
pjsua_call_set_user_data(call_info->id, user_data);
|
|
}
|
|
|
|
switch (call_info->state) {
|
|
case PJSIP_INV_STATE_CALLING:
|
|
msip_call_unhold(call_info);
|
|
break;
|
|
case PJSIP_INV_STATE_CONNECTING:
|
|
msip_call_unhold(call_info);
|
|
break;
|
|
case PJSIP_INV_STATE_CONFIRMED:
|
|
if (accountSettings.autoHangUpTime > 0) {
|
|
/* Schedule timer to hangup call after the specified duration */
|
|
pj_time_val delay;
|
|
user_data->auto_hangup_timer.id = call_info->id;
|
|
user_data->auto_hangup_timer.cb = &call_timeout_callback;
|
|
delay.sec = accountSettings.autoHangUpTime;
|
|
delay.msec = 0;
|
|
pjsua_schedule_timer(&user_data->auto_hangup_timer, &delay);
|
|
}
|
|
break;
|
|
case PJSIP_INV_STATE_DISCONNECTED:
|
|
/* Cancel duration timer, if any */
|
|
if (user_data->auto_hangup_timer.id != PJSUA_INVALID_ID) {
|
|
pjsua_cancel_timer(&user_data->auto_hangup_timer);
|
|
user_data->auto_hangup_timer.id = PJSUA_INVALID_ID;
|
|
}
|
|
call_deinit_tonegen(call_info->id);
|
|
msip_conference_leave(call_info);
|
|
pjsua_call_set_user_data(call_info->id, NULL);
|
|
break;
|
|
}
|
|
PostMessage(mainDlg->m_hWnd, UM_ON_CALL_STATE, (WPARAM)call_info, (LPARAM)user_data);
|
|
}
|
|
|
|
LRESULT CmainDlg::onCallState(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
pjsua_call_info *call_info = (pjsua_call_info *)wParam;
|
|
call_user_data *user_data = (call_user_data *)lParam;
|
|
|
|
//--
|
|
|
|
CString *str = new CString();
|
|
CString adder;
|
|
|
|
if (call_info->state != PJSIP_INV_STATE_DISCONNECTED && call_info->state != PJSIP_INV_STATE_CONNECTING && call_info->remote_contact.slen > 0) {
|
|
SIPURI contactURI;
|
|
ParseSIPURI(PjToStr(&call_info->remote_contact, TRUE), &contactURI);
|
|
CString contactDomain = RemovePort(contactURI.domain);
|
|
struct hostent *he = NULL;
|
|
if (IsIP(contactDomain)) {
|
|
HANDLE hThread;
|
|
CString *addr = new CString;
|
|
*addr = contactDomain;
|
|
hThread = CreateThread(NULL, 0, gethostbyaddrThread, addr, 0, NULL);
|
|
if (WaitForSingleObject(hThread, 500) == 0) {
|
|
contactDomain = gethostbyaddrThreadResult;
|
|
}
|
|
}
|
|
adder.AppendFormat(_T("%s, "), contactDomain);
|
|
}
|
|
|
|
unsigned cnt = 0;
|
|
unsigned cnt_srtp = 0;
|
|
|
|
switch (call_info->state) {
|
|
case PJSIP_INV_STATE_CALLING:
|
|
str->Format(_T("%s..."), Translate(_T("Calling")));
|
|
break;
|
|
case PJSIP_INV_STATE_INCOMING:
|
|
str->SetString(Translate(_T("Incoming Call")));
|
|
break;
|
|
case PJSIP_INV_STATE_EARLY:
|
|
str->SetString(Translate(PjToStr(&call_info->last_status_text).GetBuffer()));
|
|
break;
|
|
case PJSIP_INV_STATE_CONNECTING:
|
|
str->Format(_T("%s..."), Translate(_T("Connecting")));
|
|
break;
|
|
case PJSIP_INV_STATE_CONFIRMED:
|
|
str->SetString(Translate(_T("Connected")));
|
|
for (unsigned i = 0; i < call_info->media_cnt; i++) {
|
|
if (call_info->media[i].dir != PJMEDIA_DIR_NONE &&
|
|
(call_info->media[i].type == PJMEDIA_TYPE_AUDIO || call_info->media[i].type == PJMEDIA_TYPE_VIDEO)) {
|
|
cnt++;
|
|
pjsua_call_info call_info_stub;
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING && pjsua_call_get_info(call_info->id, &call_info_stub) == PJ_SUCCESS) {
|
|
pjsua_stream_info psi;
|
|
if (pjsua_call_get_stream_info(call_info->id, call_info->media[i].index, &psi) == PJ_SUCCESS) {
|
|
if (call_info->media[i].type == PJMEDIA_TYPE_AUDIO) {
|
|
adder.AppendFormat(_T("%s@%dkHz %dkbit/s%s, "),
|
|
PjToStr(&psi.info.aud.fmt.encoding_name), psi.info.aud.fmt.clock_rate / 1000,
|
|
psi.info.aud.param->info.avg_bps / 1000,
|
|
psi.info.aud.fmt.channel_cnt == 2 ? _T(" Stereo") : _T("")
|
|
);
|
|
}
|
|
else {
|
|
adder.AppendFormat(_T("%s %dkbit/s, "),
|
|
PjToStr(&psi.info.vid.codec_info.encoding_name),
|
|
psi.info.vid.codec_param->enc_fmt.det.vid.max_bps / 1000
|
|
);
|
|
}
|
|
}
|
|
pjmedia_transport_info t;
|
|
if (pjsua_call_get_med_transport_info(call_info->id, call_info->media[i].index, &t) == PJ_SUCCESS) {
|
|
for (unsigned j = 0; j < t.specific_info_cnt; j++) {
|
|
if (t.spc_info[j].buffer[0]) {
|
|
switch (t.spc_info[j].type) {
|
|
case PJMEDIA_TRANSPORT_TYPE_SRTP:
|
|
adder.Append(_T("SRTP, "));
|
|
cnt_srtp++;
|
|
break;
|
|
case PJMEDIA_TRANSPORT_TYPE_ICE:
|
|
adder.Append(_T("ICE, "));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (cnt_srtp && cnt == cnt_srtp) {
|
|
user_data->srtp = MSIP_SRTP;
|
|
}
|
|
else {
|
|
user_data->srtp = MSIP_SRTP_DISABLED;
|
|
}
|
|
break;
|
|
case PJSIP_INV_STATE_DISCONNECTED:
|
|
//--
|
|
if (call_info->last_status == 200) {
|
|
str->SetString(Translate(_T("Call Ended")));
|
|
}
|
|
else {
|
|
CString rab = PjToStr(&call_info->last_status_text);
|
|
if (rab.Find(_T("(PJ_ERESOLVE)")) != -1) {
|
|
rab = _T("Cannot get IP address of the called host.");
|
|
}
|
|
rab = Translate(rab.GetBuffer());
|
|
if (call_info->last_status) {
|
|
str->Format(_T("%d %s"), call_info->last_status, rab);
|
|
}
|
|
else {
|
|
str->SetString(rab);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!str->IsEmpty() && !adder.IsEmpty()) {
|
|
str->AppendFormat(_T(" (%s)"), adder.Left(adder.GetLength() - 2));
|
|
}
|
|
|
|
//--
|
|
|
|
CString number = PjToStr(&call_info->remote_info, TRUE);
|
|
SIPURI sipuri;
|
|
ParseSIPURI(number, &sipuri);
|
|
if (call_info->state == PJSIP_INV_STATE_CONFIRMED) {
|
|
PostMessage(WM_TIMER, IDT_TIMER_CALL, NULL);
|
|
SetTimer(IDT_TIMER_CALL, 1000, NULL);
|
|
if (!accountSettings.cmdCallStart.IsEmpty()) {
|
|
ShellExecute(NULL, NULL, accountSettings.cmdCallStart, sipuri.user, NULL, SW_HIDE);
|
|
}
|
|
if (user_data && !user_data->commands.IsEmpty()) {
|
|
SetTimer((UINT_PTR)call_info->id, 1000, (TIMERPROC)DTMFQueueTimerHandler);
|
|
}
|
|
}
|
|
|
|
if (!accountSettings.singleMode) {
|
|
if (call_info->state != PJSIP_INV_STATE_CONFIRMED) {
|
|
if (call_info->state != PJSIP_INV_STATE_DISCONNECTED) {
|
|
UpdateWindowText(*str, call_info->acc_id == account && mainDlg->iconStatusbar == IDI_SECURE ? IDI_SECURE : IDI_ONLINE);
|
|
}
|
|
else {
|
|
PostMessage(UM_UPDATEWINDOWTEXT, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (call_info->role == PJSIP_ROLE_UAC && accountSettings.localDTMF) {
|
|
if (call_info->last_status == 180 && !call_info->media_cnt) {
|
|
if (toneCalls.IsEmpty()) {
|
|
PostMessage(WM_TIMER, IDT_TIMER_TONE, NULL);
|
|
SetTimer(IDT_TIMER_TONE, 4500, NULL);
|
|
toneCalls.AddTail(call_info->id);
|
|
}
|
|
else if (toneCalls.Find(call_info->id) == NULL) {
|
|
toneCalls.AddTail(call_info->id);
|
|
}
|
|
}
|
|
else {
|
|
POSITION position = toneCalls.Find(call_info->id);
|
|
if (position != NULL) {
|
|
toneCalls.RemoveAt(position);
|
|
if (toneCalls.IsEmpty()) {
|
|
KillTimer(IDT_TIMER_TONE);
|
|
PostMessage(UM_ON_PLAYER_STOP, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool doNotShowMessagesWindow =
|
|
call_info->state == PJSIP_INV_STATE_INCOMING ||
|
|
call_info->state == PJSIP_INV_STATE_EARLY ||
|
|
call_info->state == PJSIP_INV_STATE_DISCONNECTED ||
|
|
accountSettings.singleMode ||
|
|
(accountSettings.silent && !mainDlg->IsWindowVisible());
|
|
MessagesContact* messagesContact = messagesDlg->AddTab(number, _T(""),
|
|
(!accountSettings.singleMode &&
|
|
(call_info->state == PJSIP_INV_STATE_CONFIRMED
|
|
|| call_info->state == PJSIP_INV_STATE_CONNECTING)
|
|
)
|
|
||
|
|
(accountSettings.singleMode
|
|
&&
|
|
(
|
|
(call_info->role == PJSIP_ROLE_UAC && call_info->state != PJSIP_INV_STATE_DISCONNECTED)
|
|
||
|
|
(call_info->role == PJSIP_ROLE_UAS &&
|
|
(call_info->state == PJSIP_INV_STATE_CONFIRMED
|
|
|| call_info->state == PJSIP_INV_STATE_CONNECTING)
|
|
)
|
|
))
|
|
? TRUE : FALSE,
|
|
call_info, user_data, doNotShowMessagesWindow, call_info->state == PJSIP_INV_STATE_DISCONNECTED
|
|
);
|
|
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
CString number = sipuri.user;
|
|
if (call_info->last_status == 200) {
|
|
onPlayerPlay(MSIP_SOUND_HANGUP, 0);
|
|
}
|
|
else {
|
|
if (accountSettings.singleMode && call_info->last_status != 487 && (call_info->last_status != 603 || call_info->role == PJSIP_ROLE_UAC)) {
|
|
if (messagesContact) {
|
|
BaloonPopup(*str, messagesContact->name, NIIF_INFO);
|
|
}
|
|
else {
|
|
BaloonPopup(*str, number, NIIF_INFO);
|
|
}
|
|
}
|
|
}
|
|
if (call_info->last_status != 486) {
|
|
if (!accountSettings.cmdCallEnd.IsEmpty()) {
|
|
ShellExecute(NULL, NULL, accountSettings.cmdCallEnd, number, NULL, SW_HIDE);
|
|
}
|
|
}
|
|
if (call_info->role == PJSIP_ROLE_UAS && call_info->last_status == 487) {
|
|
//-- missed call
|
|
missed = true;
|
|
}
|
|
}
|
|
|
|
if (messagesContact) {
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
messagesContact->mediaStatus = PJSUA_CALL_MEDIA_ERROR;
|
|
}
|
|
if (call_info->role == PJSIP_ROLE_UAS) {
|
|
if (call_info->state == PJSIP_INV_STATE_CONFIRMED) {
|
|
pageCalls->Add(call_info->call_id, messagesContact->number + messagesContact->numberParameters, messagesContact->name, MSIP_CALL_IN);
|
|
}
|
|
else if (call_info->state == PJSIP_INV_STATE_INCOMING || call_info->state == PJSIP_INV_STATE_EARLY) {
|
|
pageCalls->Add(call_info->call_id, messagesContact->number + messagesContact->numberParameters, messagesContact->name, MSIP_CALL_MISS);
|
|
}
|
|
}
|
|
else {
|
|
if (call_info->state == PJSIP_INV_STATE_CALLING) {
|
|
pageCalls->Add(call_info->call_id, messagesContact->number + messagesContact->numberParameters, messagesContact->name, MSIP_CALL_OUT);
|
|
}
|
|
}
|
|
}
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
pageCalls->SetDuration(call_info->call_id, call_info->connect_duration.sec);
|
|
if (call_info->last_status != 200) {
|
|
pageCalls->SetInfo(call_info->call_id, *str);
|
|
}
|
|
}
|
|
|
|
if (call_info->role == PJSIP_ROLE_UAS && call_info->state == PJSIP_INV_STATE_CONFIRMED) {
|
|
if (!accountSettings.cmdCallAnswer.IsEmpty()) {
|
|
ShellExecute(NULL, NULL, accountSettings.cmdCallAnswer, sipuri.user, NULL, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
if (accountSettings.singleMode) {
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
MessagesContact *messagesContactSelected = messagesDlg->GetMessageContact();
|
|
if (!messagesContactSelected || messagesContactSelected->callId == call_info->id || messagesContactSelected->callId == -1) {
|
|
pageDialer->Clear(false);
|
|
pageDialer->UpdateCallButton(FALSE, 0);
|
|
}
|
|
PostMessage(UM_UPDATEWINDOWTEXT, 0, 0);
|
|
}
|
|
else {
|
|
if (call_info->state != PJSIP_INV_STATE_CONFIRMED) {
|
|
UpdateWindowText(*str, call_info->acc_id == account && mainDlg->iconStatusbar == IDI_SECURE ? IDI_SECURE : IDI_ONLINE);
|
|
}
|
|
int tabN = 0;
|
|
GotoTab(tabN);
|
|
messagesDlg->OnChangeTab(call_info, user_data);
|
|
}
|
|
}
|
|
else {
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
pageDialer->PostMessage(WM_COMMAND, MAKELPARAM(IDC_CLEAR, 0), 0);
|
|
}
|
|
}
|
|
|
|
if (messagesContact && !str->IsEmpty()) {
|
|
messagesDlg->AddMessage(messagesContact, *str, MSIP_MESSAGE_TYPE_SYSTEM,
|
|
call_info->state == PJSIP_INV_STATE_INCOMING || call_info->state == PJSIP_INV_STATE_EARLY
|
|
);
|
|
}
|
|
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
messagesDlg->OnEndCall(call_info);
|
|
if (pjsua_var.state != PJSUA_STATE_RUNNING || !pjsua_call_get_count()) {
|
|
#ifdef _GLOBAL_VIDEO
|
|
if (previewWin) {
|
|
previewWin->PostMessage(WM_CLOSE, NULL, NULL);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (call_info->role == PJSIP_ROLE_UAS) {
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED || call_info->state == PJSIP_INV_STATE_CONFIRMED) {
|
|
int count = ringinDlgs.GetCount();
|
|
if (!count) {
|
|
if (call_info->state == PJSIP_INV_STATE_CONFIRMED || (call_info->state == PJSIP_INV_STATE_DISCONNECTED && call_info->connect_duration.sec == 0 && call_info->connect_duration.msec == 0)) {
|
|
PlayerStop();
|
|
}
|
|
}
|
|
else {
|
|
for (int i = 0; i < count; i++) {
|
|
RinginDlg *ringinDlg = ringinDlgs.GetAt(i);
|
|
if (call_info->id == ringinDlg->call_id) {
|
|
if (count == 1) {
|
|
PlayerStop();
|
|
}
|
|
ringinDlgs.RemoveAt(i);
|
|
ringinDlg->DestroyWindow();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --delete user data
|
|
if (call_info->state == PJSIP_INV_STATE_DISCONNECTED) {
|
|
if (user_data) {
|
|
delete user_data;
|
|
}
|
|
}
|
|
// --
|
|
delete call_info;
|
|
delete str;
|
|
return 0;
|
|
}
|
|
|
|
static void on_call_media_state(pjsua_call_id call_id)
|
|
{
|
|
pjsua_call_info *call_info = new pjsua_call_info();
|
|
if (pjsua_call_get_info(call_id, call_info) != PJ_SUCCESS || call_info->state == PJSIP_INV_STATE_NULL) {
|
|
return;
|
|
}
|
|
|
|
call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info->id);
|
|
|
|
if (call_info->media_status == PJSUA_CALL_MEDIA_ACTIVE
|
|
|| call_info->media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD
|
|
) {
|
|
msip_conference_join(call_info);
|
|
pjsua_conf_connect(call_info->conf_slot, 0);
|
|
pjsua_conf_connect(0, call_info->conf_slot);
|
|
//--
|
|
//--
|
|
::SetTimer(mainDlg->pageDialer->m_hWnd, IDT_TIMER_VU_METER, 100, NULL);
|
|
//--
|
|
}
|
|
else {
|
|
msip_conference_leave(call_info, true);
|
|
pjsua_conf_disconnect(call_info->conf_slot, 0);
|
|
pjsua_conf_disconnect(0, call_info->conf_slot);
|
|
call_deinit_tonegen(call_id);
|
|
//--
|
|
//--
|
|
}
|
|
PostMessage(mainDlg->m_hWnd, UM_ON_CALL_MEDIA_STATE, (WPARAM)call_info, (LPARAM)user_data);
|
|
}
|
|
|
|
LRESULT CmainDlg::onCallMediaState(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
pjsua_call_info *call_info = (pjsua_call_info *)wParam;
|
|
call_user_data *user_data = (call_user_data *)lParam;
|
|
|
|
messagesDlg->UpdateHoldButton(call_info);
|
|
|
|
CString message;
|
|
CString number = PjToStr(&call_info->remote_info, TRUE);
|
|
|
|
MessagesContact* messagesContact = messagesDlg->AddTab(number, _T(""), FALSE, call_info, user_data, TRUE, TRUE);
|
|
|
|
if (messagesContact) {
|
|
if (call_info->media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) {
|
|
message = _T("Call on Remote Hold");
|
|
}
|
|
if (call_info->media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) {
|
|
message = _T("Call on Local Hold");
|
|
}
|
|
if (call_info->media_status == PJSUA_CALL_MEDIA_NONE) {
|
|
message = _T("Call on Hold");
|
|
}
|
|
if (messagesContact->mediaStatus != PJSUA_CALL_MEDIA_ERROR && messagesContact->mediaStatus != call_info->media_status && call_info->media_status == PJSUA_CALL_MEDIA_ACTIVE) {
|
|
message = _T("Call is Active");
|
|
}
|
|
if (!message.IsEmpty()) {
|
|
messagesDlg->AddMessage(messagesContact, Translate(message.GetBuffer()), MSIP_MESSAGE_TYPE_SYSTEM, TRUE);
|
|
}
|
|
messagesContact->mediaStatus = call_info->media_status;
|
|
}
|
|
|
|
if (call_info->media_status == PJSUA_CALL_MEDIA_ACTIVE
|
|
|| call_info->media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD
|
|
) {
|
|
onRefreshLevels(0, 0);
|
|
}
|
|
|
|
delete call_info;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void on_call_media_event(pjsua_call_id call_id,
|
|
unsigned med_idx,
|
|
pjmedia_event *event)
|
|
{
|
|
char event_name[5];
|
|
|
|
PJ_LOG(5, (THIS_FILE, "Event %s",
|
|
pjmedia_fourcc_name(event->type, event_name)));
|
|
|
|
//#if PJSUA_HAS_VIDEO
|
|
//if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
|
|
// pjsua_call_info ci;
|
|
// pjsua_call_get_info(call_id, &ci);
|
|
// if ((ci.media[med_idx].type == PJMEDIA_TYPE_VIDEO) &&
|
|
// (ci.media[med_idx].dir & PJMEDIA_DIR_DECODING)) {
|
|
// pjsua_vid_win_id wid;
|
|
// pjmedia_rect_size size;
|
|
// pjsua_vid_win_info win_info;
|
|
|
|
// wid = ci.media[med_idx].stream.vid.win_in;
|
|
// pjsua_vid_win_get_info(wid, &win_info);
|
|
|
|
// size = event->data.fmt_changed.new_fmt.det.vid.size;
|
|
// if (size.w != win_info.size.w || size.h != win_info.size.h) {
|
|
// pjsua_vid_win_set_size(wid, &size);
|
|
// /* Re-arrange video windows */
|
|
// arrange_window(PJSUA_INVALID_ID);
|
|
// }
|
|
// }
|
|
//}
|
|
//#else
|
|
// PJ_UNUSED_ARG(call_id);
|
|
// PJ_UNUSED_ARG(med_idx);
|
|
// PJ_UNUSED_ARG(event);
|
|
//#endif
|
|
}
|
|
|
|
static void on_incoming_call(pjsua_acc_id acc, pjsua_call_id call_id,
|
|
pjsip_rx_data *rdata)
|
|
{
|
|
pjsua_call_info call_info;
|
|
pjsua_call_get_info(call_id, &call_info);
|
|
|
|
call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info.id);
|
|
if (!user_data) {
|
|
user_data = new call_user_data(call_info.id);
|
|
pjsua_call_set_user_data(call_info.id, user_data);
|
|
}
|
|
|
|
SIPURI sipuri;
|
|
ParseSIPURI(PjToStr(&call_info.remote_info, TRUE), &sipuri);
|
|
if (accountSettings.forceCodec) {
|
|
pjsua_call *call;
|
|
pjsip_dialog *dlg;
|
|
pj_status_t status;
|
|
status = acquire_call("on_incoming_call()", call_id, &call, &dlg);
|
|
if (status == PJ_SUCCESS) {
|
|
pjmedia_sdp_neg_set_prefer_remote_codec_order(call->inv->neg, PJ_FALSE);
|
|
pjsip_dlg_dec_lock(dlg);
|
|
}
|
|
}
|
|
|
|
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_curr;
|
|
if (pjsua_call_get_info(call_ids[i], &call_info_curr) == PJ_SUCCESS) {
|
|
SIPURI sipuri_curr;
|
|
ParseSIPURI(PjToStr(&call_info_curr.remote_info, TRUE), &sipuri_curr);
|
|
if (call_info_curr.id != call_info.id &&
|
|
sipuri.user + _T("@") + sipuri.domain == sipuri_curr.user + _T("@") + sipuri_curr.domain
|
|
) {
|
|
// 486 Busy Here
|
|
pjsua_call_hangup(call_info.id, 486, NULL, NULL);
|
|
return;
|
|
}
|
|
if (call_info_curr.state != PJSIP_INV_STATE_DISCONNECTED) {
|
|
calls_count_cmp++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (accountSettings.maxConcurrentCalls > 0 && calls_count_cmp > accountSettings.maxConcurrentCalls) {
|
|
// 486 Busy Here
|
|
pjsua_call_hangup(call_info.id, 486, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
if (IsWindow(mainDlg->m_hWnd)) {
|
|
// -- diversion
|
|
const pj_str_t headerDiversion = { "Diversion",9 };
|
|
pjsip_generic_string_hdr *hsr = NULL;
|
|
hsr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &headerDiversion, NULL);
|
|
if (hsr) {
|
|
CString str = PjToStr(&hsr->hvalue, true);
|
|
SIPURI sipuriDiversion;
|
|
ParseSIPURI(str, &sipuriDiversion);
|
|
user_data->diversion = !sipuriDiversion.user.IsEmpty() ? sipuriDiversion.user : sipuriDiversion.domain;
|
|
}
|
|
// -- end diversion
|
|
if (!mainDlg->callIdIncomingIgnore.IsEmpty() && mainDlg->callIdIncomingIgnore == PjToStr(&call_info.call_id)) {
|
|
pjsua_call_answer(call_id, 487, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
bool reject = false;
|
|
if (accountSettings.denyIncoming == _T("all")) {
|
|
reject = true;
|
|
}
|
|
else if (accountSettings.denyIncoming == _T("button")) {
|
|
reject = accountSettings.DND;
|
|
}
|
|
else if (accountSettings.denyIncoming == _T("user")) {
|
|
SIPURI sipuri_curr;
|
|
ParseSIPURI(PjToStr(&call_info.local_info, TRUE), &sipuri_curr);
|
|
if (sipuri_curr.user != get_account_username()) {
|
|
reject = true;
|
|
}
|
|
}
|
|
else if (accountSettings.denyIncoming == _T("domain")) {
|
|
SIPURI sipuri_curr;
|
|
ParseSIPURI(PjToStr(&call_info.local_info, TRUE), &sipuri_curr);
|
|
if (accountSettings.accountId) {
|
|
if (sipuri_curr.domain != accountSettings.account.domain) {
|
|
reject = true;
|
|
}
|
|
}
|
|
}
|
|
else if (accountSettings.denyIncoming == _T("rdomain")) {
|
|
if (accountSettings.accountId) {
|
|
if (sipuri.domain != accountSettings.account.domain) {
|
|
reject = true;
|
|
}
|
|
}
|
|
}
|
|
else if (accountSettings.denyIncoming == _T("address")) {
|
|
SIPURI sipuri_curr;
|
|
ParseSIPURI(PjToStr(&call_info.local_info, TRUE), &sipuri_curr);
|
|
if (sipuri_curr.user != get_account_username() || (accountSettings.account.domain != _T("") && sipuri_curr.domain != accountSettings.account.domain)) {
|
|
reject = true;
|
|
}
|
|
}
|
|
|
|
if (reject) {
|
|
pjsua_call_hangup(call_info.id, 486, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
accountSettings.lastCallNumber = sipuri.user;
|
|
accountSettings.lastCallHasVideo = false;
|
|
|
|
if (!accountSettings.cmdIncomingCall.IsEmpty()) {
|
|
ShellExecute(NULL, NULL, accountSettings.cmdIncomingCall, sipuri.user, NULL, SW_HIDE);
|
|
}
|
|
|
|
bool autoAnswer = false;
|
|
bool noRingDialog = false;
|
|
if (accountSettings.autoAnswer == _T("all")) {
|
|
autoAnswer = true;
|
|
}
|
|
else if (accountSettings.autoAnswer == _T("button")) {
|
|
autoAnswer = accountSettings.AA;
|
|
}
|
|
else if (accountSettings.autoAnswer == _T("header")) {
|
|
//--
|
|
pjsip_generic_string_hdr *hsr = NULL;
|
|
const pj_str_t header = pj_str("X-AUTOANSWER");
|
|
hsr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &header, NULL);
|
|
if (hsr) {
|
|
CString autoAnswerValue = PjToStr(&hsr->hvalue, TRUE);
|
|
autoAnswerValue.MakeLower();
|
|
if (autoAnswerValue == _T("true") || autoAnswerValue == _T("1")) {
|
|
autoAnswer = 1;
|
|
}
|
|
}
|
|
//--
|
|
if (!autoAnswer) {
|
|
pjsip_generic_string_hdr *hsr = NULL;
|
|
const pj_str_t header = pj_str("Call-Info");
|
|
hsr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &header, NULL);
|
|
if (hsr) {
|
|
CString callInfoValue = PjToStr(&hsr->hvalue, TRUE);
|
|
callInfoValue.MakeLower();
|
|
if (callInfoValue.Find(_T("auto answer")) != -1) {
|
|
autoAnswer = 1;
|
|
}
|
|
else {
|
|
CAtlRegExp<> regex;
|
|
REParseError parseStatus = regex.Parse(_T("answer-after={[0-9]+}"), true);
|
|
if (parseStatus == REPARSE_ERROR_OK) {
|
|
CAtlREMatchContext<> mc;
|
|
if (regex.Match(callInfoValue, &mc) && mc.m_uNumGroups == 1) {
|
|
const CAtlREMatchContext<>::RECHAR* szStart = 0;
|
|
const CAtlREMatchContext<>::RECHAR* szEnd = 0;
|
|
mc.GetMatch(0, &szStart, &szEnd);
|
|
ptrdiff_t nLength = szEnd - szStart;
|
|
CStringA text(szStart, nLength);
|
|
int autoAnswerTimeout = atoi(text);
|
|
if (!autoAnswerTimeout) {
|
|
autoAnswer = 1;
|
|
}
|
|
else if (autoAnswerTimeout > 0) {
|
|
if (mainDlg->autoAnswerCallId == PJSUA_INVALID_ID) {
|
|
noRingDialog = true;
|
|
mainDlg->autoAnswerCallId = call_id;
|
|
mainDlg->SetTimer(IDT_TIMER_AUTOANSWER, autoAnswerTimeout * 1000, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BOOL playBeep = FALSE;
|
|
if (autoAnswer && calls_count <= 1) {
|
|
mainDlg->AutoAnswer(call_id);
|
|
}
|
|
else {
|
|
if (accountSettings.hidden) {
|
|
mainDlg->PostMessage(UM_CALL_HANGUP, (WPARAM)call_id, NULL);
|
|
}
|
|
else {
|
|
if (!noRingDialog) {
|
|
//--
|
|
const pj_str_t headerUserAgent = { "User-Agent",10 };
|
|
pjsip_generic_string_hdr *hsr = NULL;
|
|
hsr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &headerUserAgent, NULL);
|
|
if (hsr) {
|
|
user_data->userAgent = PjToStr(&hsr->hvalue, true);
|
|
}
|
|
//--
|
|
mainDlg->PostMessage(UM_CREATE_RINGING, (WPARAM)call_id, NULL);
|
|
}
|
|
pjsua_call_answer(call_id, 180, NULL, NULL);
|
|
if (call_get_count_noincoming()) {
|
|
playBeep = TRUE;
|
|
}
|
|
else {
|
|
if (!accountSettings.ringingSound.GetLength()) {
|
|
mainDlg->PostMessage(UM_ON_PLAYER_PLAY, MSIP_SOUND_RINGIN, 0);
|
|
}
|
|
else {
|
|
mainDlg->PostMessage(UM_ON_PLAYER_PLAY, MSIP_SOUND_CUSTOM, (LPARAM)&accountSettings.ringingSound);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (playBeep) {
|
|
mainDlg->PostMessage(UM_ON_PLAYER_PLAY, MSIP_SOUND_RINGIN2, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void on_nat_detect(const pj_stun_nat_detect_result *res)
|
|
{
|
|
if (res->status != PJ_SUCCESS) {
|
|
pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
|
|
}
|
|
else {
|
|
if (res->nat_type == PJ_STUN_NAT_TYPE_SYMMETRIC) {
|
|
if (IsWindow(mainDlg->m_hWnd)) {
|
|
CString message;
|
|
pjsua_acc_config acc_cfg;
|
|
pj_pool_t *pool;
|
|
pool = pjsua_pool_create("acc_cfg-pjsua", 1000, 1000);
|
|
if (pool) {
|
|
pjsua_acc_id ids[PJSUA_MAX_ACC];
|
|
unsigned count = PJSUA_MAX_ACC;
|
|
if (pjsua_enum_accs(ids, &count) == PJ_SUCCESS) {
|
|
for (unsigned i = 0; i < count; i++) {
|
|
if (pjsua_acc_get_config(ids[i], pool, &acc_cfg) == PJ_SUCCESS) {
|
|
acc_cfg.sip_stun_use = PJSUA_STUN_USE_DISABLED;
|
|
acc_cfg.media_stun_use = PJSUA_STUN_USE_DISABLED;
|
|
if (pjsua_acc_modify(ids[i], &acc_cfg) == PJ_SUCCESS) {
|
|
message = _T("STUN was automatically disabled.");
|
|
message.Append(_T(" For more info visit MicroSIP website, help page."));
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pj_pool_release(pool);
|
|
}
|
|
mainDlg->BaloonPopup(_T("Symmetric NAT detected!"), message);
|
|
}
|
|
}
|
|
PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
|
|
}
|
|
}
|
|
|
|
static void on_buddy_state(pjsua_buddy_id buddy_id)
|
|
{
|
|
if (IsWindow(mainDlg->m_hWnd)) {
|
|
pjsua_buddy_info buddy_info;
|
|
if (pjsua_buddy_get_info(buddy_id, &buddy_info) == PJ_SUCCESS) {
|
|
Contact *contact = (Contact *)pjsua_buddy_get_user_data(buddy_id);
|
|
if (contact) {
|
|
int image;
|
|
bool ringing = false;
|
|
switch (buddy_info.status)
|
|
{
|
|
case PJSUA_BUDDY_STATUS_OFFLINE:
|
|
image = MSIP_CONTACT_ICON_OFFLINE;
|
|
break;
|
|
case PJSUA_BUDDY_STATUS_ONLINE:
|
|
/*
|
|
if (buddy_info.rpid.activity == PJRPID_ACTIVITY_ON_THE_PHONE) {
|
|
image = MSIP_CONTACT_ICON_ON_THE_PHONE;
|
|
if (PjToStr(&buddy_info.status_text).Left(4) == _T("Ring")) {
|
|
ringing = true;
|
|
}
|
|
}
|
|
else*/
|
|
if (buddy_info.rpid.activity == PJRPID_ACTIVITY_AWAY)
|
|
{
|
|
image = MSIP_CONTACT_ICON_AWAY;
|
|
}
|
|
else if (buddy_info.rpid.activity == PJRPID_ACTIVITY_BUSY)
|
|
{
|
|
image = MSIP_CONTACT_ICON_BUSY;
|
|
|
|
}
|
|
else
|
|
{
|
|
image = MSIP_CONTACT_ICON_ONLINE;
|
|
}
|
|
break;
|
|
default:
|
|
image = MSIP_CONTACT_ICON_UNKNOWN;
|
|
break;
|
|
}
|
|
contact->image = image;
|
|
contact->ringing = ringing;
|
|
contact->presenceNote = PjToStr(&buddy_info.status_text);
|
|
mainDlg->PostMessage(UM_ON_BUDDY_STATE, (WPARAM)contact);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CmainDlg::onBuddyState(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
Contact *contact = (Contact *)wParam;
|
|
CListCtrl *list = (CListCtrl*)pageContacts->GetDlgItem(IDC_CONTACTS);
|
|
int n = list->GetItemCount();
|
|
bool found = false;
|
|
for (int i = 0; i < n; i++) {
|
|
if (contact == (Contact *)list->GetItemData(i)) {
|
|
list->SetItem(i, 0, LVIF_IMAGE, 0, contact->image, 0, 0, 0);
|
|
list->SetItemText(i, 1, contact->presenceNote);
|
|
found = true;
|
|
}
|
|
}
|
|
if (found && contact->ringing) {
|
|
OnTimerContactBlink();
|
|
SetTimer(IDT_TIMER_CONTACTS_BLINK, 500, NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void on_pager2(pjsua_call_id call_id, const pj_str_t *from, const pj_str_t *to, const pj_str_t *contact, const pj_str_t *mime_type, const pj_str_t *body, pjsip_rx_data *rdata, pjsua_acc_id acc_id)
|
|
{
|
|
if (IsWindow(mainDlg->m_hWnd)) {
|
|
CString *number = new CString();
|
|
CString *message = new CString();
|
|
number->SetString(PjToStr(from, TRUE));
|
|
message->SetString(PjToStr(body, TRUE));
|
|
message->Trim();
|
|
//-- fix wrong domain
|
|
SIPURI sipuri;
|
|
ParseSIPURI(*number, &sipuri);
|
|
if (accountSettings.accountId && account == acc_id) {
|
|
if (IsIP(sipuri.domain)) {
|
|
sipuri.domain = accountSettings.account.domain;
|
|
}
|
|
if (!sipuri.user.IsEmpty()) {
|
|
number->Format(_T("%s@%s"), sipuri.user, sipuri.domain);
|
|
}
|
|
else {
|
|
number->SetString(sipuri.domain);
|
|
}
|
|
}
|
|
//--
|
|
mainDlg->PostMessage(UM_ON_PAGER, (WPARAM)number, (LPARAM)message);
|
|
}
|
|
}
|
|
|
|
static void on_pager_status2(pjsua_call_id call_id, const pj_str_t *to, const pj_str_t *body, void *user_data, pjsip_status_code status, const pj_str_t *reason, pjsip_tx_data *tdata, pjsip_rx_data *rdata, pjsua_acc_id acc_id)
|
|
{
|
|
if (status != 200) {
|
|
if (IsWindow(mainDlg->m_hWnd)) {
|
|
CString *number = new CString();
|
|
CString *message = new CString();
|
|
number->SetString(PjToStr(to, TRUE));
|
|
message->SetString(PjToStr(reason, TRUE));
|
|
message->Trim();
|
|
//-- fix wrong domain
|
|
SIPURI sipuri;
|
|
ParseSIPURI(*number, &sipuri);
|
|
if (accountSettings.accountId && account == acc_id) {
|
|
if (IsIP(sipuri.domain)) {
|
|
sipuri.domain = accountSettings.account.domain;
|
|
}
|
|
if (!sipuri.user.IsEmpty()) {
|
|
number->Format(_T("%s@%s"), sipuri.user, sipuri.domain);
|
|
}
|
|
else {
|
|
number->SetString(sipuri.domain);
|
|
}
|
|
}
|
|
//--
|
|
mainDlg->PostMessage(UM_ON_PAGER_STATUS, (WPARAM)number, (LPARAM)message);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void on_call_transfer_status(pjsua_call_id call_id,
|
|
int status_code,
|
|
const pj_str_t *status_text,
|
|
pj_bool_t final,
|
|
pj_bool_t *p_cont)
|
|
{
|
|
pjsua_call_info *call_info = new pjsua_call_info();
|
|
if (pjsua_call_get_info(call_id, call_info) != PJ_SUCCESS || call_info->state == PJSIP_INV_STATE_NULL) {
|
|
return;
|
|
}
|
|
|
|
call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info->id);
|
|
|
|
CString *str = new CString();
|
|
str->Format(_T("%s: %s"),
|
|
Translate(_T("Call Transfer")),
|
|
PjToStr(status_text, TRUE)
|
|
);
|
|
if (final) {
|
|
str->AppendFormat(_T(" [%s]"), Translate(_T("Final")));
|
|
}
|
|
|
|
if (status_code / 100 == 2) {
|
|
*p_cont = PJ_FALSE;
|
|
}
|
|
|
|
call_info->last_status = (pjsip_status_code)status_code;
|
|
|
|
call_info->call_id.ptr = (char *)user_data;
|
|
call_info->call_id.slen = 0;
|
|
|
|
PostMessage(mainDlg->m_hWnd, UM_ON_CALL_TRANSFER_STATUS, (WPARAM)call_info, (LPARAM)str);
|
|
}
|
|
|
|
LRESULT CmainDlg::onCallTransferStatus(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
pjsua_call_info *call_info = (pjsua_call_info *)wParam;
|
|
call_user_data *user_data = (call_user_data *)call_info->call_id.ptr;
|
|
CString *str = (CString *)lParam;
|
|
|
|
|
|
MessagesContact* messagesContact = NULL;
|
|
CString number = PjToStr(&call_info->remote_info, TRUE);
|
|
messagesContact = mainDlg->messagesDlg->AddTab(number, _T(""), FALSE, call_info, user_data, TRUE, TRUE);
|
|
if (messagesContact) {
|
|
mainDlg->messagesDlg->AddMessage(messagesContact, *str);
|
|
}
|
|
if (call_info->last_status / 100 == 2) {
|
|
if (messagesContact) {
|
|
messagesDlg->AddMessage(messagesContact, Translate(_T("Call transfered successfully, disconnecting call")));
|
|
}
|
|
msip_call_hangup_fast(call_info->id);
|
|
}
|
|
delete call_info;
|
|
delete str;
|
|
return 0;
|
|
}
|
|
|
|
static void on_call_transfer_request2(pjsua_call_id call_id, const pj_str_t *dst, pjsip_status_code *code, pjsua_call_setting *opt)
|
|
{
|
|
SIPURI sipuri;
|
|
ParseSIPURI(PjToStr(dst, TRUE), &sipuri);
|
|
// display transfer request
|
|
pj_bool_t cont;
|
|
CString number = sipuri.user;
|
|
if (number.IsEmpty()) {
|
|
number = sipuri.domain;
|
|
}
|
|
else if (!accountSettings.accountId || sipuri.domain != accountSettings.account.domain) {
|
|
number.Append(_T("@") + sipuri.domain);
|
|
}
|
|
pj_str_t status_text = StrToPjStr(number);
|
|
on_call_transfer_status(call_id,
|
|
0,
|
|
&status_text,
|
|
PJ_FALSE,
|
|
&cont);
|
|
//--
|
|
if (!code) {
|
|
// if our function call
|
|
return;
|
|
}
|
|
// deny transfer if we already have a call with same dest address
|
|
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_curr;
|
|
if (pjsua_call_get_info(call_ids[i], &call_info_curr) == PJ_SUCCESS) {
|
|
SIPURI sipuri_curr;
|
|
ParseSIPURI(PjToStr(&call_info_curr.remote_info, TRUE), &sipuri_curr);
|
|
if (sipuri.user + _T("@") + sipuri.domain == sipuri_curr.user + _T("@") + sipuri_curr.domain
|
|
) {
|
|
*code = PJSIP_SC_DECLINE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void on_call_replace_request2(pjsua_call_id call_id, pjsip_rx_data *rdata, int *st_code, pj_str_t *st_text, pjsua_call_setting *opt)
|
|
{
|
|
pjsua_call_info call_info;
|
|
if (pjsua_call_get_info(call_id, &call_info) == PJ_SUCCESS) {
|
|
if (!call_info.rem_vid_cnt) {
|
|
opt->vid_cnt = 0;
|
|
}
|
|
}
|
|
else {
|
|
opt->vid_cnt = 0;
|
|
}
|
|
}
|
|
|
|
static void on_call_replaced(pjsua_call_id old_call_id, pjsua_call_id new_call_id)
|
|
{
|
|
pjsua_call_info call_info;
|
|
if (pjsua_call_get_info(new_call_id, &call_info) == PJ_SUCCESS) {
|
|
on_call_transfer_request2(old_call_id, &call_info.remote_info, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
static void on_mwi_info(pjsua_acc_id acc_id, pjsua_mwi_info *mwi_info)
|
|
{
|
|
if (mwi_info->rdata->msg_info.ctype) {
|
|
const pjsip_ctype_hdr *ctype = mwi_info->rdata->msg_info.ctype;
|
|
if (pj_strcmp2(&ctype->media.type, "application") != 0 || pj_strcmp2(&ctype->media.subtype, "simple-message-summary") != 0) {
|
|
return;
|
|
}
|
|
}
|
|
if (!mwi_info->rdata->msg_info.msg->body || !mwi_info->rdata->msg_info.msg->body->len) {
|
|
return;
|
|
}
|
|
pjsip_msg_body *body = mwi_info->rdata->msg_info.msg->body;
|
|
pj_scanner scanner;
|
|
|
|
pj_scan_init(&scanner, (char*)body->data, body->len, PJ_SCAN_AUTOSKIP_WS, 0);
|
|
bool hasMail = false;
|
|
while (!pj_scan_is_eof(&scanner)) {
|
|
pj_str_t key;
|
|
pj_scan_get_until_chr(&scanner, ":", &key);
|
|
pj_strtrim(&key);
|
|
if (key.slen && !pj_scan_is_eof(&scanner)) {
|
|
scanner.curptr++;
|
|
pj_str_t value;
|
|
pj_scan_get_until_chr(&scanner, "\r\n", &value);
|
|
pj_strtrim(&value);
|
|
if (pj_stricmp2(&key, "Messages-Waiting") == 0) {
|
|
hasMail = pj_stricmp2(&value, "yes") == 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pj_scan_fini(&scanner);
|
|
PostMessage(mainDlg->m_hWnd, UM_ON_MWI_INFO, (WPARAM)hasMail, 0);
|
|
}
|
|
|
|
LRESULT CmainDlg::onMWIInfo(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
bool hasMail = (bool)wParam;
|
|
pageDialer->UpdateVoicemailButton(hasMail);
|
|
return 0;
|
|
}
|
|
|
|
static void on_dtmf_digit(pjsua_call_id call_id, int digit)
|
|
{
|
|
char signal[2];
|
|
signal[0] = digit;
|
|
signal[1] = 0;
|
|
call_play_digit(-1, signal);
|
|
}
|
|
|
|
static void on_call_tsx_state(pjsua_call_id call_id, pjsip_transaction *tsx, pjsip_event *e)
|
|
{
|
|
const pjsip_method info_method = {
|
|
PJSIP_OTHER_METHOD,
|
|
{ "INFO", 4 }
|
|
};
|
|
if (pjsip_method_cmp(&tsx->method, &info_method) == 0) {
|
|
/*
|
|
* Handle INFO method.
|
|
*/
|
|
if (tsx->role == PJSIP_ROLE_UAS && tsx->state == PJSIP_TSX_STATE_TRYING) {
|
|
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
|
|
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
|
|
pjsip_msg_body *body = rdata->msg_info.msg->body;
|
|
int code = 0;
|
|
if (body && body->len
|
|
&& pj_strcmp2(&body->content_type.type, "application") == 0
|
|
&& pj_strcmp2(&body->content_type.subtype, "dtmf-relay") == 0) {
|
|
code = 400;
|
|
pj_scanner scanner;
|
|
pj_scan_init(&scanner, (char*)body->data, body->len, PJ_SCAN_AUTOSKIP_WS, 0);
|
|
char digit;
|
|
int duration = 250;
|
|
while (!pj_scan_is_eof(&scanner)) {
|
|
pj_str_t key;
|
|
pj_scan_get_until_chr(&scanner, "=", &key);
|
|
pj_strtrim(&key);
|
|
if (key.slen && !pj_scan_is_eof(&scanner)) {
|
|
scanner.curptr++;
|
|
pj_str_t value;
|
|
pj_scan_get_until_chr(&scanner, "\r\n", &value);
|
|
pj_strtrim(&value);
|
|
if (pj_stricmp2(&key, "Signal") == 0) {
|
|
if (value.slen == 1) {
|
|
digit = *value.ptr;
|
|
code = 200;
|
|
}
|
|
}
|
|
else if (pj_stricmp2(&key, "Duration") == 0) {
|
|
int res = 0;
|
|
for (int i = 0; i < (unsigned)value.slen; ++i) {
|
|
res = res * 10 + (value.ptr[i] - '0');
|
|
res = res;
|
|
}
|
|
if (res >= 100 || res <= 5000) {
|
|
duration = res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pj_scan_fini(&scanner);
|
|
if (code == 200) {
|
|
on_dtmf_digit(-1, digit);
|
|
}
|
|
}
|
|
else if (!body || !body->len) {
|
|
/* 200/OK */
|
|
code = 200;
|
|
}
|
|
if (code) {
|
|
/* Answer incoming INFO */
|
|
pjsip_tx_data *tdata;
|
|
if (pjsip_endpt_create_response(tsx->endpt, rdata,
|
|
code, NULL, &tdata) == PJ_SUCCESS
|
|
) {
|
|
pjsip_tsx_send_msg(tsx, tdata);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
|
|
// display declined REFER status
|
|
const pjsip_method refer_method = {
|
|
PJSIP_OTHER_METHOD,
|
|
{ "REFER", 5 }
|
|
};
|
|
if (pjsip_method_cmp(&tsx->method, &refer_method) == 0 && tsx->status_code / 100 != 2) {
|
|
pj_bool_t cont;
|
|
on_call_transfer_status(call_id,
|
|
tsx->status_code,
|
|
&tsx->status_text,
|
|
PJ_FALSE,
|
|
&cont);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CmainDlg::~CmainDlg(void)
|
|
{
|
|
}
|
|
|
|
void CmainDlg::OnDestroy()
|
|
{
|
|
if (mmNotificationClient) {
|
|
delete mmNotificationClient;
|
|
}
|
|
WTSUnRegisterSessionNotification(m_hWnd);
|
|
|
|
PJDestroy();
|
|
|
|
accountSettings.SettingsSave();
|
|
|
|
RemoveJumpList();
|
|
if (tnd.hWnd) {
|
|
Shell_NotifyIcon(NIM_DELETE, &tnd);
|
|
}
|
|
UnloadLangPackModule();
|
|
|
|
CBaseDialog::OnDestroy();
|
|
}
|
|
|
|
void CmainDlg::PostNcDestroy()
|
|
{
|
|
CBaseDialog::PostNcDestroy();
|
|
delete this;
|
|
}
|
|
|
|
void CmainDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CBaseDialog::DoDataExchange(pDX);
|
|
// DDX_Control(pDX, IDD_MAIN, *mainDlg);
|
|
DDX_Control(pDX, IDC_MAIN_MENU, m_ButtonMenu);
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CmainDlg, CBaseDialog)
|
|
ON_WM_CREATE()
|
|
ON_WM_SYSCOMMAND()
|
|
ON_WM_QUERYENDSESSION()
|
|
ON_WM_TIMER()
|
|
ON_WM_MOVE()
|
|
ON_WM_SIZE()
|
|
ON_WM_CLOSE()
|
|
ON_WM_CONTEXTMENU()
|
|
ON_WM_DEVICECHANGE()
|
|
ON_WM_WTSSESSION_CHANGE()
|
|
ON_WM_DESTROY()
|
|
ON_BN_CLICKED(IDOK, OnBnClickedOk)
|
|
ON_BN_CLICKED(IDC_MAIN_MENU, OnBnClickedMenu)
|
|
ON_MESSAGE(UM_UPDATEWINDOWTEXT, OnUpdateWindowText)
|
|
ON_MESSAGE(UM_NOTIFYICON, onTrayNotify)
|
|
ON_MESSAGE(UM_CREATE_RINGING, onCreateRingingDlg)
|
|
ON_MESSAGE(UM_REFRESH_LEVELS, onRefreshLevels)
|
|
ON_MESSAGE(UM_ON_REG_STATE2, onRegState2)
|
|
ON_MESSAGE(UM_ON_CALL_STATE, onCallState)
|
|
ON_MESSAGE(UM_ON_MWI_INFO, onMWIInfo)
|
|
ON_MESSAGE(UM_ON_CALL_MEDIA_STATE, onCallMediaState)
|
|
ON_MESSAGE(UM_ON_CALL_TRANSFER_STATUS, onCallTransferStatus)
|
|
ON_MESSAGE(UM_ON_PLAYER_PLAY, onPlayerPlay)
|
|
ON_MESSAGE(UM_ON_PLAYER_STOP, onPlayerStop)
|
|
ON_MESSAGE(UM_ON_PAGER, onPager)
|
|
ON_MESSAGE(UM_ON_PAGER_STATUS, onPagerStatus)
|
|
ON_MESSAGE(UM_ON_BUDDY_STATE, onBuddyState)
|
|
ON_MESSAGE(UM_USERS_DIRECTORY, onUsersDirectoryLoaded)
|
|
ON_MESSAGE(WM_POWERBROADCAST, onPowerBroadcast)
|
|
ON_MESSAGE(WM_COPYDATA, onCopyData)
|
|
ON_MESSAGE(UM_CALL_ANSWER, onCallAnswer)
|
|
ON_MESSAGE(UM_CALL_HANGUP, onCallHangup)
|
|
ON_MESSAGE(UM_TAB_ICON_UPDATE, onTabIconUpdate)
|
|
ON_MESSAGE(UM_SET_PANE_TEXT, onSetPaneText)
|
|
ON_MESSAGE(UM_ON_ACCOUNT, OnAccount)
|
|
ON_COMMAND(ID_ACCOUNT_ADD, OnMenuAccountAdd)
|
|
ON_COMMAND_RANGE(ID_ACCOUNT_CHANGE_RANGE, ID_ACCOUNT_CHANGE_RANGE + 99, OnMenuAccountChange)
|
|
ON_COMMAND_RANGE(ID_ACCOUNT_EDIT_RANGE, ID_ACCOUNT_EDIT_RANGE + 99, OnMenuAccountEdit)
|
|
ON_COMMAND_RANGE(ID_CUSTOM_RANGE, ID_CUSTOM_RANGE + 99, OnMenuCustomRange)
|
|
ON_COMMAND(ID_SETTINGS, OnMenuSettings)
|
|
ON_COMMAND(ID_SHORTCUTS, OnMenuShortcuts)
|
|
ON_COMMAND(ID_ALWAYS_ON_TOP, OnMenuAlwaysOnTop)
|
|
ON_COMMAND(ID_LOG, OnMenuLog)
|
|
ON_COMMAND(ID_EXIT, OnMenuExit)
|
|
ON_NOTIFY(TCN_SELCHANGE, IDC_MAIN_TAB, &CmainDlg::OnTcnSelchangeTab)
|
|
ON_NOTIFY(TCN_SELCHANGING, IDC_MAIN_TAB, &CmainDlg::OnTcnSelchangingTab)
|
|
ON_COMMAND(ID_MENU_WEBSITE, OnMenuWebsite)
|
|
ON_COMMAND(ID_MENU_HELP, OnMenuHelp)
|
|
ON_COMMAND(ID_MENU_ADDL, OnMenuAddl)
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
BOOL CmainDlg::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (accountSettings.enableMediaButtons) {
|
|
if (pMsg->message == WM_SHELLHOOKMESSAGE) {
|
|
onShellHookMessage(pMsg->wParam, pMsg->lParam);
|
|
}
|
|
}
|
|
return CBaseDialog::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
// CmainDlg message handlers
|
|
|
|
void CmainDlg::OnBnClickedOk()
|
|
{
|
|
}
|
|
|
|
void CmainDlg::OnBnClickedMenu()
|
|
{
|
|
m_ButtonMenu.ModifyStyle(BS_DEFPUSHBUTTON, BS_PUSHBUTTON);
|
|
MainPopupMenu();
|
|
TabFocusSet();
|
|
}
|
|
|
|
CmainDlg::CmainDlg(CWnd* pParent /*=NULL*/)
|
|
: CBaseDialog(CmainDlg::IDD, pParent)
|
|
{
|
|
#ifdef _DEBUG
|
|
if (AllocConsole()) {
|
|
HANDLE console = NULL;
|
|
console = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
freopen("CONOUT$", "wt", stdout);
|
|
}
|
|
#endif
|
|
|
|
this->m_hWnd = NULL;
|
|
mmNotificationClient = NULL;
|
|
|
|
mainDlg = this;
|
|
widthAdd = 0;
|
|
heightAdd = 0;
|
|
|
|
m_tabPrev = -1;
|
|
newMessages = false;
|
|
missed = false;
|
|
|
|
CString audioCodecsCaptions = _T("opus/48000/2;Opus 24 kHz;\
|
|
PCMA/8000/1;G.711 A-law;\
|
|
PCMU/8000/1;G.711 u-law;\
|
|
G722/16000/1;G.722 16 kHz;\
|
|
G723/8000/1;G.723 8 kHz;\
|
|
G729/8000/1;G.729 8 kHz;\
|
|
GSM/8000/1;GSM 8 kHz;\
|
|
GSM-EFR/8000/1;GSM-EFR 8 kHz;\
|
|
AMR/8000/1;AMR 8 kHz;\
|
|
AMR-WB/16000/1;AMR-WB 16 kHz;\
|
|
iLBC/8000/1;iLBC 8 kHz;\
|
|
speex/32000/1;Speex 32 kHz;\
|
|
speex/16000/1;Speex 16 kHz;\
|
|
speex/8000/1;Speex 8 kHz;\
|
|
SILK/24000/1;SILK 24 kHz;\
|
|
SILK/16000/1;SILK 16 kHz;\
|
|
SILK/12000/1;SILK 12 kHz;\
|
|
SILK/8000/1;SILK 8 kHz;\
|
|
L16/44100/1;LPCM 44 kHz;\
|
|
L16/44100/2;LPCM 44 kHz Stereo");
|
|
int pos = 0;
|
|
CString resToken = audioCodecsCaptions.Tokenize(_T(";"), pos);
|
|
while (!resToken.IsEmpty()) {
|
|
audioCodecList.AddTail(resToken);
|
|
resToken = audioCodecsCaptions.Tokenize(_T(";"), pos);
|
|
}
|
|
|
|
wchar_t szBuf[STR_SZ];
|
|
wchar_t szLocale[STR_SZ];
|
|
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, szBuf, STR_SZ);
|
|
_tcscpy(szLocale, szBuf);
|
|
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGCOUNTRY, szBuf, STR_SZ);
|
|
if (_tcsclen(szBuf) != 0) {
|
|
_tcscat(szLocale, _T("_"));
|
|
_tcscat(szLocale, szBuf);
|
|
}
|
|
::GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, szBuf, STR_SZ);
|
|
if (_tcsclen(szBuf) != 0) {
|
|
_tcscat(szLocale, _T("."));
|
|
_tcscat(szLocale, szBuf);
|
|
}
|
|
_tsetlocale(LC_ALL, szLocale); // e.g. szLocale = "English_United States.1252"
|
|
|
|
LoadLangPackModule();
|
|
|
|
Create(IDD, pParent);
|
|
}
|
|
|
|
int CmainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
|
|
ShortcutsLoad();
|
|
shortcutsEnabled = accountSettings.enableShortcuts;
|
|
shortcutsBottom = accountSettings.shortcutsBottom;
|
|
if (accountSettings.enableShortcuts) {
|
|
if (shortcutsBottom) {
|
|
heightAdd += 10 + shortcuts.GetCount() * 25;
|
|
}
|
|
else {
|
|
widthAdd += 140;
|
|
}
|
|
}
|
|
int heightFix = 0;
|
|
if (widthAdd || heightAdd || heightFix) {
|
|
SetWindowPos(NULL, 0, 0, lpCreateStruct->cx + widthAdd, lpCreateStruct->cy + heightAdd + heightFix, SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
if (accountSettings.noResize) {
|
|
ModifyStyle(WS_MAXIMIZEBOX | WS_THICKFRAME, WS_BORDER);
|
|
}
|
|
|
|
if (langPack.rtl) {
|
|
ModifyStyleEx(0, WS_EX_LAYOUTRTL);
|
|
}
|
|
|
|
return CBaseDialog::OnCreate(lpCreateStruct);
|
|
}
|
|
|
|
BOOL CmainDlg::OnInitDialog()
|
|
{
|
|
CBaseDialog::OnInitDialog();
|
|
|
|
if (lstrcmp(theApp.m_lpCmdLine, _T("/hidden")) == 0) {
|
|
accountSettings.hidden = TRUE;
|
|
theApp.m_lpCmdLine = NULL;
|
|
}
|
|
|
|
WTSRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION);
|
|
mmNotificationClient = new CMMNotificationClient();
|
|
|
|
pj_ready = false;
|
|
|
|
autoAnswerCallId = PJSUA_INVALID_ID;
|
|
|
|
settingsDlg = NULL;
|
|
shortcutsDlg = NULL;
|
|
messagesDlg = new MessagesDlg(this);
|
|
transferDlg = NULL;
|
|
accountDlg = NULL;
|
|
|
|
m_lastInputTime = 0;
|
|
m_idleCounter = 0;
|
|
m_PresenceStatus = PJRPID_ACTIVITY_UNKNOWN;
|
|
|
|
#ifdef _GLOBAL_VIDEO
|
|
previewWin = NULL;
|
|
#endif
|
|
|
|
if (!accountSettings.hidden) {
|
|
|
|
SetupJumpList();
|
|
|
|
m_hIcon = theApp.LoadIcon(IDR_MAINFRAME);
|
|
iconSmall = (HICON)LoadImage(
|
|
AfxGetInstanceHandle(),
|
|
MAKEINTRESOURCE(IDR_MAINFRAME),
|
|
IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
|
|
PostMessage(WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
|
|
|
|
TranslateDialog(this->m_hWnd);
|
|
|
|
// Set the icon for this dialog. The framework does this automatically
|
|
// when the application's main window is not a dialog
|
|
SetIcon(m_hIcon, TRUE); // Set big icon
|
|
SetIcon(m_hIcon, FALSE); // Set small icon
|
|
|
|
// TODO: Add extra initialization here
|
|
|
|
// add tray icon
|
|
CString str;
|
|
str.Format(_T("%s %s"), _T(_GLOBAL_NAME_NICE), _T(_GLOBAL_VERSION));
|
|
tnd.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnd.hWnd = this->GetSafeHwnd();
|
|
tnd.uID = IDR_MAINFRAME;
|
|
tnd.uCallbackMessage = UM_NOTIFYICON;
|
|
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
|
|
iconMissed = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MISSED));
|
|
iconInactive = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_INACTIVE));
|
|
tnd.hIcon = iconInactive;
|
|
lstrcpyn(tnd.szTip, (LPCTSTR)str, sizeof(tnd.szTip));
|
|
DWORD dwMessage = NIM_ADD;
|
|
Shell_NotifyIcon(dwMessage, &tnd);
|
|
}
|
|
else {
|
|
tnd.hWnd = NULL;
|
|
}
|
|
|
|
m_bar.Create(this);
|
|
m_bar.SetIndicators(indicators, sizeof(indicators) / sizeof(indicators[0]));
|
|
m_bar.SetPaneInfo(0, IDS_STATUSBAR, SBPS_STRETCH, 0);
|
|
m_bar.SetPaneInfo(1, IDS_STATUSBAR2, SBPS_NOBORDERS, 0);
|
|
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDS_STATUSBAR);
|
|
|
|
AutoMove(m_bar.m_hWnd, 0, 100, 100, 0);
|
|
|
|
//--set window pos
|
|
CRect screenRect;
|
|
GetScreenRect(&screenRect);
|
|
CRect rect;
|
|
GetWindowRect(&rect);
|
|
|
|
windowSize.x = rect.Width();
|
|
windowSize.y = rect.Height();
|
|
|
|
int mx;
|
|
int my;
|
|
int mW = accountSettings.mainW > 0 ? accountSettings.mainW : rect.Width();
|
|
int mH = accountSettings.mainH > 0 ? accountSettings.mainH : rect.Height();
|
|
// coors not specified, first run
|
|
if (!accountSettings.mainX && !accountSettings.mainY) {
|
|
CRect primaryScreenRect;
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &primaryScreenRect, 0);
|
|
mx = primaryScreenRect.Width() - mW - widthAdd;
|
|
my = primaryScreenRect.Height() - mH;
|
|
}
|
|
else {
|
|
int maxLeft = screenRect.right - mW;
|
|
if (accountSettings.mainX > maxLeft) {
|
|
mx = maxLeft;
|
|
}
|
|
else {
|
|
mx = accountSettings.mainX < screenRect.left ? screenRect.left : accountSettings.mainX;
|
|
}
|
|
int maxTop = screenRect.bottom - mH;
|
|
if (accountSettings.mainY > maxTop) {
|
|
my = maxTop;
|
|
}
|
|
else {
|
|
my = accountSettings.mainY < screenRect.top ? screenRect.top : accountSettings.mainY;
|
|
}
|
|
}
|
|
|
|
//--set messages window pos/size
|
|
messagesDlg->GetWindowRect(&rect);
|
|
int messagesX;
|
|
int messagesY;
|
|
int messagesW = accountSettings.messagesW > 0 ? accountSettings.messagesW : 550;
|
|
int messagesH = accountSettings.messagesH > 0 ? accountSettings.messagesH : mH;
|
|
// coors not specified, first run
|
|
if (!accountSettings.messagesX && !accountSettings.messagesY) {
|
|
accountSettings.messagesX = mx - messagesW;
|
|
accountSettings.messagesY = my;
|
|
}
|
|
int maxLeft = screenRect.right - messagesW;
|
|
if (accountSettings.messagesX > maxLeft) {
|
|
messagesX = maxLeft;
|
|
}
|
|
else {
|
|
messagesX = accountSettings.messagesX < screenRect.left ? screenRect.left : accountSettings.messagesX;
|
|
}
|
|
int maxTop = screenRect.bottom - messagesH;
|
|
if (accountSettings.messagesY > maxTop) {
|
|
messagesY = maxTop;
|
|
}
|
|
else {
|
|
messagesY = accountSettings.messagesY < screenRect.top ? screenRect.top : accountSettings.messagesY;
|
|
}
|
|
|
|
messagesDlg->SetWindowPos(NULL, messagesX, messagesY, messagesW, messagesH, SWP_NOZORDER);
|
|
|
|
SetWindowPos(accountSettings.alwaysOnTop ? &CWnd::wndTopMost : &CWnd::wndNoTopMost, mx, my, mW, mH, NULL);
|
|
|
|
CTabCtrl* tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
CRect tabRect;
|
|
tab->GetWindowRect(&tabRect);
|
|
ScreenToClient(&tabRect);
|
|
TC_ITEM tabItem;
|
|
CRect lineRect;
|
|
lineRect.bottom = 3;
|
|
MapDialogRect(&lineRect);
|
|
CSize size;
|
|
size.SetSize(0, tabRect.Height() - lineRect.bottom - 3);
|
|
tab->SetItemSize(size);
|
|
|
|
tabItem.mask = TCIF_TEXT | TCIF_PARAM;
|
|
|
|
m_ButtonMenu.SetIcon(LoadImageIcon(IDI_DROPDOWN));
|
|
|
|
if (widthAdd) {
|
|
CRect pageRect;
|
|
m_ButtonMenu.GetWindowRect(pageRect);
|
|
ScreenToClient(pageRect);
|
|
m_ButtonMenu.SetWindowPos(NULL, pageRect.left + widthAdd, pageRect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
//--
|
|
tabRect.right += widthAdd;
|
|
tab->SetWindowPos(NULL, 0, 0, tabRect.Width(), tabRect.Height(), SWP_NOZORDER | SWP_NOMOVE);
|
|
}
|
|
|
|
AutoMove(tab->m_hWnd, 0, 0, 100, 0);
|
|
AutoMove(m_ButtonMenu.m_hWnd, 100, 0, 0, 0);
|
|
|
|
BYTE offset = tabRect.bottom - 1;
|
|
|
|
pageDialer = new Dialer(this);
|
|
tabItem.pszText = Translate(_T("Phone"));
|
|
tabItem.iImage = 0;
|
|
tabItem.lParam = (LPARAM)pageDialer;
|
|
tab->InsertItem(99, &tabItem);
|
|
pageDialer->SetWindowPos(NULL, 0, offset, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
|
AutoMove(pageDialer->m_hWnd, 40, 40, 20, 20);
|
|
|
|
CRect pageRect;
|
|
pageCalls = new Calls(this);
|
|
pageCalls->OnCreated();
|
|
tabItem.pszText = Translate(_T("Logs"));
|
|
tabItem.iImage = 1;
|
|
tabItem.lParam = (LPARAM)pageCalls;
|
|
tab->InsertItem(99, &tabItem);
|
|
pageCalls->GetWindowRect(pageRect);
|
|
pageCalls->SetWindowPos(NULL, 0, offset, pageRect.Width() + widthAdd, pageRect.Height() + heightAdd, SWP_NOZORDER);
|
|
AutoMove(pageCalls->m_hWnd, 0, 0, 100, 100);
|
|
|
|
pageContacts = new Contacts(this);
|
|
pageContacts->OnCreated();
|
|
tabItem.pszText = Translate(_T("Contacts"));
|
|
tabItem.iImage = 2;
|
|
tabItem.lParam = (LPARAM)pageContacts;
|
|
tab->InsertItem(99, &tabItem);
|
|
pageContacts->GetWindowRect(pageRect);
|
|
pageContacts->SetWindowPos(NULL, 0, offset, pageRect.Width() + widthAdd, pageRect.Height() + heightAdd, SWP_NOZORDER);
|
|
AutoMove(pageContacts->m_hWnd, 0, 0, 100, 100);
|
|
|
|
|
|
tab->SetCurSel(accountSettings.activeTab);
|
|
|
|
BOOL minimized = !lstrcmp(theApp.m_lpCmdLine, _T("/minimized"));
|
|
if (minimized) {
|
|
theApp.m_lpCmdLine = _T("");
|
|
}
|
|
if (accountSettings.silent) {
|
|
minimized = true;
|
|
}
|
|
|
|
m_startMinimized = (!firstRun && minimized) || accountSettings.hidden;
|
|
|
|
SetWindowText(_T(_GLOBAL_NAME_NICE));
|
|
UpdateWindowText();
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
}
|
|
|
|
void CmainDlg::OnCreated()
|
|
{
|
|
SetPaneText2();
|
|
if (!m_startMinimized) {
|
|
ShowWindow(SW_SHOW);
|
|
}
|
|
TabFocusSet();
|
|
|
|
//-- PJSIP create
|
|
while (!pj_ready) {
|
|
PJCreate();
|
|
if (pj_ready) {
|
|
break;
|
|
}
|
|
if (AfxMessageBox(_T("Unable to initialize network sockets."), MB_RETRYCANCEL | MB_ICONEXCLAMATION) != IDRETRY) {
|
|
DestroyWindow();
|
|
return;
|
|
}
|
|
}
|
|
if (lstrlen(theApp.m_lpCmdLine)) {
|
|
CommandLine(theApp.m_lpCmdLine);
|
|
theApp.m_lpCmdLine = NULL;
|
|
}
|
|
PJAccountAdd();
|
|
//--
|
|
WM_SHELLHOOKMESSAGE = RegisterWindowMessage(_T("SHELLHOOK"));
|
|
if (WM_SHELLHOOKMESSAGE) {
|
|
RegisterShellHookWindow(m_hWnd);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::BaloonPopup(CString title, CString message, DWORD flags)
|
|
{
|
|
if (tnd.hWnd) {
|
|
lstrcpyn(tnd.szInfo, message, sizeof(tnd.szInfo));
|
|
lstrcpyn(tnd.szInfoTitle, title, sizeof(tnd.szInfoTitle));
|
|
tnd.uFlags = tnd.uFlags | NIF_INFO;
|
|
tnd.dwInfoFlags = flags;
|
|
DWORD dwMessage = NIM_MODIFY;
|
|
Shell_NotifyIcon(dwMessage, &tnd);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnMenuAccountAdd()
|
|
{
|
|
if (!accountSettings.hidden) {
|
|
if (!accountDlg) {
|
|
accountDlg = new AccountDlg(this);
|
|
}
|
|
else {
|
|
accountDlg->SetForegroundWindow();
|
|
}
|
|
accountDlg->Load(0);
|
|
}
|
|
}
|
|
void CmainDlg::OnMenuAccountChange(UINT nID)
|
|
{
|
|
if (accountSettings.accountId) {
|
|
PJAccountDelete(true);
|
|
}
|
|
int idNew = nID - ID_ACCOUNT_CHANGE_RANGE + 1;
|
|
if (accountSettings.accountId != idNew) {
|
|
accountSettings.accountId = idNew;
|
|
accountSettings.AccountLoad(accountSettings.accountId, &accountSettings.account);
|
|
}
|
|
else {
|
|
accountSettings.accountId = 0;
|
|
}
|
|
accountSettings.SettingsSave();
|
|
mainDlg->PJAccountAdd();
|
|
}
|
|
|
|
void CmainDlg::OnMenuAccountEdit(UINT nID)
|
|
{
|
|
if (!accountDlg) {
|
|
accountDlg = new AccountDlg(this);
|
|
}
|
|
else {
|
|
accountDlg->SetForegroundWindow();
|
|
}
|
|
int id = accountSettings.accountId > 0 ? accountSettings.accountId : nID - ID_ACCOUNT_EDIT_RANGE + 1;
|
|
accountDlg->Load(id);
|
|
}
|
|
|
|
void CmainDlg::OnMenuCustomRange(UINT nID)
|
|
{
|
|
}
|
|
|
|
void CmainDlg::OnMenuSettings()
|
|
{
|
|
if (!accountSettings.hidden) {
|
|
if (!settingsDlg)
|
|
{
|
|
settingsDlg = new SettingsDlg(this);
|
|
}
|
|
else {
|
|
settingsDlg->SetForegroundWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnMenuShortcuts()
|
|
{
|
|
if (!shortcutsDlg)
|
|
{
|
|
shortcutsDlg = new ShortcutsDlg(this);
|
|
}
|
|
else {
|
|
shortcutsDlg->SetForegroundWindow();
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnMenuAlwaysOnTop()
|
|
{
|
|
accountSettings.alwaysOnTop = 1 - accountSettings.alwaysOnTop;
|
|
AccountSettingsPendingSave();
|
|
SetWindowPos(accountSettings.alwaysOnTop ? &this->wndTopMost : &this->wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
|
|
void CmainDlg::OnMenuLog()
|
|
{
|
|
ShellExecute(NULL, NULL, accountSettings.logFile, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
|
|
void CmainDlg::OnMenuExit()
|
|
{
|
|
this->DestroyWindow();
|
|
}
|
|
|
|
LRESULT CmainDlg::onTrayNotify(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT uMsg = (UINT)lParam;
|
|
switch (uMsg)
|
|
{
|
|
case NIN_BALLOONUSERCLICK:
|
|
onTrayNotify(NULL, WM_LBUTTONUP);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
if (this->IsWindowVisible() && !IsIconic())
|
|
{
|
|
if (wParam) {
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
else {
|
|
SetForegroundWindow();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool blockRestore = false;
|
|
if (accountSettings.hidden) {
|
|
blockRestore = true;
|
|
}
|
|
if (!blockRestore) {
|
|
if (IsIconic()) {
|
|
ShowWindow(SW_RESTORE);
|
|
}
|
|
else {
|
|
ShowWindow(SW_SHOW);
|
|
}
|
|
SetForegroundWindow();
|
|
if (missed) {
|
|
GotoTabLParam((LPARAM)pageCalls);
|
|
missed = false;
|
|
UpdateWindowText();
|
|
}
|
|
// -- show ringing dialogs
|
|
int count = ringinDlgs.GetCount();
|
|
for (int i = 0; i < count; i++) {
|
|
RinginDlg *ringinDlg = ringinDlgs.GetAt(i);
|
|
ringinDlg->ShowWindow(SW_SHOWNORMAL);
|
|
}
|
|
// -- show messages dialog
|
|
if (accountSettings.silent && ((!accountSettings.singleMode && call_get_count_noincoming()) || newMessages)) {
|
|
newMessages = false;
|
|
messagesDlg->ShowWindow(SW_SHOW);
|
|
}
|
|
//--
|
|
TabFocusSet();
|
|
}
|
|
}
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
MainPopupMenu();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CmainDlg::MainPopupMenu()
|
|
{
|
|
CString str;
|
|
CPoint point;
|
|
GetCursorPos(&point);
|
|
CMenu menu;
|
|
menu.CreatePopupMenu();
|
|
CMenu* tracker = &menu;
|
|
|
|
// -- add
|
|
tracker->AppendMenu(MF_STRING, ID_ACCOUNT_ADD, Translate(_T("Add Account...")));
|
|
//-- edit
|
|
CMenu editMenu;
|
|
editMenu.CreatePopupMenu();
|
|
Account acc;
|
|
int i = 0;
|
|
bool checked = false;
|
|
while (true) {
|
|
if (!accountSettings.AccountLoad(i + 1, &acc)) {
|
|
break;
|
|
}
|
|
|
|
if (!acc.label.IsEmpty()) {
|
|
str = acc.label;
|
|
}
|
|
else {
|
|
str.Format(_T("%s@%s"), acc.username, acc.domain);
|
|
}
|
|
tracker->InsertMenu(ID_ACCOUNT_ADD, (accountSettings.accountId == i + 1 ? MF_CHECKED : 0), ID_ACCOUNT_CHANGE_RANGE + i, str);
|
|
editMenu.AppendMenu(MF_STRING, ID_ACCOUNT_EDIT_RANGE + i, str);
|
|
if (!checked) {
|
|
checked = accountSettings.accountId == i + 1;
|
|
}
|
|
i++;
|
|
}
|
|
str = Translate(_T("Edit Account"));
|
|
str.Append(_T("\tCtrl+M"));
|
|
if (i == 1) {
|
|
MENUITEMINFO menuItemInfo;
|
|
menuItemInfo.cbSize = sizeof(MENUITEMINFO);
|
|
menuItemInfo.fMask = MIIM_STRING;
|
|
menuItemInfo.dwTypeData = Translate(_T("Make Active"));
|
|
tracker->SetMenuItemInfo(ID_ACCOUNT_CHANGE_RANGE, &menuItemInfo);
|
|
tracker->InsertMenu(ID_ACCOUNT_ADD, 0, ID_ACCOUNT_EDIT_RANGE, str);
|
|
}
|
|
else if (i > 1) {
|
|
tracker->InsertMenu(ID_ACCOUNT_ADD, MF_SEPARATOR);
|
|
if (checked) {
|
|
tracker->InsertMenu(ID_ACCOUNT_ADD, 0, ID_ACCOUNT_EDIT_RANGE, str);
|
|
}
|
|
else {
|
|
tracker->InsertMenu(ID_ACCOUNT_ADD, MF_POPUP, (UINT_PTR)editMenu.m_hMenu, Translate(_T("Edit Account")));
|
|
}
|
|
}
|
|
|
|
str = Translate(_T("Settings"));
|
|
str.Append(_T("\tCtrl+P"));
|
|
tracker->AppendMenu(MF_STRING, ID_SETTINGS, str);
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
str = Translate(_T("Shortcuts"));
|
|
str.Append(_T("\tCtrl+S"));
|
|
tracker->AppendMenu(MF_STRING, ID_SHORTCUTS, str);
|
|
|
|
bool separator = false;
|
|
if (!separator) {
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
separator = true;
|
|
}
|
|
tracker->AppendMenu(MF_STRING | (accountSettings.alwaysOnTop ? MF_CHECKED : 0), ID_ALWAYS_ON_TOP, Translate(_T("Always on Top")));
|
|
if (!separator) {
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
separator = true;
|
|
}
|
|
tracker->AppendMenu(MF_STRING | (!accountSettings.enableLog ? MF_DISABLED | MF_GRAYED : 0), ID_LOG, Translate(_T("View Log File")));
|
|
|
|
separator = false;
|
|
|
|
if (!separator) {
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
separator = true;
|
|
}
|
|
str = Translate(_T("Visit Website"));
|
|
str.Append(_T("\tCtrl+W"));
|
|
tracker->AppendMenu(MF_STRING, ID_MENU_WEBSITE, str);
|
|
|
|
if (!separator) {
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
separator = true;
|
|
}
|
|
tracker->AppendMenu(MF_STRING, ID_MENU_HELP, Translate(_T("Help")));
|
|
|
|
tracker->AppendMenu(MF_SEPARATOR);
|
|
str = Translate(_T("Exit"));
|
|
str.Append(_T("\tCtrl+Q"));
|
|
tracker->AppendMenu(MF_STRING, ID_EXIT, str);
|
|
|
|
SetForegroundWindow();
|
|
tracker->TrackPopupMenu(0, point.x, point.y, this);
|
|
PostMessage(WM_NULL, 0, 0);
|
|
}
|
|
|
|
LRESULT CmainDlg::onCreateRingingDlg(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
pjsua_call_id call_id = wParam;
|
|
pjsua_call_info call_info;
|
|
|
|
if (pjsua_var.state != PJSUA_STATE_RUNNING || pjsua_call_get_info(call_id, &call_info) != PJ_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
call_user_data *user_data = (call_user_data *)pjsua_call_get_user_data(call_info.id);
|
|
|
|
RinginDlg* ringinDlg = new RinginDlg(this);
|
|
|
|
ringinDlg->remoteHasVideo = call_info.rem_vid_cnt;
|
|
if (call_info.rem_vid_cnt) {
|
|
((CButton*)ringinDlg->GetDlgItem(IDC_VIDEO))->EnableWindow(TRUE);
|
|
}
|
|
|
|
ringinDlg->call_id = call_info.id;
|
|
SIPURI sipuri;
|
|
CStringW rab;
|
|
CString str;
|
|
CString info;
|
|
|
|
info = PjToStr(&call_info.remote_info, TRUE);
|
|
|
|
ParseSIPURI(info, &sipuri);
|
|
|
|
CString name = pageContacts->GetNameByNumber(GetSIPURI(sipuri.user, true));
|
|
if (name.IsEmpty()) {
|
|
name = !sipuri.name.IsEmpty() ? sipuri.name : (!sipuri.user.IsEmpty() ? sipuri.user : sipuri.domain);
|
|
}
|
|
if (user_data && !user_data->diversion.IsEmpty()) {
|
|
name.Format(_T("%s -> %s"), user_data->diversion, name);
|
|
}
|
|
ringinDlg->GetDlgItem(IDC_CALLER_NAME)->SetWindowText(name);
|
|
|
|
int c = 0;
|
|
int len = 0;
|
|
|
|
info = (!sipuri.user.IsEmpty() ? sipuri.user + _T("@") : _T("")) + sipuri.domain;
|
|
if (!sipuri.name.IsEmpty() && sipuri.name != name) {
|
|
info = sipuri.name + _T(" <") + info + _T(">");
|
|
}
|
|
len += info.GetLength();
|
|
str.Format(_T("%s\r\n\r\n"), info);
|
|
|
|
info = PjToStr(&call_info.local_info, TRUE);
|
|
ParseSIPURI(info, &sipuri);
|
|
info = (!sipuri.user.IsEmpty() ? sipuri.user + _T("@") : _T("")) + sipuri.domain;
|
|
len += info.GetLength();
|
|
str.AppendFormat(_T("%s: %s\r\n\r\n"), Translate(_T("To")), info);
|
|
|
|
if (len < 70) {
|
|
c++;
|
|
}
|
|
|
|
if (user_data && !user_data->userAgent.IsEmpty()) {
|
|
str.AppendFormat(_T("%s: %s"), Translate(_T("User-Agent")), user_data->userAgent);
|
|
}
|
|
else {
|
|
c++;
|
|
}
|
|
|
|
for (int i = 0; i < c; i++) {
|
|
str = _T("\r\n") + str;
|
|
}
|
|
|
|
|
|
if (str != name) {
|
|
ringinDlg->GetDlgItem(IDC_CALLER_ADDR)->SetWindowText(str);
|
|
}
|
|
else {
|
|
ringinDlg->GetDlgItem(IDC_CALLER_ADDR)->EnableWindow(FALSE);
|
|
}
|
|
ringinDlgs.Add(ringinDlg);
|
|
if (!accountSettings.bringToFrontOnIncoming) {
|
|
if (GetForegroundWindow()->GetTopLevelParent() != this) {
|
|
BaloonPopup(Translate(_T("Incoming Call")), name, NIIF_INFO);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onRefreshLevels(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
pageDialer->OnHScroll(0, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onPager(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CString *number = (CString *)wParam;
|
|
CString *message = (CString *)lParam;
|
|
bool doNotShowMessagesWindow = accountSettings.silent && !mainDlg->IsWindowVisible();
|
|
if (doNotShowMessagesWindow) {
|
|
newMessages = true;
|
|
}
|
|
MessagesContact* messagesContact = messagesDlg->AddTab(*number,
|
|
CString(), FALSE, NULL, NULL,
|
|
doNotShowMessagesWindow
|
|
);
|
|
if (messagesContact) {
|
|
messagesDlg->AddMessage(messagesContact, *message, MSIP_MESSAGE_TYPE_REMOTE);
|
|
onPlayerPlay(MSIP_SOUND_MESSAGE_IN, 0);
|
|
}
|
|
delete number;
|
|
delete message;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onPagerStatus(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CString *number = (CString *)wParam;
|
|
CString *message = (CString *)lParam;
|
|
bool doNotShowMessagesWindow = accountSettings.silent && !mainDlg->IsWindowVisible();
|
|
MessagesContact* messagesContact = mainDlg->messagesDlg->AddTab(*number,
|
|
CString(), FALSE, NULL, NULL,
|
|
doNotShowMessagesWindow);
|
|
if (messagesContact) {
|
|
mainDlg->messagesDlg->AddMessage(messagesContact, *message);
|
|
}
|
|
delete number;
|
|
delete message;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onPowerBroadcast(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (wParam == PBT_APMRESUMEAUTOMATIC) {
|
|
PJAccountAdd();
|
|
}
|
|
else if (wParam == PBT_APMSUSPEND) {
|
|
PJAccountDelete();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CmainDlg::OnAccount(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (!accountDlg) {
|
|
accountDlg = new AccountDlg(this);
|
|
}
|
|
else {
|
|
accountDlg->SetForegroundWindow();
|
|
}
|
|
accountDlg->Load(accountSettings.accountId);
|
|
if (wParam && accountDlg) {
|
|
CEdit *edit = (CEdit*)accountDlg->GetDlgItem(IDC_EDIT_PASSWORD);
|
|
if (edit) {
|
|
edit->SetFocus();
|
|
int nLength = edit->GetWindowTextLength();
|
|
edit->SetSel(nLength, nLength);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CmainDlg::OnTimerCall()
|
|
{
|
|
pjsua_call_id call_id;
|
|
int duration = messagesDlg->GetCallDuration(&call_id);
|
|
if (duration != -1) {
|
|
CString str;
|
|
str.Format(_T("%s %s"), Translate(_T("Connected")), GetDuration(duration, true));
|
|
call_user_data *user_data;
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING) {
|
|
user_data = (call_user_data *)pjsua_call_get_user_data(call_id);
|
|
}
|
|
else {
|
|
user_data = NULL;
|
|
}
|
|
unsigned icon = IDI_ACTIVE;
|
|
if (user_data) {
|
|
if (user_data->srtp == MSIP_SRTP) {
|
|
icon = IDI_ACTIVE_SECURE;
|
|
}
|
|
}
|
|
UpdateWindowText(str, icon);
|
|
}
|
|
else {
|
|
KillTimer(IDT_TIMER_CALL);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnTimerContactBlink()
|
|
{
|
|
CListCtrl *list = (CListCtrl*)pageContacts->GetDlgItem(IDC_CONTACTS);
|
|
int n = list->GetItemCount();
|
|
bool ringing = false;
|
|
for (int i = 0; i < n; i++) {
|
|
Contact *contact = (Contact *)list->GetItemData(i);
|
|
if (contact->ringing) {
|
|
list->SetItem(i, 0, LVIF_IMAGE, 0, timerContactBlinkState ? MSIP_CONTACT_ICON_BLANK : contact->image, 0, 0, 0);
|
|
ringing = true;
|
|
}
|
|
else {
|
|
list->SetItem(i, 0, LVIF_IMAGE, 0, contact->image, 0, 0, 0);
|
|
}
|
|
}
|
|
if (!ringing) {
|
|
KillTimer(IDT_TIMER_CONTACTS_BLINK);
|
|
timerContactBlinkState = false;
|
|
}
|
|
else {
|
|
timerContactBlinkState = !timerContactBlinkState;
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnTimer(UINT_PTR TimerVal)
|
|
{
|
|
if (TimerVal == IDT_TIMER_AUTOANSWER) {
|
|
KillTimer(IDT_TIMER_AUTOANSWER);
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING) {
|
|
AutoAnswer(autoAnswerCallId);
|
|
}
|
|
autoAnswerCallId = PJSUA_INVALID_ID;
|
|
}
|
|
else if (TimerVal == IDT_TIMER_SWITCH_DEVICES) {
|
|
KillTimer(IDT_TIMER_SWITCH_DEVICES);
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING) {
|
|
PJ_LOG(3, (THIS_FILE, "Execute refresh devices"));
|
|
bool snd_is_active = pjsua_snd_is_active();
|
|
bool is_ring;
|
|
if (snd_is_active) {
|
|
int in, out;
|
|
if (pjsua_get_snd_dev(&in, &out) == PJ_SUCCESS) {
|
|
is_ring = (out == msip_audio_ring);
|
|
}
|
|
else {
|
|
is_ring = false;
|
|
}
|
|
pjsua_set_null_snd_dev();
|
|
}
|
|
pjmedia_aud_dev_refresh();
|
|
UpdateSoundDevicesIds();
|
|
#ifdef _GLOBAL_VIDEO
|
|
pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
|
|
if (vid_subsys->init_count) {
|
|
pjmedia_vid_dev_refresh();
|
|
}
|
|
#endif
|
|
if (snd_is_active) {
|
|
msip_set_sound_device(is_ring ? msip_audio_ring : msip_audio_output, true);
|
|
}
|
|
}
|
|
}
|
|
else if (TimerVal == IDT_TIMER_SAVE) {
|
|
KillTimer(IDT_TIMER_SAVE);
|
|
accountSettings.SettingsSave();
|
|
}
|
|
else if (TimerVal == IDT_TIMER_DIRECTORY) {
|
|
UsersDirectoryLoad();
|
|
}
|
|
else if (TimerVal == IDT_TIMER_CONTACTS_BLINK) {
|
|
OnTimerContactBlink();
|
|
}
|
|
else if (TimerVal == IDT_TIMER_CALL) {
|
|
OnTimerCall();
|
|
}
|
|
else
|
|
if (TimerVal == IDT_TIMER_IDLE) {
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING && m_PresenceStatus != PJRPID_ACTIVITY_BUSY) {
|
|
//--
|
|
LASTINPUTINFO lii;
|
|
lii.cbSize = sizeof(LASTINPUTINFO);
|
|
if (GetLastInputInfo(&lii)) {
|
|
if (lii.dwTime != m_lastInputTime) {
|
|
m_lastInputTime = lii.dwTime;
|
|
m_idleCounter = 0;
|
|
if (m_PresenceStatus == PJRPID_ACTIVITY_AWAY) {
|
|
PublishStatus();
|
|
}
|
|
}
|
|
else {
|
|
m_idleCounter++;
|
|
if (m_idleCounter == 120) {
|
|
PublishStatus(false);
|
|
}
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
else
|
|
if (TimerVal = IDT_TIMER_TONE) {
|
|
onPlayerPlay(MSIP_SOUND_RINGOUT, 0);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::PJCreate()
|
|
{
|
|
player_id = PJSUA_INVALID_ID;
|
|
|
|
pageContacts->isSubscribed = FALSE;
|
|
|
|
// check updates
|
|
if (accountSettings.updatesInterval != _T("never"))
|
|
{
|
|
CTime t = CTime::GetCurrentTime();
|
|
time_t time = t.GetTime();
|
|
int days;
|
|
if (accountSettings.updatesInterval == _T("daily"))
|
|
{
|
|
days = 1;
|
|
}
|
|
else if (accountSettings.updatesInterval == _T("monthly"))
|
|
{
|
|
days = 30;
|
|
}
|
|
else if (accountSettings.updatesInterval == _T("quarterly"))
|
|
{
|
|
days = 90;
|
|
}
|
|
else
|
|
{
|
|
days = 7;
|
|
}
|
|
if (accountSettings.checkUpdatesTime + days * 86400 < time)
|
|
{
|
|
CheckUpdates();
|
|
accountSettings.checkUpdatesTime = time;
|
|
accountSettings.SettingsSave();
|
|
}
|
|
}
|
|
|
|
// pj create
|
|
pj_status_t status;
|
|
pjsua_config ua_cfg;
|
|
pjsua_media_config media_cfg;
|
|
pjsua_transport_config cfg;
|
|
|
|
// Must create pjsua before anything else!
|
|
status = pjsua_create();
|
|
if (status != PJ_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
// Initialize configs with default settings.
|
|
pjsua_config_default(&ua_cfg);
|
|
pjsua_media_config_default(&media_cfg);
|
|
|
|
CString userAgent;
|
|
if (accountSettings.userAgent.IsEmpty()) {
|
|
userAgent.Format(_T("%s/%s"), _T(_GLOBAL_NAME_NICE), _T(_GLOBAL_VERSION));
|
|
ua_cfg.user_agent = StrToPjStr(userAgent);
|
|
}
|
|
else {
|
|
ua_cfg.user_agent = StrToPjStr(accountSettings.userAgent);
|
|
}
|
|
|
|
ua_cfg.cb.on_reg_state2 = &on_reg_state2;
|
|
ua_cfg.cb.on_call_state = &on_call_state;
|
|
ua_cfg.cb.on_dtmf_digit = &on_dtmf_digit;
|
|
ua_cfg.cb.on_call_tsx_state = &on_call_tsx_state;
|
|
|
|
ua_cfg.cb.on_call_media_state = &on_call_media_state;
|
|
ua_cfg.cb.on_call_media_event = &on_call_media_event;
|
|
ua_cfg.cb.on_incoming_call = &on_incoming_call;
|
|
ua_cfg.cb.on_nat_detect = &on_nat_detect;
|
|
ua_cfg.cb.on_buddy_state = &on_buddy_state;
|
|
ua_cfg.cb.on_pager2 = &on_pager2;
|
|
ua_cfg.cb.on_pager_status2 = &on_pager_status2;
|
|
ua_cfg.cb.on_call_transfer_request2 = &on_call_transfer_request2;
|
|
ua_cfg.cb.on_call_transfer_status = &on_call_transfer_status;
|
|
|
|
ua_cfg.cb.on_call_replace_request2 = &on_call_replace_request2;
|
|
ua_cfg.cb.on_call_replaced = &on_call_replaced;
|
|
|
|
ua_cfg.cb.on_mwi_info = &on_mwi_info;
|
|
|
|
ua_cfg.srtp_secure_signaling = 0;
|
|
|
|
/*
|
|
TODO: accountSettings.account: public_addr
|
|
*/
|
|
|
|
if (accountSettings.enableSTUN && !accountSettings.stun.IsEmpty())
|
|
{
|
|
ua_cfg.stun_srv_cnt = 1;
|
|
ua_cfg.stun_srv[0] = StrToPjStr(accountSettings.stun);
|
|
}
|
|
|
|
media_cfg.enable_ice = PJ_FALSE;
|
|
media_cfg.no_vad = accountSettings.vad ? PJ_FALSE : PJ_TRUE;
|
|
media_cfg.ec_tail_len = accountSettings.ec ? PJSUA_DEFAULT_EC_TAIL_LEN : 0;
|
|
if (accountSettings.ec) {
|
|
#ifndef _DEBUG
|
|
media_cfg.clock_rate = 48000;
|
|
#else
|
|
media_cfg.clock_rate = 16000;
|
|
#endif
|
|
media_cfg.channel_count = 1;
|
|
}
|
|
else {
|
|
media_cfg.clock_rate = 44100;
|
|
media_cfg.channel_count = 2;
|
|
}
|
|
|
|
if (accountSettings.dnsSrv) {
|
|
ua_cfg.nameserver_count = 4;
|
|
ua_cfg.nameserver[0] = StrToPjStr(_T("8.8.8.8"));
|
|
ua_cfg.nameserver[1] = StrToPjStr(_T("8.8.4.4"));
|
|
ua_cfg.nameserver[2] = StrToPjStr(_T("2001:4860:4860::8888"));
|
|
ua_cfg.nameserver[3] = StrToPjStr(_T("2001:4860:4860::8844"));
|
|
}
|
|
|
|
// Initialize pjsua
|
|
if (accountSettings.enableLog) {
|
|
pjsua_logging_config log_cfg;
|
|
pjsua_logging_config_default(&log_cfg);
|
|
//--
|
|
CStringA buf;
|
|
int len = accountSettings.logFile.GetLength() + 1;
|
|
LPSTR pBuf = buf.GetBuffer(len);
|
|
WideCharToMultiByte(CP_ACP, 0, accountSettings.logFile.GetBuffer(), -1, pBuf, len, NULL, NULL);
|
|
log_cfg.log_filename = pj_str(pBuf);
|
|
log_cfg.decor |= PJ_LOG_HAS_CR;
|
|
accountSettings.logFile = pBuf;
|
|
buf.ReleaseBuffer();
|
|
//--
|
|
status = pjsua_init(&ua_cfg, &log_cfg, &media_cfg);
|
|
}
|
|
else {
|
|
status = pjsua_init(&ua_cfg, NULL, &media_cfg);
|
|
}
|
|
|
|
if (status != PJ_SUCCESS) {
|
|
pjsua_destroy();
|
|
return;
|
|
}
|
|
|
|
// Start pjsua
|
|
status = pjsua_start();
|
|
|
|
if (status != PJ_SUCCESS) {
|
|
pjsua_destroy();
|
|
return;
|
|
}
|
|
|
|
if (!accountSettings.rport) {
|
|
pjsip_cfg()->endpt.disable_rport = PJ_TRUE;
|
|
}
|
|
|
|
pj_ready = true;
|
|
|
|
// Set snd devices
|
|
UpdateSoundDevicesIds();
|
|
|
|
//Set aud codecs prio
|
|
PJ_LOG(3, (THIS_FILE, "Set audio codecs"));
|
|
if (accountSettings.audioCodecs.IsEmpty())
|
|
{
|
|
accountSettings.audioCodecs = _T(_GLOBAL_CODECS_ENABLED);
|
|
}
|
|
if (accountSettings.audioCodecs.GetLength())
|
|
{
|
|
// add unknown new codecs to the list
|
|
pjsua_codec_info codec_info[64];
|
|
unsigned count = 64;
|
|
if (pjsua_enum_codecs(codec_info, &count) == PJ_SUCCESS) {
|
|
for (unsigned i = 0; i < count; i++) {
|
|
pjsua_codec_set_priority(&codec_info[i].codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
|
|
CString rab = PjToStr(&codec_info[i].codec_id);
|
|
if (!audioCodecList.Find(rab)) {
|
|
audioCodecList.AddTail(rab);
|
|
rab.Append(_T("~"));
|
|
audioCodecList.AddTail(rab);
|
|
}
|
|
}
|
|
}
|
|
// remove unsupported codecs from list
|
|
POSITION pos = audioCodecList.GetHeadPosition();
|
|
while (pos) {
|
|
POSITION posKey = pos;
|
|
CString key = audioCodecList.GetNext(pos);
|
|
POSITION posValue = pos;
|
|
CString value = audioCodecList.GetNext(pos);
|
|
pj_str_t codec_id = StrToPjStr(key);
|
|
pjmedia_codec_param param;
|
|
if (pjsua_codec_get_param(&codec_id, ¶m) != PJ_SUCCESS) {
|
|
audioCodecList.RemoveAt(posKey);
|
|
audioCodecList.RemoveAt(posValue);
|
|
}
|
|
};
|
|
|
|
int curPos = 0;
|
|
int i = PJMEDIA_CODEC_PRIO_NORMAL;
|
|
CString resToken = accountSettings.audioCodecs.Tokenize(_T(" "), curPos);
|
|
while (!resToken.IsEmpty()) {
|
|
pj_str_t codec_id = StrToPjStr(resToken);
|
|
/*
|
|
if (pj_strcmp2(&codec_id,"opus/48000/2") == 0) {
|
|
pjmedia_codec_param param;
|
|
pjsua_codec_get_param(&codec_id, ¶m);
|
|
//param.info.clock_rate = 16000;
|
|
param.info.avg_bps = 16000;
|
|
param.info.max_bps = param.info.avg_bps * 2;
|
|
//param.setting.dec_fmtp.param[param.setting.dec_fmtp.cnt].name=pj_str("maxplaybackrate");
|
|
//param.setting.dec_fmtp.param[param.setting.dec_fmtp.cnt].val = pj_str("8000");
|
|
//param.setting.dec_fmtp.cnt++;
|
|
param.setting.dec_fmtp.param[param.setting.dec_fmtp.cnt].name=pj_str("sprop-maxcapturerate");
|
|
param.setting.dec_fmtp.param[param.setting.dec_fmtp.cnt].val = pj_str("8000");
|
|
param.setting.dec_fmtp.cnt++;
|
|
pjsua_codec_set_param(&codec_id, ¶m);
|
|
}
|
|
*/
|
|
pjsua_codec_set_priority(&codec_id, i);
|
|
resToken = accountSettings.audioCodecs.Tokenize(_T(" "), curPos);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
#ifdef _GLOBAL_VIDEO
|
|
//Set vid codecs prio
|
|
PJ_LOG(3, (THIS_FILE, "Set video codecs"));
|
|
if (accountSettings.videoCodec.GetLength())
|
|
{
|
|
pj_str_t codec_id = StrToPjStr(accountSettings.videoCodec);
|
|
pjsua_vid_codec_set_priority(&codec_id, 255);
|
|
}
|
|
int bitrate;
|
|
if (!accountSettings.videoH264) {
|
|
pjsua_vid_codec_set_priority(&pj_str("H264"), 0);
|
|
}
|
|
else
|
|
{
|
|
const pj_str_t codec_id = { "H264", 4 };
|
|
pjmedia_vid_codec_param param;
|
|
pjsua_vid_codec_get_param(&codec_id, ¶m);
|
|
if (accountSettings.videoBitrate) {
|
|
bitrate = 1000 * accountSettings.videoBitrate;
|
|
param.enc_fmt.det.vid.avg_bps = bitrate;
|
|
param.enc_fmt.det.vid.max_bps = bitrate;
|
|
}
|
|
/*
|
|
param.enc_fmt.det.vid.size.w = 140;
|
|
param.enc_fmt.det.vid.size.h = 80;
|
|
param.enc_fmt.det.vid.fps.num = 30;
|
|
param.enc_fmt.det.vid.fps.denum = 1;
|
|
param.dec_fmt.det.vid.size.w = 640;
|
|
param.dec_fmt.det.vid.size.h = 480;
|
|
param.dec_fmt.det.vid.fps.num = 30;
|
|
param.dec_fmt.det.vid.fps.denum = 1;
|
|
*/
|
|
/*
|
|
// Defaut (level 1e, 30):
|
|
param.dec_fmtp.cnt = 2;
|
|
param.dec_fmtp.param[0].name = pj_str("profile-level-id");
|
|
param.dec_fmtp.param[0].val = pj_str("42e01e");
|
|
param.dec_fmtp.param[1].name = pj_str("packetization-mode");
|
|
param.dec_fmtp.param[1].val = pj_str("1");
|
|
//*/
|
|
pjsua_vid_codec_set_param(&codec_id, ¶m);
|
|
}
|
|
if (!accountSettings.videoH263) {
|
|
pjsua_vid_codec_set_priority(&pj_str("H263"), 0);
|
|
}
|
|
else {
|
|
if (accountSettings.videoBitrate) {
|
|
bitrate = 1000 * accountSettings.videoBitrate;
|
|
const pj_str_t codec_id = { "H263", 4 };
|
|
pjmedia_vid_codec_param param;
|
|
pjsua_vid_codec_get_param(&codec_id, ¶m);
|
|
param.enc_fmt.det.vid.avg_bps = bitrate;
|
|
param.enc_fmt.det.vid.max_bps = bitrate;
|
|
pjsua_vid_codec_set_param(&codec_id, ¶m);
|
|
}
|
|
}
|
|
if (!accountSettings.videoVP8) {
|
|
pjsua_vid_codec_set_priority(&pj_str("VP8"), 0);
|
|
}
|
|
else {
|
|
if (accountSettings.videoBitrate) {
|
|
bitrate = 1000 * accountSettings.videoBitrate;
|
|
const pj_str_t codec_id = { "VP8", 4 };
|
|
pjmedia_vid_codec_param param;
|
|
pjsua_vid_codec_get_param(&codec_id, ¶m);
|
|
param.enc_fmt.det.vid.avg_bps = bitrate;
|
|
param.enc_fmt.det.vid.max_bps = bitrate;
|
|
pjsua_vid_codec_set_param(&codec_id, ¶m);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Create transport
|
|
PJ_LOG(3, (THIS_FILE, "Create transport"));
|
|
transport_udp_local = -1;
|
|
transport_udp = -1;
|
|
transport_tcp = -1;
|
|
transport_tls = -1;
|
|
|
|
pjsua_transport_config_default(&cfg);
|
|
|
|
if (accountSettings.sourcePort) {
|
|
cfg.port = accountSettings.sourcePort;
|
|
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &transport_udp);
|
|
if (status != PJ_SUCCESS) {
|
|
cfg.port = 0;
|
|
pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &transport_udp);
|
|
}
|
|
if (MACRO_ENABLE_LOCAL_ACCOUNT) {
|
|
if (accountSettings.sourcePort == 5060) {
|
|
transport_udp_local = transport_udp;
|
|
}
|
|
else {
|
|
cfg.port = 5060;
|
|
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &transport_udp_local);
|
|
if (status != PJ_SUCCESS) {
|
|
transport_udp_local = transport_udp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (MACRO_ENABLE_LOCAL_ACCOUNT) {
|
|
cfg.port = 5060;
|
|
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &transport_udp_local);
|
|
if (status != PJ_SUCCESS) {
|
|
transport_udp_local = -1;
|
|
}
|
|
}
|
|
cfg.port = 0;
|
|
pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, &transport_udp);
|
|
if (transport_udp_local == -1) {
|
|
transport_udp_local = transport_udp;
|
|
}
|
|
}
|
|
|
|
cfg.port = MACRO_ENABLE_LOCAL_ACCOUNT ? 5060 : 0;
|
|
status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, &transport_tcp);
|
|
if (status != PJ_SUCCESS && cfg.port) {
|
|
cfg.port = 0;
|
|
pjsua_transport_create(PJSIP_TRANSPORT_TCP, &cfg, &transport_tcp);
|
|
}
|
|
|
|
cfg.port = MACRO_ENABLE_LOCAL_ACCOUNT ? 5061 : 0;
|
|
status = pjsua_transport_create(PJSIP_TRANSPORT_TLS, &cfg, &transport_tls);
|
|
if (status != PJ_SUCCESS && cfg.port) {
|
|
cfg.port = 0;
|
|
pjsua_transport_create(PJSIP_TRANSPORT_TLS, &cfg, &transport_tls);
|
|
}
|
|
|
|
if (accountSettings.usersDirectory.Find(_T("%s")) == -1 && accountSettings.usersDirectory.Find(_T("{")) == -1) {
|
|
UsersDirectoryLoad();
|
|
}
|
|
|
|
SetTimer(IDT_TIMER_IDLE, 5000, NULL);
|
|
|
|
account = PJSUA_INVALID_ID;
|
|
account_local = PJSUA_INVALID_ID;
|
|
|
|
PJAccountAddLocal();
|
|
|
|
}
|
|
|
|
void CmainDlg::UpdateSoundDevicesIds()
|
|
{
|
|
msip_audio_input = -1;
|
|
msip_audio_output = -2;
|
|
msip_audio_ring = -2;
|
|
|
|
unsigned count = 128;
|
|
pjmedia_aud_dev_info aud_dev_info[128];
|
|
pjsua_enum_aud_devs(aud_dev_info, &count);
|
|
for (unsigned i = 0; i < count; i++)
|
|
{
|
|
CString audDevName(aud_dev_info[i].name);
|
|
if (aud_dev_info[i].input_count && !accountSettings.audioInputDevice.Compare(audDevName)) {
|
|
msip_audio_input = i;
|
|
}
|
|
if (aud_dev_info[i].output_count) {
|
|
if (!accountSettings.audioOutputDevice.Compare(audDevName)) {
|
|
msip_audio_output = i;
|
|
}
|
|
if (!accountSettings.audioRingDevice.Compare(audDevName)) {
|
|
msip_audio_ring = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmainDlg::PJDestroy()
|
|
{
|
|
KillTimer(IDT_TIMER_IDLE);
|
|
KillTimer(IDT_TIMER_CALL);
|
|
|
|
if (pj_ready) {
|
|
if (pageContacts) {
|
|
pageContacts->PresenceUnsubsribe();
|
|
}
|
|
call_deinit_tonegen(-1);
|
|
|
|
toneCalls.RemoveAll();
|
|
|
|
if (IsWindow(m_hWnd)) {
|
|
KillTimer(IDT_TIMER_TONE);
|
|
}
|
|
|
|
PlayerStop();
|
|
|
|
if (accountSettings.accountId) {
|
|
PJAccountDelete();
|
|
}
|
|
|
|
pj_ready = false;
|
|
|
|
//if (transport_udp_local!=PJSUA_INVALID_ID && transport_udp_local!=transport_udp) {
|
|
// pjsua_transport_close(transport_udp_local,PJ_TRUE);
|
|
//}
|
|
if (transport_udp != PJSUA_INVALID_ID) {
|
|
//pjsua_transport_close(transport_udp,PJ_TRUE);
|
|
}
|
|
//if (transport_tcp!=PJSUA_INVALID_ID) {
|
|
// pjsua_transport_close(transport_tcp,PJ_TRUE);
|
|
//}
|
|
//if (transport_tls!=PJSUA_INVALID_ID) {
|
|
// pjsua_transport_close(transport_tls,PJ_TRUE);
|
|
//}
|
|
pjsua_destroy();
|
|
}
|
|
}
|
|
|
|
void CmainDlg::PJAccountConfig(pjsua_acc_config *acc_cfg)
|
|
{
|
|
pjsua_acc_config_default(acc_cfg);
|
|
#ifdef _GLOBAL_VIDEO
|
|
acc_cfg->vid_in_auto_show = PJ_TRUE;
|
|
acc_cfg->vid_out_auto_transmit = PJ_TRUE;
|
|
acc_cfg->vid_cap_dev = VideoCaptureDeviceId();
|
|
acc_cfg->vid_wnd_flags = PJMEDIA_VID_DEV_WND_BORDER | PJMEDIA_VID_DEV_WND_RESIZABLE;
|
|
#endif
|
|
|
|
if (accountSettings.rtpPortMin > 0) {
|
|
acc_cfg->rtp_cfg.port = accountSettings.rtpPortMin;
|
|
if (accountSettings.rtpPortMax > accountSettings.rtpPortMin) {
|
|
acc_cfg->rtp_cfg.port_range = accountSettings.rtpPortMax - accountSettings.rtpPortMin;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add account is not exists.
|
|
*/
|
|
void CmainDlg::PJAccountAdd()
|
|
{
|
|
if (pjsua_acc_is_valid(account)) {
|
|
return;
|
|
}
|
|
CString str;
|
|
|
|
if (!accountSettings.accountId) {
|
|
return;
|
|
}
|
|
if (accountSettings.account.username.IsEmpty()) {
|
|
if (!accountSettings.silent) {
|
|
OnAccount(0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
CString title = _T(_GLOBAL_NAME_NICE);
|
|
CString titleAdder;
|
|
CString usernameLocal;
|
|
usernameLocal = accountSettings.account.username;
|
|
if (!accountSettings.account.label.IsEmpty())
|
|
{
|
|
titleAdder = accountSettings.account.label;
|
|
}
|
|
else if (!accountSettings.account.displayName.IsEmpty())
|
|
{
|
|
titleAdder = accountSettings.account.displayName;
|
|
}
|
|
else if (!usernameLocal.IsEmpty())
|
|
{
|
|
titleAdder = usernameLocal;
|
|
}
|
|
if (!titleAdder.IsEmpty()) {
|
|
title.AppendFormat(_T(" - %s"), titleAdder);
|
|
}
|
|
SetPaneText2(titleAdder);
|
|
SetWindowText(title);
|
|
|
|
pjsua_acc_config acc_cfg;
|
|
PJAccountConfig(&acc_cfg);
|
|
|
|
if (accountSettings.account.disableSessionTimer) {
|
|
acc_cfg.use_timer = PJSUA_SIP_TIMER_INACTIVE;
|
|
}
|
|
|
|
if (accountSettings.account.srtp == _T("optional")) {
|
|
acc_cfg.use_srtp = PJMEDIA_SRTP_OPTIONAL;
|
|
}
|
|
else if (accountSettings.account.srtp == _T("mandatory")) {
|
|
acc_cfg.use_srtp = PJMEDIA_SRTP_MANDATORY;
|
|
}
|
|
else {
|
|
acc_cfg.use_srtp = PJMEDIA_SRTP_DISABLED;
|
|
}
|
|
if (!accountSettings.enableSTUN || accountSettings.stun.IsEmpty()) {
|
|
acc_cfg.rtp_cfg.public_addr = StrToPjStr(accountSettings.account.publicAddr);
|
|
}
|
|
acc_cfg.ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM;
|
|
acc_cfg.ice_cfg.enable_ice = accountSettings.account.ice ? PJ_TRUE : PJ_FALSE;
|
|
acc_cfg.allow_via_rewrite = accountSettings.account.allowRewrite ? PJ_TRUE : PJ_FALSE;
|
|
acc_cfg.allow_sdp_nat_rewrite = acc_cfg.allow_via_rewrite;
|
|
acc_cfg.allow_contact_rewrite = acc_cfg.allow_via_rewrite ? 2 : PJ_FALSE;
|
|
acc_cfg.publish_enabled = accountSettings.account.publish ? PJ_TRUE : PJ_FALSE;
|
|
|
|
if (!accountSettings.account.voicemailNumber.IsEmpty()) {
|
|
acc_cfg.mwi_enabled = PJ_TRUE;
|
|
}
|
|
|
|
transport = MSIP_TRANSPORT_AUTO;
|
|
if (accountSettings.account.transport == _T("udp") && transport_udp != -1) {
|
|
acc_cfg.transport_id = transport_udp;
|
|
}
|
|
else if (accountSettings.account.transport == _T("tcp") && transport_tcp != -1) {
|
|
transport = MSIP_TRANSPORT_TCP;
|
|
}
|
|
else if (accountSettings.account.transport == _T("tls") && transport_tls != -1) {
|
|
transport = MSIP_TRANSPORT_TLS;
|
|
}
|
|
|
|
str.Format(_T("%s..."), Translate(_T("Connecting")));
|
|
UpdateWindowText(str);
|
|
|
|
acc_cfg.cred_count = 1;
|
|
acc_cfg.cred_info[0].username = StrToPjStr(!accountSettings.account.authID.IsEmpty() ? accountSettings.account.authID : get_account_username());
|
|
acc_cfg.cred_info[0].realm = pj_str("*");
|
|
acc_cfg.cred_info[0].scheme = pj_str("Digest");
|
|
acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
|
|
acc_cfg.cred_info[0].data = StrToPjStr(get_account_password());
|
|
|
|
CString proxy;
|
|
if (!accountSettings.account.proxy.IsEmpty()) {
|
|
acc_cfg.proxy_cnt = 1;
|
|
proxy.Format(_T("sip:%s"), accountSettings.account.proxy);
|
|
AddTransportSuffix(proxy);
|
|
acc_cfg.proxy[0] = StrToPjStr(proxy);
|
|
}
|
|
|
|
//-- port knocker
|
|
if (!accountSettings.portKnockerPorts.IsEmpty()) {
|
|
CString host;
|
|
CString ip;
|
|
if (!accountSettings.portKnockerHost.IsEmpty()) {
|
|
host = accountSettings.portKnockerHost;
|
|
}
|
|
else {
|
|
host = RemovePort(get_account_server());
|
|
}
|
|
if (!host.IsEmpty()) {
|
|
AfxSocketInit();
|
|
if (IsIP(host)) {
|
|
ip = host;
|
|
}
|
|
else {
|
|
hostent *he = gethostbyname(CStringA(host));
|
|
if (he) {
|
|
ip = inet_ntoa(*((struct in_addr *) he->h_addr_list[0]));
|
|
}
|
|
}
|
|
CSocket udpSocket;
|
|
if (!ip.IsEmpty() && udpSocket.Create(0, SOCK_DGRAM, 0)) {
|
|
int pos = 0;
|
|
CString strPort = accountSettings.portKnockerPorts.Tokenize(_T(","), pos);
|
|
while (pos != -1) {
|
|
strPort.Trim();
|
|
if (!strPort.IsEmpty()) {
|
|
int port = StrToInt(strPort);
|
|
if (port > 0 && port <= 65535) {
|
|
udpSocket.SendToEx(0, 0, port, ip);
|
|
}
|
|
}
|
|
strPort = accountSettings.portKnockerPorts.Tokenize(_T(","), pos);
|
|
}
|
|
udpSocket.Close();
|
|
}
|
|
}
|
|
}
|
|
//--
|
|
pj_status_t status = PJ_SUCCESS;
|
|
//--
|
|
CString localURI;
|
|
if (!accountSettings.account.displayName.IsEmpty()) {
|
|
localURI = _T("\"") + accountSettings.account.displayName + _T("\" ");
|
|
}
|
|
localURI += GetSIPURI(get_account_username());
|
|
acc_cfg.id = StrToPjStr(localURI);
|
|
//--
|
|
if (get_account_server().IsEmpty()) {
|
|
acc_cfg.register_on_acc_add = PJ_FALSE;
|
|
}
|
|
else {
|
|
CString regURI;
|
|
regURI.Format(_T("sip:%s"), get_account_server());
|
|
AddTransportSuffix(regURI);
|
|
acc_cfg.reg_uri = StrToPjStr(regURI);
|
|
}
|
|
//--
|
|
status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &account);
|
|
|
|
if (account == PJSUA_INVALID_ID) {
|
|
ShowErrorMessage(status);
|
|
UpdateWindowText(_T(""), IDI_DEFAULT, true);
|
|
}
|
|
|
|
PublishStatus(true, acc_cfg.register_on_acc_add);
|
|
|
|
}
|
|
|
|
void CmainDlg::PJAccountAddLocal()
|
|
{
|
|
if (MACRO_ENABLE_LOCAL_ACCOUNT) {
|
|
pj_status_t status;
|
|
pjsua_acc_config acc_cfg;
|
|
PJAccountConfig(&acc_cfg);
|
|
acc_cfg.priority--;
|
|
pjsua_transport_data *t = &pjsua_var.tpdata[0];
|
|
CString localURI;
|
|
localURI.Format(_T("<sip:%s>"), PjToStr(&t->local_name.host));
|
|
acc_cfg.id = StrToPjStr(localURI);
|
|
pjsua_acc_add(&acc_cfg, PJ_TRUE, &account_local);
|
|
acc_cfg.priority++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete account if exists.
|
|
*/
|
|
void CmainDlg::PJAccountDelete(bool deep)
|
|
{
|
|
if (pageContacts) {
|
|
pageContacts->PresenceUnsubsribe();
|
|
}
|
|
if (pjsua_acc_is_valid(account)) {
|
|
pjsua_acc_del(account);
|
|
account = PJSUA_INVALID_ID;
|
|
}
|
|
onMWIInfo(0, 0);
|
|
SetPaneText2();
|
|
SetWindowText(_T(_GLOBAL_NAME_NICE));
|
|
UpdateWindowText();
|
|
}
|
|
|
|
void CmainDlg::PJAccountDeleteLocal()
|
|
{
|
|
if (pjsua_acc_is_valid(account_local)) {
|
|
pjsua_acc_del(account_local);
|
|
account_local = PJSUA_INVALID_ID;
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
|
|
{
|
|
CTabCtrl* tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
int nTab = tab->GetCurSel();
|
|
TC_ITEM tci;
|
|
tci.mask = TCIF_PARAM;
|
|
tab->GetItem(nTab, &tci);
|
|
if (tci.lParam > 0) {
|
|
CWnd* pWnd = (CWnd *)tci.lParam;
|
|
if (m_tabPrev != -1) {
|
|
tab->GetItem(m_tabPrev, &tci);
|
|
if (tci.lParam > 0) {
|
|
((CWnd *)tci.lParam)->ShowWindow(SW_HIDE);
|
|
}
|
|
}
|
|
pWnd->ShowWindow(SW_SHOW);
|
|
if (IsWindowVisible()) {
|
|
pWnd->SetFocus();
|
|
}
|
|
if (nTab != accountSettings.activeTab) {
|
|
accountSettings.activeTab = nTab;
|
|
AccountSettingsPendingSave();
|
|
}
|
|
if (pWnd == pageCalls && missed) {
|
|
missed = false;
|
|
UpdateWindowText();
|
|
}
|
|
}
|
|
else {
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CmainDlg::OnTcnSelchangingTab(NMHDR *pNMHDR, LRESULT *pResult)
|
|
{
|
|
CTabCtrl* tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
m_tabPrev = tab->GetCurSel();
|
|
*pResult = FALSE;
|
|
}
|
|
|
|
LRESULT CmainDlg::OnUpdateWindowText(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UpdateWindowText(_T("-"));
|
|
return TRUE;
|
|
}
|
|
|
|
void CmainDlg::TabFocusSet()
|
|
{
|
|
CTabCtrl* tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
int nTab = tab->GetCurSel();
|
|
TC_ITEM tci;
|
|
tci.mask = TCIF_PARAM;
|
|
tab->GetItem(nTab, &tci);
|
|
CWnd* pWnd = (CWnd *)tci.lParam;
|
|
pWnd->SetFocus();
|
|
}
|
|
|
|
void CmainDlg::UpdateWindowText(CString text, int icon, bool afterRegister)
|
|
{
|
|
if (text.IsEmpty() && pjsua_var.state == PJSUA_STATE_RUNNING && pjsua_call_get_count()) {
|
|
return;
|
|
}
|
|
CString str;
|
|
bool showAccountDlg = false;
|
|
if (text.IsEmpty() || text == _T("-")) {
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING && pjsua_acc_is_valid(account)) {
|
|
pjsua_acc_info info;
|
|
pjsua_acc_get_info(account, &info);
|
|
str = PjToStr(&info.status_text);
|
|
if (str != _T("Default status message")) {
|
|
if (!info.has_registration || str == _T("OK"))
|
|
{
|
|
if (m_PresenceStatus == PJRPID_ACTIVITY_BUSY) {
|
|
icon = IDI_BUSY;
|
|
str = Translate(_T("Do Not Disturb"));
|
|
} else {
|
|
if (m_PresenceStatus == PJRPID_ACTIVITY_AWAY) {
|
|
icon = IDI_AWAY;
|
|
str = Translate(_T("Away"));
|
|
}
|
|
else {
|
|
if (info.has_registration && transport == MSIP_TRANSPORT_TLS) {
|
|
icon = IDI_SECURE;
|
|
}
|
|
else {
|
|
icon = IDI_ONLINE;
|
|
}
|
|
str = Translate(_T("Online"));
|
|
}
|
|
if (accountSettings.autoAnswer == _T("button") && accountSettings.AA) {
|
|
str.AppendFormat(_T(" (%s)"), Translate(_T("Auto Answer")));
|
|
}
|
|
}
|
|
if (!info.has_registration) {
|
|
str.AppendFormat(_T(" (%s)"), Translate(_T("outgoing")));
|
|
}
|
|
pageContacts->PresenceSubsribe();
|
|
if (!dialNumberDelayed.IsEmpty())
|
|
{
|
|
DialNumber(dialNumberDelayed);
|
|
dialNumberDelayed = _T("");
|
|
}
|
|
}
|
|
else if (str == _T("In Progress")) {
|
|
str.Format(_T("%s..."), Translate(_T("Connecting")));
|
|
}
|
|
else if (info.status == 401 || info.status == 403) {
|
|
onTrayNotify(NULL, WM_LBUTTONUP);
|
|
if (afterRegister) {
|
|
showAccountDlg = true;
|
|
}
|
|
icon = IDI_OFFLINE;
|
|
str = Translate(_T("Incorrect Password"));
|
|
}
|
|
else {
|
|
str = Translate(str.GetBuffer());
|
|
}
|
|
str = str.GetBuffer();
|
|
}
|
|
else {
|
|
str.Format(_T("%s: %d"), Translate(_T("Response Code")), info.status);
|
|
}
|
|
}
|
|
else {
|
|
if (afterRegister) {
|
|
showAccountDlg = true;
|
|
}
|
|
str = _T(_GLOBAL_NAME_NICE);
|
|
icon = IDI_DEFAULT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
str = text;
|
|
}
|
|
|
|
CString* pPaneText = new CString();
|
|
*pPaneText = str;
|
|
PostMessage(UM_SET_PANE_TEXT, NULL, (LPARAM)pPaneText);
|
|
|
|
if (icon != -1) {
|
|
HICON hIcon = (HICON)LoadImage(
|
|
AfxGetInstanceHandle(),
|
|
MAKEINTRESOURCE(icon),
|
|
IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
|
|
m_bar.GetStatusBarCtrl().SetIcon(0, hIcon);
|
|
iconStatusbar = icon;
|
|
|
|
//--
|
|
tnd.uFlags = tnd.uFlags & ~NIF_INFO;
|
|
if ((pjsua_var.state == PJSUA_STATE_RUNNING && !pjsua_acc_is_valid(account) && MACRO_ENABLE_LOCAL_ACCOUNT) || (icon != IDI_DEFAULT && icon != IDI_OFFLINE)) {
|
|
if (missed) {
|
|
if (tnd.hIcon != iconMissed) {
|
|
tnd.uFlags = tnd.uFlags & ~NIF_INFO;
|
|
tnd.hIcon = iconMissed;
|
|
Shell_NotifyIcon(NIM_MODIFY, &tnd);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (tnd.hIcon != iconSmall) {
|
|
tnd.hIcon = iconSmall;
|
|
Shell_NotifyIcon(NIM_MODIFY, &tnd);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (tnd.hIcon != iconInactive) {
|
|
tnd.hIcon = iconInactive;
|
|
Shell_NotifyIcon(NIM_MODIFY, &tnd);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
if (showAccountDlg) {
|
|
PostMessage(UM_ON_ACCOUNT, 1);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::PublishStatus(bool online, bool init)
|
|
{
|
|
bool busy = (accountSettings.denyIncoming == _T("button") && accountSettings.DND);
|
|
pjrpid_activity presenceStatusNew;
|
|
pj_str_t note = pj_str("");
|
|
if (m_PresenceStatus == PJRPID_ACTIVITY_BUSY) {
|
|
if (!busy) {
|
|
presenceStatusNew = PJRPID_ACTIVITY_UNKNOWN;
|
|
note = pj_str("Idle");
|
|
}
|
|
}
|
|
else {
|
|
if (busy) {
|
|
presenceStatusNew = PJRPID_ACTIVITY_BUSY;
|
|
note = pj_str("Busy");
|
|
}
|
|
else {
|
|
presenceStatusNew = online ? PJRPID_ACTIVITY_UNKNOWN : PJRPID_ACTIVITY_AWAY;
|
|
note = online ? pj_str("Idle") : pj_str("Away");
|
|
}
|
|
}
|
|
if (note.slen) {
|
|
pjsua_acc_id ids[PJSUA_MAX_ACC];
|
|
unsigned count = PJSUA_MAX_ACC;
|
|
if (pjsua_enum_accs(ids, &count) == PJ_SUCCESS) {
|
|
pjrpid_element pr;
|
|
pr.type = PJRPID_ELEMENT_TYPE_PERSON;
|
|
pr.id = pj_str(NULL);
|
|
pr.note = pj_str(NULL);
|
|
pr.note = note;
|
|
pr.activity = presenceStatusNew;
|
|
for (unsigned i = 0; i < count; i++) {
|
|
pjsua_acc_set_online_status2(ids[i], PJ_TRUE, &pr);
|
|
}
|
|
}
|
|
m_PresenceStatus = presenceStatusNew;
|
|
}
|
|
if (!init) {
|
|
UpdateWindowText();
|
|
}
|
|
}
|
|
|
|
LRESULT CmainDlg::onCopyData(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (pj_ready) {
|
|
COPYDATASTRUCT *s = (COPYDATASTRUCT*)lParam;
|
|
if (s && s->dwData == 1) {
|
|
CString params = (LPCTSTR)s->lpData;
|
|
CommandLine(params);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CmainDlg::CommandLine(CString params) {
|
|
params.Trim();
|
|
if (!params.IsEmpty()) {
|
|
int pos = params.Find(_T("msip:"));
|
|
if (pos == 0) {
|
|
CString cmd = params.Mid(5);
|
|
if (cmd == _T("minimize")) {
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
else if (cmd == _T("answer")) {
|
|
msip_call_answer();
|
|
}
|
|
else if (cmd == _T("hangupall")) {
|
|
call_hangup_all_noincoming();
|
|
}
|
|
else if (cmd == _T("hold")) {
|
|
messagesDlg->OnBnClickedHold();
|
|
}
|
|
else if (cmd.Find(_T("transfer_")) == 0) {
|
|
messagesDlg->CallAction(MSIP_ACTION_TRANSFER, cmd.Mid(9));
|
|
}
|
|
else if (cmd == _T("micmute")) {
|
|
pageDialer->OnBnClickedMuteInput();
|
|
}
|
|
else if (cmd == _T("speakmute")) {
|
|
pageDialer->OnBnClickedMuteOutput();
|
|
}
|
|
else if (cmd == _T("micup")) {
|
|
pageDialer->OnBnClickedPlusInput();
|
|
}
|
|
else if (cmd == _T("micdown")) {
|
|
pageDialer->OnBnClickedMinusInput();
|
|
}
|
|
else if (cmd == _T("speakup")) {
|
|
pageDialer->OnBnClickedPlusOutput();
|
|
}
|
|
else if (cmd == _T("speakdown")) {
|
|
pageDialer->OnBnClickedMinusOutput();
|
|
}
|
|
else if (!cmd.IsEmpty()) {
|
|
DialNumberFromCommandLine(cmd);
|
|
}
|
|
}
|
|
else {
|
|
if (params == _T("/answer")) {
|
|
msip_call_answer();
|
|
}
|
|
else if (params == _T("/hangupall")) {
|
|
call_hangup_all_noincoming();
|
|
}
|
|
else {
|
|
DialNumberFromCommandLine(params);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CmainDlg::GotoTabLParam(LPARAM lParam) {
|
|
CTabCtrl* tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
for (int i = 0; i < tab->GetItemCount(); i++) {
|
|
TC_ITEM tci;
|
|
tci.mask = TCIF_PARAM;
|
|
tab->GetItem(i, &tci);
|
|
if (tci.lParam == lParam) {
|
|
return GotoTab(i, tab);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CmainDlg::GotoTab(int i, CTabCtrl* tab) {
|
|
if (!tab) {
|
|
tab = (CTabCtrl*)GetDlgItem(IDC_MAIN_TAB);
|
|
}
|
|
int nTab = tab->GetCurSel();
|
|
if (nTab != i) {
|
|
LRESULT pResult;
|
|
OnTcnSelchangingTab(NULL, &pResult);
|
|
tab->SetCurSel(i);
|
|
OnTcnSelchangeTab(NULL, &pResult);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void CmainDlg::DialNumberFromCommandLine(CString number) {
|
|
GotoTab(0);
|
|
pjsua_acc_info info;
|
|
number.Trim('"');
|
|
if (number.Mid(0, 4).CompareNoCase(_T("tel:")) == 0 || number.Mid(0, 4).CompareNoCase(_T("sip:")) == 0) {
|
|
number = number.Mid(4);
|
|
}
|
|
else if (number.Mid(0, 7).CompareNoCase(_T("callto:")) == 0) {
|
|
number = number.Mid(7);
|
|
}
|
|
if (accountSettings.accountId > 0) {
|
|
if (pjsua_acc_is_valid(account) &&
|
|
(get_account_server().IsEmpty() ||
|
|
(pjsua_acc_get_info(account, &info) == PJ_SUCCESS && info.status == 200)
|
|
)
|
|
) {
|
|
DialNumber(number);
|
|
}
|
|
else {
|
|
dialNumberDelayed = number;
|
|
}
|
|
}
|
|
else {
|
|
if (pjsua_acc_is_valid(account_local)) {
|
|
DialNumber(number);
|
|
}
|
|
else if (accountSettings.enableLocalAccount) {
|
|
dialNumberDelayed = number;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmainDlg::DialNumber(CString params)
|
|
{
|
|
CString number;
|
|
CString message;
|
|
int i = params.Find(_T(" "));
|
|
if (i != -1) {
|
|
number = params.Mid(0, i);
|
|
message = params.Mid(i + 1);
|
|
message.Trim();
|
|
}
|
|
else {
|
|
number = params;
|
|
}
|
|
number.Trim();
|
|
if (!number.IsEmpty()) {
|
|
if (message.IsEmpty()) {
|
|
MakeCall(number);
|
|
}
|
|
else {
|
|
messagesDlg->SendInstantMessage(NULL, message, number);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CmainDlg::MakeCall(CString number, bool hasVideo)
|
|
{
|
|
if (accountSettings.singleMode && call_get_count_noincoming()) {
|
|
GotoTab(0);
|
|
}
|
|
else {
|
|
accountSettings.lastCallNumber = number;
|
|
accountSettings.lastCallHasVideo = hasVideo;
|
|
CString commands;
|
|
CString numberFormated = FormatNumber(number, &commands);
|
|
pj_status_t pj_status = pjsua_verify_sip_url(StrToPj(numberFormated));
|
|
if (pj_status == PJ_SUCCESS) {
|
|
bool doNotShowMessagesWindow = accountSettings.singleMode ||
|
|
(accountSettings.silent && !mainDlg->IsWindowVisible());
|
|
messagesDlg->AddTab(numberFormated, _T(""), TRUE, NULL, NULL, doNotShowMessagesWindow);
|
|
messagesDlg->Call(hasVideo, commands);
|
|
return true;
|
|
}
|
|
else {
|
|
ShowErrorMessage(pj_status);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CmainDlg::MessagesOpen(CString number)
|
|
{
|
|
CString commands;
|
|
CString numberFormated = FormatNumber(number, &commands);
|
|
pj_status_t pj_status = pjsua_verify_sip_url(StrToPj(numberFormated));
|
|
if (pj_status == PJ_SUCCESS) {
|
|
messagesDlg->AddTab(numberFormated, _T(""), TRUE);
|
|
return true;
|
|
}
|
|
else {
|
|
ShowErrorMessage(pj_status);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CmainDlg::AutoAnswer(pjsua_call_id call_id)
|
|
{
|
|
pjsua_call_info call_info;
|
|
if (pjsua_call_get_info(call_id, &call_info) != PJ_SUCCESS || (call_info.state != PJSIP_INV_STATE_INCOMING && call_info.state != PJSIP_INV_STATE_EARLY)) {
|
|
return;
|
|
}
|
|
mainDlg->PostMessage(UM_CALL_ANSWER, (WPARAM)call_id, (LPARAM)call_info.rem_vid_cnt);
|
|
if (!accountSettings.hidden) {
|
|
mainDlg->PostMessage(UM_ON_PLAYER_PLAY, MSIP_SOUND_RINGIN2, 0);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::ShortcutAction(Shortcut *shortcut)
|
|
{
|
|
switch (shortcut->type) {
|
|
case MSIP_SHORTCUT_CALL:
|
|
mainDlg->MakeCall(shortcut->number);
|
|
break;
|
|
case MSIP_SHORTCUT_VIDEOCALL:
|
|
#ifdef _GLOBAL_VIDEO
|
|
mainDlg->MakeCall(shortcut->number, true);
|
|
#else
|
|
mainDlg->MakeCall(shortcut->number);
|
|
#endif
|
|
break;
|
|
case MSIP_SHORTCUT_MESSAGE:
|
|
mainDlg->MessagesOpen(shortcut->number);
|
|
break;
|
|
case MSIP_SHORTCUT_DTMF:
|
|
mainDlg->pageDialer->DTMF(shortcut->number);
|
|
break;
|
|
case MSIP_SHORTCUT_TRANSFER:
|
|
MessagesContact* messagesContactSelected = mainDlg->messagesDlg->GetMessageContact();
|
|
if (messagesContactSelected && messagesContactSelected->callId != -1) {
|
|
pj_str_t pj_uri = StrToPjStr(GetSIPURI(shortcut->number, true));
|
|
call_user_data *user_data;
|
|
user_data = (call_user_data *)pjsua_call_get_user_data(messagesContactSelected->callId);
|
|
if (!user_data || !user_data->inConference) {
|
|
pjsua_call_xfer(messagesContactSelected->callId, &pj_uri, NULL);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LRESULT CmainDlg::onPlayerPlay(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CString filename;
|
|
BOOL noLoop;
|
|
BOOL inCall;
|
|
if (wParam == MSIP_SOUND_CUSTOM) {
|
|
filename = *(CString*)lParam;
|
|
noLoop = FALSE;
|
|
inCall = FALSE;
|
|
}
|
|
else {
|
|
filename = accountSettings.pathExe + _T("\\");
|
|
switch (wParam) {
|
|
case MSIP_SOUND_MESSAGE_IN:
|
|
filename.Append(_T("messagein.wav"));
|
|
noLoop = TRUE;
|
|
inCall = FALSE;
|
|
break;
|
|
case MSIP_SOUND_MESSAGE_OUT:
|
|
filename.Append(_T("messageout.wav"));
|
|
noLoop = TRUE;
|
|
inCall = FALSE;
|
|
break;
|
|
case MSIP_SOUND_HANGUP:
|
|
filename.Append(_T("hangup.wav"));
|
|
noLoop = TRUE;
|
|
inCall = TRUE;
|
|
break;
|
|
case MSIP_SOUND_RINGIN:
|
|
filename.Append(_T("ringin.wav"));
|
|
noLoop = FALSE;
|
|
inCall = FALSE;
|
|
break;
|
|
case MSIP_SOUND_RINGIN2:
|
|
filename.Append(_T("ringin2.wav"));
|
|
noLoop = TRUE;
|
|
inCall = TRUE;
|
|
break;
|
|
case MSIP_SOUND_RINGOUT:
|
|
filename.Append(_T("ringout.wav"));
|
|
noLoop = TRUE;
|
|
inCall = TRUE;
|
|
break;
|
|
default:
|
|
noLoop = TRUE;
|
|
inCall = FALSE;
|
|
}
|
|
}
|
|
PlayerPlay(filename, noLoop, inCall);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onPlayerStop(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PlayerStop();
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct pjsua_player_eof_data
|
|
{
|
|
pj_pool_t *pool;
|
|
pjsua_player_id player_id;
|
|
};
|
|
|
|
static PJ_DEF(pj_status_t) on_pjsua_wav_file_end_callback(pjmedia_port* media_port, void* args)
|
|
{
|
|
mainDlg->PostMessage(UM_ON_PLAYER_STOP, 0, 0);
|
|
return -1;//Here it is important to return value other than PJ_SUCCESS
|
|
}
|
|
|
|
void CmainDlg::PlayerPlay(CString filename, bool noLoop, bool inCall)
|
|
{
|
|
PlayerStop();
|
|
if (pjsua_var.state != PJSUA_STATE_NULL && !filename.IsEmpty()) {
|
|
pj_str_t file = StrToPjStr(filename);
|
|
if (pjsua_var.mconf && pjsua_player_create(&file, noLoop ? PJMEDIA_FILE_NO_LOOP : 0, &player_id) == PJ_SUCCESS) {
|
|
pjmedia_port *player_media_port;
|
|
if (pjsua_player_get_port(player_id, &player_media_port) == PJ_SUCCESS) {
|
|
if (noLoop) {
|
|
pj_pool_t *pool = pjsua_pool_create("microsip_eof_data", 512, 512);
|
|
struct pjsua_player_eof_data *eof_data = PJ_POOL_ZALLOC_T(pool, struct pjsua_player_eof_data);
|
|
eof_data->pool = pool;
|
|
eof_data->player_id = player_id;
|
|
pjmedia_wav_player_set_eof_cb(player_media_port, eof_data, &on_pjsua_wav_file_end_callback);
|
|
}
|
|
if (
|
|
(!tone_gen && pjsua_conf_get_active_ports() <= 2)
|
|
||
|
|
(tone_gen && pjsua_conf_get_active_ports() <= 3)
|
|
) {
|
|
msip_set_sound_device(inCall ? msip_audio_output : msip_audio_ring);
|
|
}
|
|
pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmainDlg::PlayerStop()
|
|
{
|
|
if (player_id != PJSUA_INVALID_ID) {
|
|
if (pjsua_var.state != PJSUA_STATE_NULL) {
|
|
pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0);
|
|
if (pjsua_player_destroy(player_id) == PJ_SUCCESS) {
|
|
player_id = PJSUA_INVALID_ID;
|
|
}
|
|
}
|
|
else {
|
|
player_id = PJSUA_INVALID_ID;
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CmainDlg::onShellHookMessage(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (wParam == HSHELL_APPCOMMAND) {
|
|
int nCmd = GET_APPCOMMAND_LPARAM(lParam);
|
|
if (nCmd == APPCOMMAND_MEDIA_PLAY ||
|
|
nCmd == APPCOMMAND_MEDIA_PLAY_PAUSE ||
|
|
nCmd == APPCOMMAND_MEDIA_STOP) {
|
|
if (ringinDlgs.GetCount()) {
|
|
RinginDlg *ringinDlg = ringinDlgs.GetAt(0);
|
|
if (nCmd == APPCOMMAND_MEDIA_STOP) {
|
|
ringinDlg->OnBnClickedDecline();
|
|
}
|
|
else {
|
|
ringinDlg->CallAccept(ringinDlg->remoteHasVideo);
|
|
}
|
|
}
|
|
else {
|
|
if (nCmd == APPCOMMAND_MEDIA_STOP) {
|
|
messagesDlg->OnBnClickedEnd();
|
|
}
|
|
else {
|
|
CButton* callButton = (CButton*)pageDialer->GetDlgItem(IDC_CALL);
|
|
if (callButton->IsWindowVisible() && callButton->IsWindowEnabled()) {
|
|
pageDialer->OnBnClickedCall();
|
|
}
|
|
else {
|
|
messagesDlg->OnBnClickedHold();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (nCmd == APPCOMMAND_MEDIA_PAUSE) {
|
|
messagesDlg->OnBnClickedHold();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onCallAnswer(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING) {
|
|
pjsua_call_id call_id = wParam;
|
|
if (lParam < 0) {
|
|
pjsua_call_answer(call_id, -lParam, NULL, NULL);
|
|
return 0;
|
|
}
|
|
pjsua_call_info call_info;
|
|
if (pjsua_call_get_info(call_id, &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)) {
|
|
if (accountSettings.singleMode) {
|
|
call_hangup_all_noincoming();
|
|
}
|
|
msip_set_sound_device(msip_audio_output);
|
|
#ifdef _GLOBAL_VIDEO
|
|
if (lParam > 0) {
|
|
createPreviewWin();
|
|
}
|
|
#endif
|
|
pjsua_call_setting call_setting;
|
|
pjsua_call_setting_default(&call_setting);
|
|
call_setting.vid_cnt = lParam > 0 ? 1 : 0;
|
|
if (pjsua_call_answer2(call_id, &call_setting, 200, NULL, NULL) == PJ_SUCCESS) {
|
|
callIdIncomingIgnore = PjToStr(&call_info.call_id);
|
|
}
|
|
PlayerStop();
|
|
if (!accountSettings.silent) {
|
|
onTrayNotify(NULL, WM_LBUTTONUP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onCallHangup(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (pjsua_var.state == PJSUA_STATE_RUNNING) {
|
|
pjsua_call_id call_id = wParam;
|
|
msip_call_hangup_fast(call_id);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onTabIconUpdate(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (messagesDlg) {
|
|
pjsua_call_id call_id = wParam;
|
|
for (int i = 0; i < messagesDlg->tab->GetItemCount(); i++) {
|
|
MessagesContact* messagesContact = messagesDlg->GetMessageContact(i);
|
|
if (messagesContact->callId == call_id) {
|
|
pjsua_call_info call_info;
|
|
if (pjsua_call_get_info(call_id, &call_info) == PJ_SUCCESS) {
|
|
messagesDlg->UpdateTabIcon(messagesContact, i, &call_info);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CmainDlg::onSetPaneText(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CString* pString = (CString*)lParam;
|
|
ASSERT(pString != NULL);
|
|
m_bar.SetPaneText(0, *pString);
|
|
delete pString;
|
|
return 0;
|
|
}
|
|
|
|
void CmainDlg::SetPaneText2(CString str)
|
|
{
|
|
if (str.IsEmpty()) {
|
|
m_bar.SetPaneInfo(1, IDS_STATUSBAR2, SBPS_NOBORDERS, 0);
|
|
}
|
|
else {
|
|
CSize size = m_bar.GetDC()->GetTextExtent(str);
|
|
int width = size.cx;
|
|
m_bar.SetPaneInfo(1, IDS_STATUSBAR2, SBPS_NORMAL, width);
|
|
}
|
|
m_bar.SetPaneText(1, str);
|
|
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDS_STATUSBAR);
|
|
}
|
|
|
|
BOOL CmainDlg::CopyStringToClipboard(IN const CString & str)
|
|
{
|
|
// Open the clipboard
|
|
if (!OpenClipboard())
|
|
return FALSE;
|
|
|
|
// Empty the clipboard
|
|
if (!EmptyClipboard())
|
|
{
|
|
CloseClipboard();
|
|
return FALSE;
|
|
}
|
|
|
|
// Number of bytes to copy (consider +1 for end-of-string, and
|
|
// properly scale byte size to sizeof(TCHAR))
|
|
SIZE_T textCopySize = (str.GetLength() + 1) * sizeof(TCHAR);
|
|
|
|
// Allocate a global memory object for the text
|
|
HGLOBAL hTextCopy = GlobalAlloc(GMEM_MOVEABLE, textCopySize);
|
|
if (hTextCopy == NULL)
|
|
{
|
|
CloseClipboard();
|
|
return FALSE;
|
|
}
|
|
|
|
// Lock the handle, and copy source text to the buffer
|
|
TCHAR * textCopy = reinterpret_cast<TCHAR *>(GlobalLock(
|
|
hTextCopy));
|
|
ASSERT(textCopy != NULL);
|
|
StringCbCopy(textCopy, textCopySize, str.GetString());
|
|
GlobalUnlock(hTextCopy);
|
|
textCopy = NULL; // avoid dangling references
|
|
|
|
// Place the handle on the clipboard
|
|
#if defined( _UNICODE )
|
|
UINT textFormat = CF_UNICODETEXT; // Unicode text
|
|
#else
|
|
UINT textFormat = CF_TEXT; // ANSI text
|
|
#endif // defined( _UNICODE )
|
|
|
|
if (SetClipboardData(textFormat, hTextCopy) == NULL)
|
|
{
|
|
// Failed
|
|
CloseClipboard();
|
|
return FALSE;
|
|
}
|
|
|
|
// Release the clipboard
|
|
CloseClipboard();
|
|
|
|
// All right
|
|
return TRUE;
|
|
}
|
|
|
|
void CmainDlg::OnSysCommand(UINT nID, LPARAM lParam)
|
|
{
|
|
if (nID == SC_CLOSE) {
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
else {
|
|
__super::OnSysCommand(nID, lParam);
|
|
}
|
|
}
|
|
|
|
BOOL CmainDlg::OnQueryEndSession()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void CmainDlg::OnClose()
|
|
{
|
|
DestroyWindow();
|
|
}
|
|
|
|
void CmainDlg::OnContextMenu(CWnd *pWnd, CPoint point)
|
|
{
|
|
CPoint local = point;
|
|
ScreenToClient(&local);
|
|
CRect rect;
|
|
GetClientRect(&rect);
|
|
int height = 16;
|
|
CDC *pDC = GetDC();
|
|
if (pDC) {
|
|
int dpiY = GetDeviceCaps(pDC->m_hDC, LOGPIXELSY);
|
|
height = MulDiv(height, dpiY, 96);
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
if (rect.Height() - local.y <= height) {
|
|
MainPopupMenu();
|
|
}
|
|
else {
|
|
DefWindowProc(WM_CONTEXTMENU, NULL, MAKELPARAM(point.x, point.y));
|
|
}
|
|
}
|
|
|
|
BOOL CmainDlg::OnDeviceChange(UINT nEventType, DWORD_PTR dwData)
|
|
{
|
|
if (nEventType == DBT_DEVNODES_CHANGED) {
|
|
if (pj_ready) {
|
|
if (dwData == 1) {
|
|
PJ_LOG(3, (THIS_FILE, "OnDeviceStateChanged event, schedule refresh devices"));
|
|
}
|
|
else {
|
|
PJ_LOG(3, (THIS_FILE, "WM_DEVICECHANGE received, schedule refresh devices"));
|
|
}
|
|
KillTimer(IDT_TIMER_SWITCH_DEVICES);
|
|
SetTimer(IDT_TIMER_SWITCH_DEVICES, 1500, NULL);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CmainDlg::OnSessionChange(UINT nSessionState, UINT nId)
|
|
{
|
|
if (nSessionState == WTS_REMOTE_CONNECT || nSessionState == WTS_CONSOLE_CONNECT) {
|
|
if (pj_ready) {
|
|
PJ_LOG(3, (THIS_FILE, "WM_WTSSESSION_CHANGE received, schedule refresh devices"));
|
|
KillTimer(IDT_TIMER_SWITCH_DEVICES);
|
|
SetTimer(IDT_TIMER_SWITCH_DEVICES, 1500, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnMove(int x, int y)
|
|
{
|
|
if (IsWindowVisible() && !IsZoomed() && !IsIconic()) {
|
|
CRect cRect;
|
|
GetWindowRect(&cRect);
|
|
accountSettings.mainX = cRect.left;
|
|
accountSettings.mainY = cRect.top;
|
|
AccountSettingsPendingSave();
|
|
}
|
|
}
|
|
|
|
void CmainDlg::OnSize(UINT type, int w, int h)
|
|
{
|
|
CBaseDialog::OnSize(type, w, h);
|
|
if (this->IsWindowVisible() && type == SIZE_RESTORED) {
|
|
CRect cRect;
|
|
GetWindowRect(&cRect);
|
|
accountSettings.mainW = cRect.Width();
|
|
accountSettings.mainH = cRect.Height();
|
|
AccountSettingsPendingSave();
|
|
}
|
|
}
|
|
|
|
void CmainDlg::SetupJumpList()
|
|
{
|
|
JumpList jl(_T(_GLOBAL_NAME_NICE));
|
|
jl.AddTasks();
|
|
}
|
|
|
|
void CmainDlg::RemoveJumpList()
|
|
{
|
|
JumpList jl(_T(_GLOBAL_NAME_NICE));
|
|
jl.DeleteJumpList();
|
|
}
|
|
|
|
void CmainDlg::OnMenuWebsite()
|
|
{
|
|
OpenURL(_T(_GLOBAL_MENU_WEBSITE));
|
|
}
|
|
|
|
void CmainDlg::OnMenuHelp()
|
|
{
|
|
OpenURL(_T(_GLOBAL_MENU_HELP));
|
|
}
|
|
|
|
void CmainDlg::OnMenuAddl()
|
|
{
|
|
}
|
|
|
|
LRESULT CmainDlg::onUsersDirectoryLoaded(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PJ_LOG(3, (THIS_FILE, "Users directory loaded"));
|
|
URLGetAsyncData *response = (URLGetAsyncData *)wParam;
|
|
int expires = 0;
|
|
if (response->statusCode == 200 && !response->body.IsEmpty()) {
|
|
CXMLFile xmlFile;
|
|
if (xmlFile.LoadFromStream((BYTE*)response->body.GetBuffer(), response->body.GetLength())) {
|
|
BOOL ok = FALSE;
|
|
bool changed = false;
|
|
pageContacts->SetCanditates();
|
|
CXMLElement *root = xmlFile.GetRoot();
|
|
CXMLElement *directory = root->GetFirstChild();
|
|
while (directory) {
|
|
if (directory->GetElementType() == XET_TAG) {
|
|
CXMLElement *entry = directory->GetFirstChild();
|
|
while (entry) {
|
|
if (entry->GetElementType() == XET_TAG) {
|
|
CXMLElement *data = entry->GetFirstChild();
|
|
CString number;
|
|
CString name;
|
|
char presence = -1;
|
|
while (data) {
|
|
if (data->GetElementType() == XET_TAG) {
|
|
CString dataName = data->GetElementName();
|
|
CXMLElement *value = data->GetFirstChild();
|
|
if (value->GetElementType() == XET_TEXT) {
|
|
if (dataName.CompareNoCase(_T("name")) == 0) {
|
|
name = Utf8DecodeUni(UnicodeToAnsi(value->GetElementName()));
|
|
}
|
|
else if (dataName.CompareNoCase(_T("extension")) == 0 || dataName.CompareNoCase(_T("number")) == 0 || dataName.CompareNoCase(_T("telephone")) == 0) {
|
|
number = Utf8DecodeUni(UnicodeToAnsi(value->GetElementName()));
|
|
}
|
|
else if (dataName.CompareNoCase(_T("presence")) == 0) {
|
|
CString rab = value->GetElementName();
|
|
presence = !(rab.IsEmpty() || rab == _T("0")
|
|
|| rab.CompareNoCase(_T("no")) == 0
|
|
|| rab.CompareNoCase(_T("false")) == 0
|
|
|| rab.CompareNoCase(_T("null")) == 0);
|
|
}
|
|
}
|
|
}
|
|
data = entry->GetNextChild();
|
|
}
|
|
if (!number.IsEmpty()) {
|
|
if (pageContacts->ContactAdd(number, name, presence, 1, FALSE, TRUE) && !changed) {
|
|
changed = true;
|
|
}
|
|
if (!ok) {
|
|
ok = TRUE;
|
|
}
|
|
}
|
|
}
|
|
entry = directory->GetNextChild();
|
|
}
|
|
}
|
|
directory = root->GetNextChild();
|
|
}
|
|
if (ok) {
|
|
if (pageContacts->DeleteCanditates() || changed) {
|
|
pageContacts->ContactsSave();
|
|
}
|
|
}
|
|
}
|
|
response->headers.MakeLower();
|
|
CString search = _T("\r\ncache-control:");
|
|
int n = response->headers.Find(search);
|
|
if (n > 0) {
|
|
n = n + search.GetLength();
|
|
int l = response->headers.Find(_T("\r\n"), n);
|
|
if (l > 0) {
|
|
response->headers = response->headers.Mid(n, l - n);
|
|
search = _T("max-age=");
|
|
n = response->headers.Find(search);
|
|
if (n != -1) {
|
|
response->headers = response->headers.Mid(n + search.GetLength());
|
|
expires = atoi(CStringA(response->headers));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (expires <= 0) {
|
|
expires = 3600;
|
|
}
|
|
else if (expires < 60) {
|
|
expires = 60;
|
|
}
|
|
else if (expires > 86400) {
|
|
expires = 86400;
|
|
}
|
|
SetTimer(IDT_TIMER_DIRECTORY, 1000 * expires, NULL);
|
|
|
|
PJ_LOG(3, (THIS_FILE, "End UsersDirectoryLoad"));
|
|
delete response;
|
|
return 0;
|
|
}
|
|
|
|
void CmainDlg::UsersDirectoryLoad()
|
|
{
|
|
KillTimer(IDT_TIMER_DIRECTORY);
|
|
if (!accountSettings.usersDirectory.IsEmpty()) {
|
|
PJ_LOG(3, (THIS_FILE, "Users directory load"));
|
|
CString url;
|
|
url.Format(accountSettings.usersDirectory, accountSettings.account.username, accountSettings.account.password, get_account_server());
|
|
url = msip_url_mask(url);
|
|
PJ_LOG(3, (THIS_FILE, "Begin UsersDirectoryLoad"));
|
|
URLGetAsync(url, m_hWnd, UM_USERS_DIRECTORY);
|
|
}
|
|
}
|
|
|
|
void CmainDlg::AccountSettingsPendingSave()
|
|
{
|
|
KillTimer(IDT_TIMER_SAVE);
|
|
SetTimer(IDT_TIMER_SAVE, 5000, NULL);
|
|
}
|
|
|
|
void CmainDlg::CheckUpdates()
|
|
{
|
|
CInternetSession session;
|
|
try {
|
|
CHttpFile* pFile;
|
|
CString url = _T("http://update.microsip.org/?version=");
|
|
url.Append(_T(_GLOBAL_VERSION));
|
|
#ifndef _GLOBAL_VIDEO
|
|
url.Append(_T("&lite=1"));
|
|
#endif
|
|
pFile = (CHttpFile*)session.OpenURL(url, NULL, INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE);
|
|
if (pFile)
|
|
{
|
|
DWORD dwStatusCode;
|
|
pFile->QueryInfoStatusCode(dwStatusCode);
|
|
if (dwStatusCode == 202) {
|
|
CString caption;
|
|
caption.Format(_T("%s %s"), _T(_GLOBAL_NAME), Translate(_T("Update Available")));
|
|
CString message = Translate(_T("Do you want to update now?"));
|
|
CStringA body;
|
|
int i;
|
|
UINT len = 0;
|
|
do {
|
|
LPSTR p = body.GetBuffer(len + 1024);
|
|
i = pFile->Read(p + len, 1024);
|
|
len += i;
|
|
body.ReleaseBuffer(len);
|
|
} while (i>0);
|
|
//--
|
|
if (!body.IsEmpty()) {
|
|
message.AppendFormat(_T("\r\n\r\n%s"), CString(body));
|
|
}
|
|
if (::MessageBox(this->m_hWnd, message, caption, MB_YESNO | MB_ICONQUESTION) == IDYES)
|
|
{
|
|
OpenURL(_T("http://www.microsip.org/downloads"));
|
|
}
|
|
}
|
|
pFile->Close();
|
|
}
|
|
session.Close();
|
|
}
|
|
catch (CInternetException *e) {}
|
|
}
|
|
|
|
#ifdef _GLOBAL_VIDEO
|
|
int CmainDlg::VideoCaptureDeviceId(CString name)
|
|
{
|
|
unsigned count = 64;
|
|
pjmedia_vid_dev_info vid_dev_info[64];
|
|
pjsua_vid_enum_devs(vid_dev_info, &count);
|
|
for (unsigned i = 0; i < count; i++) {
|
|
if (vid_dev_info[i].fmt_cnt && (vid_dev_info[i].dir == PJMEDIA_DIR_ENCODING || vid_dev_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING)) {
|
|
CString vidDevName(vid_dev_info[i].name);
|
|
if ((!name.IsEmpty() && name == vidDevName)
|
|
||
|
|
(name.IsEmpty() && accountSettings.videoCaptureDevice == vidDevName)) {
|
|
return vid_dev_info[i].id;
|
|
}
|
|
}
|
|
}
|
|
return PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
|
|
}
|
|
|
|
void CmainDlg::createPreviewWin()
|
|
{
|
|
if (!previewWin) {
|
|
previewWin = new Preview(this);
|
|
}
|
|
previewWin->Start(VideoCaptureDeviceId());
|
|
}
|
|
#endif
|