Ticket #493: PocketPC, a new and better sample application for PocketPC

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1819 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip-apps/src/pocketpj/PocketPJDlg.cpp b/pjsip-apps/src/pocketpj/PocketPJDlg.cpp
new file mode 100644
index 0000000..430b822
--- /dev/null
+++ b/pjsip-apps/src/pocketpj/PocketPJDlg.cpp
@@ -0,0 +1,709 @@
+// PocketPJDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "PocketPJ.h"
+#include "PocketPJDlg.h"
+#include <iphlpapi.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define TIMER_ID    101
+static CPocketPJDlg *theDlg;
+
+/////////////////////////////////////////////////////////////////////////////
+// CPocketPJDlg dialog
+
+CPocketPJDlg::CPocketPJDlg(CWnd* pParent /*=NULL*/)
+	: CDialog(CPocketPJDlg::IDD, pParent), m_PopUp(NULL)
+{
+	//{{AFX_DATA_INIT(CPocketPJDlg)
+		// NOTE: the ClassWizard will add member initialization here
+	//}}AFX_DATA_INIT
+	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+
+	theDlg = this;
+
+	m_PopUp = new CPopUpWnd(this);
+	m_PopUp->Hide();
+
+	unsigned i;
+	m_PopUpCount = 0;
+	for (i=0; i<POPUP_MAX_TYPE; ++i) {
+	    m_PopUpState[i] = FALSE;
+	}
+}
+
+void CPocketPJDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+	//{{AFX_DATA_MAP(CPocketPJDlg)
+	DDX_Control(pDX, IDC_URL, m_Url);
+	DDX_Control(pDX, IDC_BUDDY_LIST, m_BuddyList);
+	DDX_Control(pDX, IDC_BTN_ACTION, m_BtnUrlAction);
+	DDX_Control(pDX, IDC_BTN_ACC, m_BtnAcc);
+	DDX_Control(pDX, IDC_ACC_ID, m_AccId);
+	//}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CPocketPJDlg, CDialog)
+	//{{AFX_MSG_MAP(CPocketPJDlg)
+	ON_BN_CLICKED(IDC_BTN_ACC, OnBtnAcc)
+	ON_BN_CLICKED(IDC_BTN_ACTION, OnBtnAction)
+	ON_COMMAND(IDC_ACC_SETTINGS, OnSettings)
+	ON_COMMAND(IDC_URI_CALL, OnUriCall)
+	ON_WM_TIMER()
+	ON_COMMAND(IDC_URI_ADD_BUDDY, OnUriAddBuddy)
+	ON_COMMAND(IDC_URI_DEL_BUDDY, OnUriDelBuddy)
+	ON_COMMAND(IDC_ACC_ONLINE, OnAccOnline)
+	ON_COMMAND(IDC_ACC_INVISIBLE, OnAccInvisible)
+	ON_NOTIFY(NM_CLICK, IDC_BUDDY_LIST, OnClickBuddyList)
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+void CPocketPJDlg::Error(const CString &title, pj_status_t rc)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+    wchar_t werrmsg[PJ_ERR_MSG_SIZE];
+
+    pj_strerror(rc, errmsg, sizeof(errmsg));
+    pj_ansi_to_unicode(errmsg, strlen(errmsg), werrmsg, PJ_ARRAY_SIZE(werrmsg));
+
+    AfxMessageBox(title + _T(": ") + werrmsg);
+}
+
+BOOL CPocketPJDlg::Restart()
+{
+    pj_status_t status;
+
+    char ver[80];
+    sprintf(ver, "PocketPJ/%s", pj_get_version());
+
+    ShowWindow(SW_SHOW);
+    PopUp_Show(POPUP_REGISTRATION, ver,
+	       "Starting up....", "", "", "", 0);
+
+    KillTimer(TIMER_ID);
+
+    // Destroy first.
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Cleaning up..");
+    pjsua_destroy();
+
+    m_BtnAcc.SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_OFFLINE)) );
+    UpdateWindow();
+
+
+    // Create
+    PopUp_Show(POPUP_REGISTRATION, ver,
+	       "Starting up....", "Creating stack..", "", "", 0);
+
+    status = pjsua_create();
+    if (status != PJ_SUCCESS) {
+	Error(_T("Error in creating library"), status);
+	PopUp_Hide(POPUP_REGISTRATION);
+	return FALSE;
+    }
+
+    pjsua_config cfg;
+    pjsua_logging_config log_cfg;
+    pjsua_media_config media_cfg;
+
+    pjsua_config_default(&cfg);
+    cfg.max_calls = 1;
+    cfg.thread_cnt = 0;
+    cfg.user_agent = pj_str(ver);
+
+    cfg.cb.on_call_state = &on_call_state;
+    cfg.cb.on_call_media_state = &on_call_media_state;
+    cfg.cb.on_incoming_call = &on_incoming_call;
+    cfg.cb.on_reg_state = &on_reg_state;
+    cfg.cb.on_buddy_state = &on_buddy_state;
+    cfg.cb.on_pager = &on_pager;
+
+    /* Configure nameserver */
+    char nameserver[60];
+    {
+	FIXED_INFO fi;
+	ULONG len = sizeof(fi);
+	CString err;
+
+	PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Retrieving network parameters..");
+	if (GetNetworkParams(&fi, &len) != ERROR_SUCCESS) {
+	    err = _T("Info: Error querying network parameters. You must configure DNS server.");
+	} else if (fi.CurrentDnsServer == NULL) {
+	    err = _T("Info: DNS server not configured. You must configure DNS server.");
+	} 
+	
+	if (err.GetLength()) {
+	    if (m_Cfg.m_DNS.GetLength()) {
+		pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_DNS, m_Cfg.m_DNS.GetLength(),
+				   nameserver, sizeof(nameserver));
+		cfg.nameserver_count = 1;
+		cfg.nameserver[0] = pj_str(nameserver);
+	    } else {
+		AfxMessageBox(err);
+		pjsua_destroy();
+		PopUp_Hide(POPUP_REGISTRATION);
+		return FALSE;
+	    }
+	} else {
+	    strcpy(nameserver, fi.CurrentDnsServer->IpAddress.String);
+	    cfg.nameserver_count = 1;
+	    cfg.nameserver[0] = pj_str(nameserver);
+	}
+    }
+
+    char tmp_stun[80];
+    if (m_Cfg.m_UseStun) {
+	pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_StunSrv, m_Cfg.m_StunSrv.GetLength(),
+			   tmp_stun, sizeof(tmp_stun));
+	cfg.stun_host = pj_str(tmp_stun);
+    }
+
+    pjsua_logging_config_default(&log_cfg);
+    log_cfg.log_filename = pj_str("\\PocketPJ.TXT");
+
+    pjsua_media_config_default(&media_cfg);
+    media_cfg.clock_rate = 8000;
+    media_cfg.audio_frame_ptime = 40;
+    media_cfg.ec_tail_len = 0;
+    media_cfg.ilbc_mode = 30;
+    media_cfg.max_media_ports = 8;
+    media_cfg.quality = 1;
+    media_cfg.thread_cnt = 1;
+    media_cfg.enable_ice = m_Cfg.m_UseIce;
+    
+    // Init
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Initializing..");
+    status = pjsua_init(&cfg, &log_cfg, &media_cfg);
+    if (status != PJ_SUCCESS) {
+	Error(_T("Error initializing library"), status);
+	pjsua_destroy();
+	PopUp_Hide(POPUP_REGISTRATION);
+	return FALSE;
+    }
+
+    // Create one UDP transport
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Add transport..");
+    pjsua_transport_id transport_id;
+    pjsua_transport_config udp_cfg;
+
+    pjsua_transport_config_default(&udp_cfg);
+    udp_cfg.port = 0;
+    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP,
+					&udp_cfg, &transport_id);
+    if (status != PJ_SUCCESS) {
+	Error(_T("Error creating UDP transport"), status);
+	pjsua_destroy();
+	PopUp_Hide(POPUP_REGISTRATION);
+	return FALSE;
+    }
+
+    // Adjust codecs priority
+    pj_str_t tmp;
+    pjsua_codec_set_priority(pj_cstr(&tmp, "GSM"),  200);
+    pjsua_codec_set_priority(pj_cstr(&tmp, "PCMU"), 190);
+    pjsua_codec_set_priority(pj_cstr(&tmp, "PCMA"), 185);
+    pjsua_codec_set_priority(pj_cstr(&tmp, "iLBC"), 0);
+    pjsua_codec_set_priority(pj_cstr(&tmp, "speex"), 0);
+    pjsua_codec_set_priority(pj_cstr(&tmp, "L16"), 0);
+
+
+    // Start!
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Starting..");
+    status = pjsua_start();
+    if (status != PJ_SUCCESS) {
+	Error(_T("Error starting library"), status);
+	pjsua_destroy();
+	PopUp_Hide(POPUP_REGISTRATION);
+	return FALSE;
+    }
+
+    // Add account
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "Adding account..");
+    char domain[80], username[80], passwd[80];
+    char id[80], reg_uri[80];
+    pjsua_acc_config acc_cfg;
+
+    pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_Domain, m_Cfg.m_Domain.GetLength(),
+		       domain, sizeof(domain));
+    pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_User, m_Cfg.m_User.GetLength(),
+		       username, sizeof(username));
+    pj_unicode_to_ansi((LPCTSTR)m_Cfg.m_Password, m_Cfg.m_Password.GetLength(),
+		       passwd, sizeof(passwd));
+
+    snprintf(id, sizeof(id), "<sip:%s@%s>", username, domain);
+    snprintf(reg_uri, sizeof(reg_uri), "sip:%s", domain);
+
+    pjsua_acc_config_default(&acc_cfg);
+    acc_cfg.id = pj_str(id);
+    acc_cfg.reg_uri = pj_str(reg_uri);
+    acc_cfg.cred_count = 1;
+    acc_cfg.cred_info[0].scheme = pj_str("Digest");
+    acc_cfg.cred_info[0].realm = pj_str("*");
+    acc_cfg.cred_info[0].username = pj_str(username);
+    acc_cfg.cred_info[0].data_type = 0;
+    acc_cfg.cred_info[0].data = pj_str(passwd);
+
+    acc_cfg.use_srtp = (m_Cfg.m_UseStun ? PJMEDIA_SRTP_OPTIONAL : PJMEDIA_SRTP_DISABLED);
+    acc_cfg.srtp_secure_signaling = 0;
+    acc_cfg.publish_enabled = m_Cfg.m_UsePublish;
+    
+    status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &m_PjsuaAccId);
+    if (status != PJ_SUCCESS) {
+	Error(_T("Invalid account settings"), status);
+	pjsua_destroy();
+	PopUp_Hide(POPUP_REGISTRATION);
+	return FALSE;
+    }
+
+    CString acc_text = m_Cfg.m_User + _T("@") + m_Cfg.m_Domain;
+    m_AccId.SetWindowText(acc_text);
+
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE1, acc_text);
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE2, "Registering..");
+    PopUp_Modify(POPUP_REGISTRATION, POPUP_EL_TITLE3, "");
+
+    SetTimer(TIMER_ID, 100, NULL);
+    return TRUE;
+}
+
+
+void CPocketPJDlg::PopUp_Show( PopUpType type, 
+			        const CString& title1,
+				const CString& title2,
+				const CString& title3,
+				const CString& btn1,
+				const CString& btn2,
+				unsigned userData)
+{
+    if (!m_PopUpState[type])
+	++m_PopUpCount;
+
+    m_PopUpState[type] = TRUE;
+
+    m_PopUpContent[type].m_Title1 = title1;
+    m_PopUpContent[type].m_Title2 = title2;
+    m_PopUpContent[type].m_Title3 = title3;
+    m_PopUpContent[type].m_Btn1 = btn1;
+    m_PopUpContent[type].m_Btn2 = btn2;
+
+    m_PopUp->SetContent(m_PopUpContent[type]);
+    m_PopUp->Show();
+}
+
+void CPocketPJDlg::PopUp_Modify(PopUpType type,
+				PopUpElement el,
+				const CString& text)
+{
+    switch (el) {
+    case POPUP_EL_TITLE1:
+	m_PopUpContent[type].m_Title1 = text;
+	break;
+    case POPUP_EL_TITLE2:
+	m_PopUpContent[type].m_Title2 = text;
+	break;
+    case POPUP_EL_TITLE3:
+	m_PopUpContent[type].m_Title3 = text;
+	break;
+    case POPUP_EL_BUTTON1:
+	m_PopUpContent[type].m_Btn1 = text;
+	break;
+    case POPUP_EL_BUTTON2:
+	m_PopUpContent[type].m_Btn1 = text;
+	break;
+    }
+
+    m_PopUp->SetContent(m_PopUpContent[type]);
+}
+
+void CPocketPJDlg::PopUp_Hide(PopUpType type)
+{
+    if (m_PopUpState[type])
+	--m_PopUpCount;
+
+    m_PopUpState[type] = FALSE;
+
+    if (m_PopUpCount == 0) {
+	m_PopUp->Hide();
+	UpdateWindow();
+    } else {
+	for (int i=POPUP_MAX_TYPE-1; i>=0; --i) {
+	    if (m_PopUpState[i]) {
+		m_PopUp->SetContent(m_PopUpContent[i]);
+		break;
+	    }
+	}
+    }
+}
+
+void CPocketPJDlg::OnCallState()
+{
+    pjsua_call_info ci;
+
+    pjsua_call_get_info(0, &ci);
+    
+    switch (ci.state) {
+    case PJSIP_INV_STATE_NULL:	    /**< Before INVITE is sent or received  */
+	break;
+    case PJSIP_INV_STATE_CALLING:   /**< After INVITE is sent		    */
+	PopUp_Show(POPUP_CALL, "Calling..", ci.remote_info.ptr, "",
+		   "", "Hangup", 0);
+	break;
+    case PJSIP_INV_STATE_INCOMING:  /**< After INVITE is received.	    */
+	PopUp_Show(POPUP_CALL, "Incoming call..", ci.remote_info.ptr, "",
+		   "Answer", "Hangup", 0);
+	pjsua_call_answer(0, 180, NULL, NULL);
+	break;
+    case PJSIP_INV_STATE_EARLY:	    /**< After response with To tag.	    */
+    case PJSIP_INV_STATE_CONNECTING:/**< After 2xx is sent/received.	    */
+    case PJSIP_INV_STATE_CONFIRMED:  /**< After ACK is sent/received.	    */
+	{
+	    CString stateText = ci.state_text.ptr;
+	    PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE3, stateText);
+	}
+	break;
+    case PJSIP_INV_STATE_DISCONNECTED:/**< Session is terminated.	    */
+	PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE3, "Disconnected");
+	PopUp_Hide(POPUP_CALL);
+	break;
+    }    
+}
+
+void CPocketPJDlg::on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    theDlg->OnCallState();
+}
+
+void CPocketPJDlg::on_call_media_state(pjsua_call_id call_id)
+{
+    pjsua_call_info call_info;
+
+    pjsua_call_get_info(call_id, &call_info);
+    if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
+	pjsua_conf_connect(call_info.conf_slot, 0);
+	pjsua_conf_connect(0, call_info.conf_slot);
+    }
+}
+
+void CPocketPJDlg::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+				    pjsip_rx_data *rdata)
+{
+}
+
+void CPocketPJDlg::OnRegState()
+{
+    pjsua_acc_info ai;
+    pjsua_acc_get_info(m_PjsuaAccId, &ai);
+
+    CString acc_text = m_Cfg.m_User + _T("@") + m_Cfg.m_Domain;
+
+    if (ai.expires>0 && ai.status/100==2) {
+	/* Registration success */
+	HBITMAP old = m_BtnAcc.SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_ONLINE)) );
+	acc_text += " (OK)";
+	m_AccId.SetWindowText(acc_text);
+	PopUp_Hide(POPUP_REGISTRATION);
+    } else if (ai.status/100 != 2) {
+	acc_text += " (err)";
+	Error(_T("SIP registration error"), PJSIP_ERRNO_FROM_SIP_STATUS(ai.status));
+	m_AccId.SetWindowText(acc_text);
+	PopUp_Hide(POPUP_REGISTRATION);
+    }
+}
+
+void CPocketPJDlg::on_reg_state(pjsua_acc_id acc_id)
+{
+    theDlg->OnRegState();
+}
+
+void CPocketPJDlg::on_buddy_state(pjsua_buddy_id buddy_id)
+{
+    theDlg->RedrawBuddyList();
+}
+
+void CPocketPJDlg::on_pager(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 *text)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CPocketPJDlg message handlers
+
+BOOL CPocketPJDlg::OnInitDialog()
+{
+	CDialog::OnInitDialog();
+
+	// 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
+	
+	CenterWindow(GetDesktopWindow());	// center to the hpc screen
+ 
+	// TODO: Add extra initialization here
+	
+	m_Cfg.LoadRegistry();
+	//ShowWindow(SW_SHOW);
+	m_AccId.SetWindowText(m_Cfg.m_User);
+
+	CImageList *il = new CImageList;
+	VERIFY(il->Create(16, 16, ILC_COLOR|ILC_MASK, 2, 4));
+
+	CBitmap *bmp = new CBitmap;
+	bmp->LoadBitmap(MAKEINTRESOURCE(IDB_BLANK));
+	il->Add(bmp, RGB(255,255,255));
+	bmp = new CBitmap;
+	bmp->LoadBitmap(MAKEINTRESOURCE(IDB_ONLINE));
+	il->Add(bmp, RGB(255,255,255));
+	
+	m_BuddyList.SetImageList(il, LVSIL_SMALL);
+
+	if (m_Cfg.m_Domain.GetLength()==0 || Restart() == FALSE) {
+	    for (;;) {
+		CSettingsDlg dlg(m_Cfg);
+		if (dlg.DoModal() != IDOK) {
+		    EndDialog(IDOK);
+		    return TRUE;
+		}
+
+		m_Cfg.SaveRegistry();
+
+		if (Restart())
+		    break;
+	    }
+	}
+
+	RedrawBuddyList();
+	return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+
+
+void CPocketPJDlg::OnBtnAcc() 
+{
+    CMenu menu;
+    VERIFY(menu.LoadMenu(IDR_ACC_MENU));
+    CMenu* pPopup = menu.GetSubMenu(0);
+    ASSERT(pPopup != NULL);
+
+    RECT r;
+    m_BtnAcc.GetWindowRect(&r);
+    pPopup->TrackPopupMenu(TPM_LEFTALIGN, r.left+4, r.top+4, this);
+}
+
+void CPocketPJDlg::OnBtnAction() 
+{
+    CMenu menu;
+    VERIFY(menu.LoadMenu(IDR_URI_MENU));
+    CMenu* pPopup = menu.GetSubMenu(0);
+    ASSERT(pPopup != NULL);
+
+    RECT r;
+    this->m_BtnUrlAction.GetWindowRect(&r);
+    pPopup->TrackPopupMenu(TPM_LEFTALIGN, r.left+4, r.top+4, this);
+}
+
+void CPocketPJDlg::OnSettings() 
+{
+    for (;;) {
+	CSettingsDlg dlg(m_Cfg);
+	if (dlg.DoModal() != IDOK) {
+	    return;
+	}
+
+	m_Cfg.SaveRegistry();
+
+	if (Restart())
+	    break;
+    }
+}
+
+void CPocketPJDlg::OnOK()
+{
+    if (AfxMessageBox(_T("Quit PocketPJ?"), MB_YESNO)==IDYES) {
+	KillTimer(TIMER_ID);
+	PopUp_Show(POPUP_REGISTRATION, "", "Shutting down..", "", "", "", 0);
+	pjsua_destroy();
+	CDialog::OnOK();
+	PopUp_Hide(POPUP_REGISTRATION);
+	m_Cfg.SaveRegistry();
+	return;
+    }
+}
+
+void CPocketPJDlg::OnTimer(UINT nIDEvent) 
+{
+    pjsua_handle_events(10);
+    CDialog::OnTimer(nIDEvent);
+}
+
+int  CPocketPJDlg::FindBuddyInPjsua(const CString &Uri)
+{
+    char uri[80];
+    pjsua_buddy_id  id[128];
+    unsigned i, count = PJ_ARRAY_SIZE(id);
+
+    if (pjsua_enum_buddies(id, &count) != PJ_SUCCESS)
+	return PJSUA_INVALID_ID;
+    if (count==0)
+	return PJSUA_INVALID_ID;
+
+    pj_unicode_to_ansi((LPCTSTR)Uri, Uri.GetLength(), uri, sizeof(uri));
+
+    for (i=0; i<count; ++i) {
+	pjsua_buddy_info bi;
+	pjsua_buddy_get_info(id[i], &bi);
+	if (pj_strcmp2(&bi.uri, uri)==0)
+	    return i;
+    }
+
+    return PJSUA_INVALID_ID;
+}
+
+int  CPocketPJDlg::FindBuddyInCfg(const CString &uri)
+{
+    int i;
+    for (i=0; i<m_Cfg.m_BuddyList.GetSize(); ++i) {
+	if (m_Cfg.m_BuddyList.GetAt(0) == uri) {
+	    return i;
+	}
+    }
+    return -1;
+}
+
+void CPocketPJDlg::RedrawBuddyList()
+{
+    int i;
+
+    m_BuddyList.DeleteAllItems();
+
+    for (i=0; i<m_Cfg.m_BuddyList.GetSize(); ++i) {
+	int isOnline;
+	int id;
+
+	id = FindBuddyInPjsua(m_Cfg.m_BuddyList.GetAt(i));
+	if (id != PJSUA_INVALID_ID) {
+	    pjsua_buddy_info bi;
+	    pjsua_buddy_get_info(id, &bi);
+	    isOnline = (bi.status == PJSUA_BUDDY_STATUS_ONLINE);
+	} else {
+	    isOnline = 0;
+	}
+
+	LVITEM lvi;
+	memset(&lvi, 0, sizeof(lvi));
+	lvi.mask = LVIF_TEXT  | LVIF_IMAGE;
+	lvi.iItem = i;
+	lvi.iImage = isOnline;
+	lvi.pszText = (LPTSTR)(LPCTSTR)m_Cfg.m_BuddyList.GetAt(i);
+
+	m_BuddyList.InsertItem(&lvi);
+    }
+}
+
+void CPocketPJDlg::OnUriCall() 
+{
+    char tmp[120];
+    CString uri;
+    pj_status_t status;
+
+    m_Url.GetWindowText(uri);
+    pj_unicode_to_ansi((LPCTSTR)uri, uri.GetLength(), tmp, sizeof(tmp));
+    if ((status=pjsua_verify_sip_url(tmp)) != PJ_SUCCESS) {
+	Error("The URL is not valid SIP URL", status);
+	return;
+    }
+
+    pj_str_t dest_uri = pj_str(tmp);
+    pjsua_call_id call_id;
+
+    status = pjsua_call_make_call(m_PjsuaAccId, &dest_uri, 0, NULL, NULL, &call_id);
+
+    if (status != PJ_SUCCESS)
+	Error("Unable to make call", status);
+}
+
+void CPocketPJDlg::OnUriAddBuddy() 
+{
+    int i;
+    char tmp[120];
+    CString uri;
+    pj_status_t status;
+
+    m_Url.GetWindowText(uri);
+    pj_unicode_to_ansi((LPCTSTR)uri, uri.GetLength(), tmp, sizeof(tmp));
+    if ((status=pjsua_verify_sip_url(tmp)) != PJ_SUCCESS) {
+	Error("The URL is not valid SIP URL", status);
+	return;
+    }
+
+    for (i=0; i<m_Cfg.m_BuddyList.GetSize(); ++i) {
+	if (m_Cfg.m_BuddyList.GetAt(0) == uri) {
+	    AfxMessageBox(_T("The URI is already in the buddy list"));
+	    return;
+	}
+    }
+
+    m_Cfg.m_BuddyList.Add(uri);
+    RedrawBuddyList();
+}
+
+void CPocketPJDlg::OnUriDelBuddy() 
+{
+    CString uri;
+
+    m_Url.GetWindowText(uri);
+    int i = FindBuddyInCfg(uri);
+    if (i<0) {
+	/* Buddy not found */
+	return;
+    }
+
+    m_Cfg.m_BuddyList.RemoveAt(i);
+    RedrawBuddyList();
+    AfxMessageBox(_T("Buddy " + uri + " deleted"));
+}
+
+void CPocketPJDlg::OnAccOnline() 
+{
+    pjsua_acc_set_online_status(m_PjsuaAccId, PJ_TRUE);
+    m_BtnAcc.SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_ONLINE)) );
+}
+
+void CPocketPJDlg::OnAccInvisible() 
+{
+    pjsua_acc_set_online_status(m_PjsuaAccId, PJ_FALSE);
+    m_BtnAcc.SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_INVISIBLE)) );
+}
+
+void CPocketPJDlg::OnPopUpButton(int btnNo)
+{
+    if (btnNo == 1) {
+	pjsua_call_answer(0, 200, NULL, 0);
+	PopUp_Modify(POPUP_CALL, POPUP_EL_BUTTON1, "");
+    } else if (btnNo == 2) {
+	// Hangup button
+	PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE2, "Hang up..");
+	PopUp_Modify(POPUP_CALL, POPUP_EL_TITLE3, "");
+	pjsua_call_hangup(0, PJSIP_SC_DECLINE, 0, 0);
+    }
+}
+
+void CPocketPJDlg::OnClickBuddyList(NMHDR* pNMHDR, LRESULT* pResult) 
+{
+    POSITION pos = m_BuddyList.GetFirstSelectedItemPosition();
+    if (pos != NULL) {
+	int iItem = m_BuddyList.GetNextSelectedItem(pos);
+	CString uri = m_BuddyList.GetItemText(iItem, 0);
+	m_Url.SetWindowText(uri);
+    }
+    *pResult = 0;
+}