www.pudn.com > (IPMessenger)Ver2.04.rar > MAINWIN.CPP


static char *mainwin_id =  
	"@(#)Copyright (C) H.Shirouzu 1996-2003   mainwin.cpp	Ver2.04"; 
/* ======================================================================== 
	Project  Name			: IP Messenger for Win32 
	Module Name				: Main Window 
	Create					: 1996-06-01(Sat) 
	Update					: 2003-10-01(Wed) 
	Copyright				: H.Shirouzu 
	Reference				:  
	======================================================================== */ 
 
#include "tlib.h" 
#include "resource.h" 
#include "ipmsg.h" 
#include "msgstr.h" 
 
HICON		TMainWin::hMainIcon = NULL; 
HICON		TMainWin::hRevIcon = NULL; 
TMainWin	*TMainWin::mainWin = NULL; 
static HWND	hMainWnd = NULL; 
 
/* 
	MainWindow の初期化 
*/ 
TMainWin::TMainWin(ULONG nicAddr, int _portNo, TWin *_parent) : TWin(_parent) 
{ 
	hosts.Enable(THosts::NAME, TRUE); 
	hosts.Enable(THosts::ADDR, TRUE); 
	cfg = new Cfg(nicAddr, portNo = _portNo); 
	if ((msgMng = new MsgMng(nicAddr, portNo, cfg))->GetStatus() == FALSE) 
	{ 
		::PostQuitMessage(0); 
		return; 
	} 
	cfg->ReadRegistry(); 
	setupDlg = new TSetupDlg(cfg, &hosts); 
	aboutDlg = new TAboutDlg(); 
	absenceDlg = new TAbsenceDlg(cfg, this); 
	logmng = new LogMng(cfg); 
	ansList = new TRecycleList(MAX_ANSLIST, sizeof(AddrObj)); 
	shareMng = new ShareMng(cfg); 
	shareStatDlg = new TShareStatDlg(shareMng, cfg); 
	refreshStartTime = 0; 
	entryStartTime = IPMSG_GETLIST_FINISH; 
 
	memset(packetLog, 0, sizeof(packetLog)); 
	packetLogCnt = 0; 
 
	entryTimerStatus = 0; 
	reverseTimerStatus = 0; 
	ansTimerID = 0; 
	terminateFlg = FALSE; 
	activeToggle = TRUE; 
 
	InitIcon(); 
 
 
	hAccel = ::LoadAccelerators(TApp::hI, (LPCSTR)IPMSG_ACCEL); 
} 
 
/* 
	MainWindow 終了 
*/ 
TMainWin::~TMainWin() 
{ 
#if 0	// 無駄 
	delete msgMng; 
	delete cfg; 
	delete ansList; 
#endif 
} 
 
/* 
	子Window および socketの終了と所有Memoryの開放 
*/ 
void TMainWin::Terminate(void) 
{ 
	if (terminateFlg == TRUE) 
		return; 
	terminateFlg = TRUE; 
 
	if (msgMng->GetStatus() != TRUE) 
		return; 
 
	ExitHost(); 
	DeleteListDlg(&sendList); 
	DeleteListDlg(&recvList); 
	DeleteListDlg(&msgList); 
	delete aboutDlg; 
	delete shareStatDlg; 
	delete absenceDlg; 
	delete setupDlg; 
 
	if (IsNewShell()) 
		TaskBar(NIM_DELETE); 
 
	time_t	now_time = Time(); 
	for (int cnt=0; cnt < hosts.HostCnt(); cnt++) 
		hosts.GetHost(cnt)->updateTime = now_time; 
	cfg->WriteRegistry(CFG_HOSTINFO|CFG_DELCHLDHOST); 
 
	msgMng->CloseSocket(); 
 
#if 0	// 無駄 
	delete logmng; 
 
	Host *host; 
	while (hosts.HostCnt() > 0) 
	{ 
		hosts.DelHost(host = hosts.GetHost(0)); 
//		delete host; 
	} 
 
	AddrObj *brObj; 
	while ((brObj = (AddrObj *)cfg->DialUpList.TopObj()) != NULL) 
	{ 
		cfg->DialUpList.DelObj(brObj); 
		delete brObj; 
	} 
#endif 
} 
 
/* 
	MainWindow 生成時の CallBack 
	New Shell なら、TaskTray に icon登録、そうでないなら icon化 
	Packet 受信開始、Entry Packetの送出 
*/ 
BOOL TMainWin::EvCreate(LPARAM lParam) 
{ 
	hMainWnd = hWnd; 
	mainWin = this; 
 
	if (msgMng->GetStatus() != TRUE) 
		return	TRUE; 
 
	if (IsNewShell()) 
	{ 
		Show(SW_HIDE); 
		while (TaskBar(NIM_ADD, hMainIcon, IPMSG_MSGSTR) != TRUE) 
			Sleep(1000);	// for logon script 
	} 
	else 
		Show(SW_MINIMIZE); 
	TaskBarCreateMsg= ::RegisterWindowMessage("TaskbarCreated"); 
 
	SetIcon(cfg->AbsenceCheck == FALSE ? hMainIcon : hRevIcon); 
	SetCaption(); 
	if (SetupCryptAPI() == FALSE) 
		MessageBox("CryptoAPI can't be used. Setup New version IE"); 
 
	msgMng->AsyncSelectRegist(hWnd); 
	SetHotKey(cfg); 
 
	if (msgMng->GetStatus() == TRUE) 
		EntryHost(); 
 
	return	TRUE; 
} 
 
/* 
	Task Managerなどからの終了要求 
*/ 
BOOL TMainWin::EvClose(void) 
{ 
	Terminate(); 
	::PostQuitMessage(0); 
	return	TRUE; 
} 
 
/* 
	Timer Callback 
	NonPopup受信時の icon反転 
	ListGet Modeにおける、HostList要求/受信処理 
*/ 
BOOL TMainWin::EvTimer(WPARAM timerID, TIMERPROC proc) 
{ 
	if (terminateFlg == TRUE) 
	{ 
		::KillTimer(hWnd, timerID); 
		return	TRUE; 
	} 
 
	switch (timerID) 
	{ 
	case IPMSG_REVERSEICON: 
		ReverseIcon(FALSE); 
		return	TRUE; 
 
	case IPMSG_LISTGET_TIMER: 
		::KillTimer(hWnd, IPMSG_LISTGET_TIMER); 
		entryTimerStatus = 0; 
		if (entryStartTime != IPMSG_GETLIST_FINISH) 
		{ 
			entryStartTime = Time(); 
			if (::SetTimer(hWnd, IPMSG_LISTGETRETRY_TIMER, cfg->ListGetMSec, NULL)) 
				entryTimerStatus = IPMSG_LISTGETRETRY_TIMER; 
			BroadcastEntry(IPMSG_BR_ISGETLIST2 | IPMSG_RETRYOPT); 
		} 
		return	TRUE; 
 
	case IPMSG_LISTGETRETRY_TIMER: 
		::KillTimer(hWnd, IPMSG_LISTGETRETRY_TIMER); 
		entryTimerStatus = 0; 
		if (entryStartTime != IPMSG_GETLIST_FINISH) 
		{ 
			entryStartTime = IPMSG_GETLIST_FINISH; 
			if (cfg->ListGet) 
				BroadcastEntry(IPMSG_BR_ENTRY); 
		} 
		return	TRUE; 
 
	case IPMSG_ANS_TIMER: 
		::KillTimer(hWnd, IPMSG_ANS_TIMER); 
		ansTimerID = 0; 
		ExecuteAnsQueue(); 
		return	TRUE; 
 
	case IPMSG_ENTRY_TIMER: 
		::KillTimer(hWnd, IPMSG_ENTRY_TIMER); 
 
		for (TBroadcastObj *brobj=cfg->broadcastList.Top(); brobj; brobj=cfg->broadcastList.Next(brobj)) 
			BroadcastEntrySub(brobj->Addr(), htons(portNo), IPMSG_BR_ENTRY); 
 
		for (AddrObj *obj = (AddrObj *)cfg->DialUpList.TopObj(); obj != NULL; obj = (AddrObj *)cfg->DialUpList.NextObj(obj)) 
			BroadcastEntrySub(obj->addr, obj->portNo, IPMSG_BR_ENTRY); 
		return	TRUE; 
	} 
 
	return	FALSE; 
} 
 
/* 
	WM_COMMAND CallBack 
*/ 
BOOL TMainWin::EvCommand(WORD wNotifyCode, WORD wID, LPARAM hwndCtl) 
{ 
	switch (wID) 
	{ 
	case MENU_SETUP: 
		MiscDlgOpen(setupDlg); 
		return	TRUE; 
 
	case MENU_LOGOPEN: 
		LogOpen(); 
		return	TRUE; 
 
	case MENU_ABOUT: 
		MiscDlgOpen(aboutDlg); 
		return	TRUE; 
 
	case MENU_SHARE: 
		MiscDlgOpen(shareStatDlg); 
		return	TRUE; 
 
	case MENU_ACTIVEWIN: 
		ActiveChildWindow(activeToggle = TRUE); 
		return	TRUE; 
 
	case MENU_ABSENCE: 
		cfg->AbsenceCheck = !cfg->AbsenceCheck; 
		BroadcastEntry(IPMSG_BR_ABSENCE);  
		SetIcon(cfg->AbsenceCheck == FALSE ? hMainIcon : hRevIcon); 
		return	TRUE; 
 
	case MENU_ABSENCEEX: 
		MiscDlgOpen(absenceDlg); 
		return	TRUE; 
 
	case HIDE_ACCEL: 
		PostMessage(WM_HIDE_CHILDWIN, 0, 0); 
		return	TRUE; 
 
	case MISC_ACCEL: 
	case MENU_DELMISCDLG: 
		DeleteListDlg(&msgList); 
		return	TRUE; 
 
	case MENU_EXIT: 
	case IDCANCEL: 
		Terminate(); 
		::PostQuitMessage(0); 
		return	TRUE; 
 
	default: 
		if (wID >= (UINT)MENU_ABSENCE_START && wID < (UINT)MENU_ABSENCE_START + cfg->AbsenceMax) 
		{ 
			cfg->AbsenceChoice = wID - MENU_ABSENCE_START; 
			cfg->AbsenceCheck = FALSE; 
			EvCommand(0, MENU_ABSENCE, 0); 
			return	TRUE; 
		} 
	} 
	return	FALSE; 
} 
 
/* 
	System Menu Callback 
*/ 
BOOL TMainWin::EvSysCommand(WPARAM uCmdType, WORD xPos, WORD yPos) 
{ 
	switch (uCmdType) 
	{ 
	case SC_RESTORE: case SC_MAXIMIZE: 
		if (!IsNewShell()) 
			SendDlgOpen(); 
		return	TRUE; 
 
	case MENU_SETUP: 
	case MENU_LOGOPEN: 
	case MENU_ABOUT: 
	case MENU_SHARE: 
	case MENU_ACTIVEWIN: 
	case MENU_DELMISCDLG: 
	case MENU_ABSENCE: 
	case MENU_ABSENCEEX: 
	case MENU_EXIT: 
		return	EvCommand(0, uCmdType, 0); 
 
	default: 
		if (uCmdType >= MENU_ABSENCE_START && (int)uCmdType < MENU_ABSENCE_START + cfg->AbsenceMax) 
			return	EvCommand(0, uCmdType, 0); 
		break; 
	} 
	return	FALSE; 
} 
 
/* 
	Logout時などの終了通知 CallBack 
*/ 
BOOL TMainWin::EvEndSession(BOOL nSession, BOOL nLogOut) 
{ 
	if (nSession) 
		Terminate(); 
	return	TRUE; 
} 
 
/* 
	iconを通常Windowに戻してよいかどうかの問い合わせ CallBack 
*/ 
BOOL TMainWin::EvQueryOpen(void) 
{ 
	if (!IsNewShell()) 
		SendDlgOpen(); 
	return	TRUE; 
} 
 
BOOL TMainWin::EvHotKey(int hotKey) 
{ 
	switch (hotKey) 
	{ 
	case WM_SENDDLG_OPEN: 
	case WM_DELMISCDLG: 
	case WM_RECVDLG_OPEN: 
		return	PostMessage(hotKey, 0, 0), TRUE; 
	} 
	return	FALSE; 
} 
 
/* 
	MouseButton Event CallBack 
*/ 
BOOL TMainWin::EventButton(UINT uMsg, int nHitTest, POINTS pos) 
{ 
	switch (uMsg) 
	{ 
//	case WM_RBUTTONDOWN: 
//	case WM_NCRBUTTONDOWN: 
	case WM_RBUTTONUP: 
	case WM_NCRBUTTONUP: 
		Popup(MAIN_MENU); 
		return	TRUE; 
 
	case WM_LBUTTONDBLCLK: 
	case WM_NCLBUTTONDBLCLK: 
		if (cfg->OneClickPopup == FALSE) 
			SendDlgOpen(); 
		return	TRUE; 
 
	case WM_LBUTTONDOWN: 
	case WM_NCLBUTTONDOWN: 
		SetForegroundWindow(); 
 
		BOOL ctl_on = (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE; 
		BOOL shift_on = (GetAsyncKeyState(VK_SHIFT) & 0x8000) ? TRUE : FALSE; 
		BOOL menu_on = (GetAsyncKeyState(VK_MENU) & 0x8000) ? TRUE : FALSE; 
 
//		if (ctl_on && !menu_on) 
//			return	PostMessage(WM_COMMAND, MENU_ABSENCE, 0), TRUE; 
		if (shift_on && !menu_on) 
			return	PostMessage(WM_COMMAND, MENU_ACTIVEWIN, 0), TRUE; 
 
		if (!IsNewShell() && cfg->MsgMinimize == FALSE) 
			ActiveListDlg(&msgList); 
 
		for (TSendDlg *dlg = (TSendDlg *)sendList.TopObj(); dlg != NULL; dlg = (TSendDlg *)sendList.NextObj(dlg)) 
			if (dlg->IsSending()) 
				dlg->SetForegroundWindow();	// 再送信確認ダイアログを前に 
 
		if (PopupCheck() == TRUE) 
			return	TRUE; 
 
		if (cfg->OneClickPopup == TRUE) 
			PostMessage(WM_SENDDLG_OPEN, 0, 0); 
		return	FALSE; 
	} 
	return	FALSE; 
} 
 
 
/* 
	Menu Event CallBack 
*/ 
BOOL TMainWin::EventInitMenu(UINT uMsg, HMENU hMenu, UINT uPos, BOOL fSystemMenu) 
{ 
	switch (uMsg) 
	{ 
	case WM_INITMENU: 
		if (IsNewShell() != TRUE && GetMenuItemID(hMenu, 0) != MENU_DELMISCDLG) 
		{ 
			HMENU	hTargetMenu; 
			char	buf[MAX_LISTBUF]; 
 
			GetSystemMenu(hWnd, TRUE);		// 初期化 
			hTargetMenu = GetSystemMenu(hWnd, FALSE); 
			DeleteMenu(hTargetMenu, SC_MAXIMIZE, MF_BYCOMMAND); 
			DeleteMenu(hTargetMenu, SC_MINIMIZE, MF_BYCOMMAND); 
			DeleteMenu(hTargetMenu, SC_SIZE, MF_BYCOMMAND); 
			DeleteMenu(hTargetMenu, SC_TASKLIST, MF_BYCOMMAND); 
 
			HMENU	hMainMenu	= LoadMenu(TApp::hI, (LPCSTR)MAIN_MENU); 
			HMENU	hSubMenu	= GetSubMenu(hMainMenu, 0); 
			int		maxItem = GetMenuItemCount(hSubMenu); 
			for (int cnt=0; cnt < maxItem -2; cnt++) 
			{ 
				if (GetMenuString(hSubMenu, cnt, buf, sizeof(buf), MF_BYPOSITION) > 0) 
					::AppendMenu(hTargetMenu, MF_STRING, GetMenuItemID(hSubMenu, cnt), buf); 
				else 
					::AppendMenu(hTargetMenu, MF_SEPARATOR, NULL, NULL); 
			} 
			AddAbsenceMenu(hTargetMenu, 0); 
			DestroyMenu(hMainMenu); 
		} 
		return	TRUE; 
	} 
	return	FALSE; 
} 
 
BOOL TMainWin::AddAbsenceMenu(HMENU hTargetMenu, int insertOffset) 
{ 
	char	buf[MAX_LISTBUF]; 
	HMENU	hSubMenu = ::CreateMenu(); 
	UINT	index = ::GetMenuItemCount(hTargetMenu) - insertOffset; 
 
	if (hSubMenu == NULL) 
		return	FALSE; 
 
	for (int cnt=cfg->AbsenceMax -1; cnt >= 0; cnt--) 
		::AppendMenu(hSubMenu, MF_STRING, MENU_ABSENCE_START + cnt, cfg->AbsenceHead[cnt]); 
	::AppendMenu(hSubMenu, MF_SEPARATOR, 0, 0); 
	::AppendMenu(hSubMenu, MF_STRING, MENU_ABSENCEEX, ABSENCESET_MSGSTR); 
	::InsertMenu(hTargetMenu, index++, MF_BYPOSITION|MF_POPUP, (UINT)hSubMenu, ABSENCEMENU_MSGSTR); 
 
	if (cfg->AbsenceCheck) 
	{ 
		wsprintf(buf, "%s(%s)", ABSENCELIFT_MSGSTR, cfg->AbsenceHead[cfg->AbsenceChoice]); 
		::InsertMenu(hTargetMenu, index, MF_BYPOSITION|MF_STRING, MENU_ABSENCE, buf); 
	} 
	return	TRUE; 
} 
 
/* 
	User定義 Event CallBack 
*/ 
BOOL TMainWin::EventUser(UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
	switch (uMsg) 
	{ 
	case WM_SENDDLG_OPEN: 
		SendDlgOpen((HWND)wParam, (MsgBuf *)lParam); 
		return	TRUE; 
 
	case WM_SENDDLG_EXIT: 
		SendDlgExit((TSendDlg *)lParam); 
		return	TRUE; 
 
	case WM_SENDDLG_HIDE: 
		SendDlgHide((TSendDlg *)lParam); 
		return	TRUE; 
 
	case WM_RECVDLG_OPEN: 
		PopupCheck(); 
		return	TRUE; 
 
	case WM_RECVDLG_EXIT: 
		RecvDlgExit((TRecvDlg *)lParam); 
		return	TRUE; 
 
	case WM_IPMSG_NOTIFY:	// TaskTray 
		PostMessage((UINT)lParam, 0, 0); 
		return	TRUE; 
 
	case WM_HIDE_CHILDWIN: 
		ActiveChildWindow(activeToggle = !activeToggle); 
		return	TRUE; 
 
	case WM_UDPEVENT: 
		UdpEvent(lParam); 
		return	TRUE; 
 
	case WM_TCPEVENT: 
		TcpEvent(wParam, lParam); 
		return	TRUE; 
 
	case WM_REFRESH_HOST: 
		RefreshHost((BOOL)wParam); 
		return	TRUE; 
 
	case WM_MSGDLG_EXIT: 
		MsgDlgExit((TMsgDlg *)lParam); 
		return	TRUE; 
 
	case WM_DELMISCDLG: 
		EvCommand(0, MENU_DELMISCDLG, 0); 
		return	TRUE; 
 
	case WM_IPMSG_INITICON: 
		InitIcon(); 
		SetIcon(cfg->AbsenceCheck == FALSE ? hMainIcon : hRevIcon); 
		return	TRUE; 
 
	default: 
		if (uMsg == TaskBarCreateMsg) 
		{ 
			TaskBar(NIM_ADD, hMainIcon, IPMSG_MSGSTR); 
			return	TRUE; 
		} 
	} 
	return	FALSE; 
} 
 
/* 
	参加 Message Packet送出 
*/ 
void TMainWin::EntryHost(void) 
{ 
	time_t	now_time = Time(); 
 
	if (entryStartTime + (time_t)cfg->ListGetMSec / 1000 > now_time) 
		return; 
	entryStartTime = now_time; 
 
	if (cfg->ListGet == TRUE) 
	{ 
		if (::SetTimer(hWnd, IPMSG_LISTGET_TIMER, cfg->ListGetMSec, NULL)) 
			entryTimerStatus = IPMSG_LISTGET_TIMER; 
		BroadcastEntry(IPMSG_BR_ISGETLIST2); 
	} 
	else 
		BroadcastEntry(IPMSG_BR_ENTRY); 
} 
 
/* 
	脱出 Message Packet送出 
*/ 
void TMainWin::ExitHost(void) 
{ 
	BroadcastEntry(IPMSG_BR_EXIT); 
	Sleep(100); 
	BroadcastEntry(IPMSG_BR_EXIT); 
} 
 
/* 
	重複 Packet調査(簡易...もしくは手抜きとも言う(^^;) 
*/				 
BOOL TMainWin::IsLastPacket(MsgBuf *msg) 
{ 
	for (int cnt=0; cnt < MAX_PACKETLOG; cnt++) 
	{ 
		if (packetLog[cnt].addr == msg->hostSub.addr && packetLog[cnt].port == msg->hostSub.portNo && packetLog[cnt].no == msg->packetNo && msg->packetNo != IPMSG_DEFAULT_PORT) 
		return	TRUE; 
	} 
	return	FALSE; 
} 
 
/* 
	UDP Packet 受信処理 
*/ 
BOOL TMainWin::UdpEvent(LPARAM lParam) 
{ 
	MsgBuf	msg; 
 
	if (WSAGETSELECTERROR(lParam) || msgMng->Recv(&msg) != TRUE) 
		return	FALSE; 
 
	if (cfg->PriorityReject) 
	{ 
		Host *host = cfg->priorityHosts.GetHostByName(&msg.hostSub); 
		if (host && (host->priority < 0 || cfg->PriorityReject >= 2 && host->priority == 0) && IsSameHost(&msg.hostSub, msgMng->GetLocalHost()) == FALSE) 
		{ 
			ULONG	cmd = GET_MODE(msg.command); 
			if (cmd != IPMSG_BR_EXIT && cmd != IPMSG_NOOPERATION) 
				BroadcastEntrySub(&msg.hostSub, IPMSG_BR_EXIT); 
			if (GET_MODE(msg.command) != IPMSG_ANSENTRY) 
				return	FALSE; 
		} 
	} 
 
	switch (GET_MODE(msg.command)) 
	{ 
	case IPMSG_BR_ENTRY: 
		MsgBrEntry(&msg); 
		return	TRUE; 
 
	case IPMSG_BR_EXIT: 
		MsgBrExit(&msg); 
		return	TRUE; 
 
	case IPMSG_ANSENTRY: 
		MsgAnsEntry(&msg); 
		return	TRUE; 
 
	case IPMSG_BR_ABSENCE: 
		MsgBrAbsence(&msg); 
		return	TRUE; 
 
	case IPMSG_SENDMSG: 
		MsgSendMsg(&msg); 
		break; 
 
	case IPMSG_RECVMSG: 
		MsgRecvMsg(&msg); 
		break; 
 
	case IPMSG_READMSG: 
	case IPMSG_ANSREADMSG: 
		MsgReadMsg(&msg); 
		break; 
 
	case IPMSG_BR_ISGETLIST2: 
		MsgBrIsGetList(&msg); 
		return	TRUE; 
 
	case IPMSG_OKGETLIST: 
		MsgOkGetList(&msg); 
		return	TRUE; 
 
	case IPMSG_GETLIST: 
		MsgGetList(&msg); 
		return	TRUE; 
 
	case IPMSG_ANSLIST: 
		MsgAnsList(&msg); 
		return	TRUE; 
 
	case IPMSG_GETINFO: 
		MsgGetInfo(&msg); 
		break; 
 
	case IPMSG_SENDINFO: 
		MsgSendInfo(&msg); 
		break; 
 
	case IPMSG_GETPUBKEY: 
		MsgGetPubKey(&msg); 
		break; 
 
	case IPMSG_ANSPUBKEY: 
		MsgAnsPubKey(&msg); 
		break; 
 
	case IPMSG_GETABSENCEINFO: 
		MsgGetAbsenceInfo(&msg); 
		break; 
 
	case IPMSG_SENDABSENCEINFO: 
		MsgSendAbsenceInfo(&msg); 
		break; 
 
	case IPMSG_RELEASEFILES: 
		MsgReleaseFiles(&msg); 
		break; 
	} 
 
	packetLog[packetLogCnt].no = msg.packetNo; 
	packetLog[packetLogCnt].addr = msg.hostSub.addr; 
	packetLog[packetLogCnt].port = msg.hostSub.portNo; 
	packetLogCnt = (packetLogCnt + 1) % MAX_PACKETLOG; 
 
	return	TRUE; 
} 
 
/* 
	TCP Packet 受信処理 
*/ 
inline SendFileObj *TMainWin::FindSendFileObj(int sd) 
{ 
	for (SendFileObj *obj = (SendFileObj *)sendFileList.TopObj(); obj; obj = (SendFileObj *)sendFileList.NextObj(obj)) 
		if (obj->conInfo->sd == sd) 
			return	obj; 
	return	NULL; 
} 
 
BOOL TMainWin::TcpEvent(int sd, LPARAM lParam) 
{ 
	if (WSAGETSELECTERROR(lParam)) 
		return	FALSE; 
 
	switch (LOWORD(lParam)) { 
	case FD_ACCEPT: 
		{ 
			ConnectInfo	tmpInfo, *info; 
			if (msgMng->Accept(hWnd, &tmpInfo)) 
			{ 
				if (CheckConnectInfo(&tmpInfo)) 
				{ 
					info = new ConnectInfo(tmpInfo); 
					connectList.AddObj(info); 
				} 
				else ::closesocket(tmpInfo.sd); 
			} 
		} 
		break; 
 
	case FD_READ: 
		StartSendFile(sd); 
		break; 
 
	case FD_CLOSE: 
		{ 
			SendFileObj *obj; 
			if ((obj = FindSendFileObj(sd)) != NULL) 
				EndSendFile(obj); 
			else 
				::closesocket(sd); 
		} 
		break; 
	} 
	return	TRUE; 
} 
 
BOOL TMainWin::CheckConnectInfo(ConnectInfo *conInfo) 
{ 
	for (ShareInfo *info=shareMng->Top(); info; info=shareMng->Next(info)) 
	{ 
		for (int cnt=0; cnt < info->hostCnt; cnt++) 
			if (info->host[cnt]->hostSub.addr == conInfo->addr/* && info->host[cnt]->hostSub.portNo == conInfo->port*/) 
				return	conInfo->port = info->host[cnt]->hostSub.portNo, TRUE; 
	} 
	return	FALSE; 
} 
 
/* 
	ファイル送受信開始処理 
*/ 
BOOL TMainWin::StartSendFile(int sd) 
{ 
	ConnectInfo 	*conInfo; 
	AcceptFileInfo	fileInfo; 
 
	for (conInfo=(ConnectInfo *)connectList.TopObj(); conInfo && conInfo->sd != sd; conInfo=(ConnectInfo *)connectList.NextObj(conInfo)) 
		; 
	if (conInfo == NULL) 
		return	::closesocket(sd), FALSE; 
	else { 
		msgMng->ConnectDone(hWnd, conInfo);	// 非同期メッセージの抑制 
 
// すでに read 要求がきているので、固まる事は無い...はず 
// 一度の recv で読めない場合、エラーにしてしまう(手抜き) 
		char	buf[MAX_PATH]; 
		int		size; 
		if ((size = ::recv(conInfo->sd, buf, sizeof(buf) -1, 0)) > 0) 
			buf[size] = 0; 
		if (size <= 0 || shareMng->GetAcceptableFileInfo(conInfo, buf, &fileInfo) == FALSE) 
		{ 
			connectList.DelObj(conInfo); 
			::closesocket(conInfo->sd); 
			delete conInfo; 
			return	FALSE; 
		} 
	} 
 
	SendFileObj	*obj = new SendFileObj; 
	memset(obj, 0, sizeof(SendFileObj)); 
	obj->conInfo = conInfo; 
	obj->hFile = INVALID_HANDLE_VALUE; 
	obj->fileInfo = fileInfo.fileInfo; 
	obj->offset = fileInfo.offset; 
	obj->packetNo = fileInfo.packetNo; 
	obj->host = fileInfo.host; 
	obj->command = GET_MODE(fileInfo.command); 
	obj->conInfo->startTick = obj->conInfo->lastTick = ::GetTickCount(); 
	obj->attachTime = fileInfo.attachTime; 
	connectList.DelObj(conInfo); 
	sendFileList.AddObj(obj); 
 
	if (GetFileInfomation(obj->fileInfo->Fname(), &obj->fdata) == FALSE) 
		return	EndSendFile(obj), FALSE; 
 
	obj->isDir = (obj->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE; 
	obj->status = obj->isDir || obj->command == IPMSG_GETDIRFILES ? FS_DIRFILESTART : FS_TRANSFILE; 
 
	if (*obj->fdata.cFileName == 0) 
		ForcePathToFname(obj->fileInfo->Fname(), obj->fdata.cFileName); 
 
	BOOL	ret; 
	if (obj->isDir) 
	{ 
		ret = obj->command == IPMSG_GETDIRFILES ? TRUE : FALSE; 
		obj->hDir = (HANDLE *)malloc((MAX_PATH/2) * sizeof(HANDLE)); 
	} 
	else { 
		if ((cfg->fileTransOpt & FT_STRICTDATE) && *(_int64 *)&obj->fdata.ftLastWriteTime > *(_int64 *)&obj->attachTime) 
			ret = FALSE, obj->status = FS_COMPLETE;		// 共有情報から消去 
		else 
			ret = OpenSendFile(obj->fileInfo->Fname(), obj); 
	} 
	if (ret == FALSE) 
		return	EndSendFile(obj), FALSE; 
 
	DWORD	id;	// 使わず(95系で error になるのを防ぐだけ) 
	obj->hThread = ~0;	// 微妙な領域を避ける 
	// thread 内では MT 対応が必要な crt は使わず 
	if ((obj->hThread = ::CreateThread(NULL, 0, SendFileThread, obj, 0, &id)) == NULL) 
		return	EndSendFile(obj), FALSE; 
 
	return	TRUE; 
} 
 
BOOL TMainWin::OpenSendFile(const char *fname, SendFileObj *obj) 
{ 
	DWORD	lowSize, highSize, viewSize; 
 
	if ((obj->hFile = ::CreateFile(fname, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) 
	{ 
		lowSize = ::GetFileSize(obj->hFile, &highSize); 
		if ((obj->fileSize = (_int64)highSize << 32 | lowSize) == 0) 
			return	TRUE; 
		obj->hMap = ::CreateFileMapping(obj->hFile, 0, PAGE_READONLY, highSize, lowSize, 0); 
		viewSize = (int)(obj->fileSize > cfg->ViewMax ? cfg->ViewMax : obj->fileSize); 
		highSize = (int)(obj->offset >> 32); 
		lowSize = (int)((obj->offset / cfg->ViewMax) * cfg->ViewMax); 
		obj->mapAddr = (char *)::MapViewOfFile(obj->hMap, FILE_MAP_READ, highSize, lowSize, viewSize); 
		if (obj->mapAddr && IsBadReadPtr(obj->mapAddr, 1) == TRUE) 
		{ 
			CloseSendFile(obj); 
			return	FALSE; 
		} 
	} 
	return	obj->mapAddr ? TRUE : FALSE; 
} 
 
BOOL TMainWin::CloseSendFile(SendFileObj *obj) 
{ 
	if (obj == NULL) 
		return	FALSE; 
 
	::UnmapViewOfFile(obj->mapAddr);obj->mapAddr= NULL; 
	::CloseHandle(obj->hMap);		obj->hMap	= NULL; 
	::CloseHandle(obj->hFile);		obj->hFile	= INVALID_HANDLE_VALUE; 
	obj->offset = 0; 
 
	return	TRUE; 
} 
 
DWORD WINAPI TMainWin::SendFileThread(void *_sendFileObj) 
{ 
	SendFileObj	*obj = (SendFileObj *)_sendFileObj; 
	fd_set		fds; 
	fd_set		*rfds = NULL, *wfds = &fds; 
	timeval		tv; 
	int			sock_ret; 
	BOOL		ret = FALSE, completeWait = FALSE; 
	BOOL		(TMainWin::*SendFileFunc)(SendFileObj *obj) = 
				obj->command == IPMSG_GETDIRFILES ? TMainWin::SendDirFile : TMainWin::SendFile; 
 
	FD_ZERO(&fds); 
	FD_SET(obj->conInfo->sd, &fds); 
 
	for (int waitCnt=0; waitCnt < 180 && obj->hThread != NULL; waitCnt++) 
	{ 
		tv.tv_sec = 1, tv.tv_usec = 0; 
 
		if ((sock_ret = ::select(obj->conInfo->sd + 1, rfds, wfds, NULL, &tv)) > 0) 
		{ 
			waitCnt = 0; 
 
			if (completeWait) 
			{	// dummy read により、相手側の socket クローズによる EOF を検出 
				if (::recv(obj->conInfo->sd, (char *)&ret, sizeof(ret), 0) >= 0) 
					ret = TRUE; 
				break; 
			} 
			else if ((mainWin->*SendFileFunc)(obj) != TRUE) 
				break; 
			else if (obj->status == FS_COMPLETE) 
			{ 
				completeWait = TRUE, rfds = &fds, wfds = NULL; 
				// 過去β7以前の互換性のため 
				if (obj->fileSize == 0) { ret = TRUE; break; } 
			} 
		} 
		else if (sock_ret == 0) { 
			FD_ZERO(&fds); 
			FD_SET(obj->conInfo->sd, &fds); 
		} 
		else if (sock_ret == SOCKET_ERROR) { 
			break; 
		} 
	} 
 
	if (obj->isDir) 
	{ 
		mainWin->CloseSendFile(obj); 
		while (--obj->dirCnt >= 0) 
			::FindClose(obj->hDir[obj->dirCnt]); 
	} 
 
	obj->status = ret ? FS_COMPLETE : FS_ERROR; 
	mainWin->PostMessage(WM_TCPEVENT, obj->conInfo->sd, FD_CLOSE); 
	::ExitThread(0); 
	return	0; 
} 
 
int MakeDirHeader(SendFileObj *obj, BOOL find) 
{ 
	int				len; 
	WIN32_FIND_DATA	*dat = &obj->fdata; 
	DWORD			attr = dat->dwFileAttributes, ipmsg_attr; 
 
	ipmsg_attr = (find == FALSE ? IPMSG_FILE_RETPARENT : (attr & FILE_ATTRIBUTE_DIRECTORY) 
			? IPMSG_FILE_DIR : IPMSG_FILE_REGULAR) | 
		(attr & FILE_ATTRIBUTE_READONLY ? IPMSG_FILE_RONLYOPT : 0) | 
		(attr & FILE_ATTRIBUTE_HIDDEN ? IPMSG_FILE_HIDDENOPT : 0) | 
		(attr & FILE_ATTRIBUTE_SYSTEM ? IPMSG_FILE_SYSTEMOPT : 0); 
 
	if (find) 
		len = wsprintf(obj->header, "0000:%s:%x%08x:%x:%x=%x:%x=%x:", dat->cFileName, 
				dat->nFileSizeHigh, dat->nFileSizeLow, ipmsg_attr, 
				IPMSG_FILE_MTIME, FileTime2UnixTime(&dat->ftLastWriteTime), 
				IPMSG_FILE_CREATETIME, FileTime2UnixTime(&dat->ftCreationTime)); 
	else if (*(_int64 *)&dat->ftLastWriteTime) 
		len = wsprintf(obj->header, "0000:.:0:%x:%x=%x:%x=%x:", ipmsg_attr, 
				IPMSG_FILE_MTIME, FileTime2UnixTime(&dat->ftLastWriteTime), 
				IPMSG_FILE_CREATETIME, FileTime2UnixTime(&dat->ftCreationTime)); 
	else 
		len = wsprintf(obj->header, "0000:.:0:%x:", ipmsg_attr); 
 
	obj->header[wsprintf(obj->header, "%04x", len)] = ':'; 
 
	return	len; 
} 
 
/* 
	ファイル送受信 
*/ 
BOOL TMainWin::SendDirFile(SendFileObj *obj) 
{ 
	BOOL	find = FALSE; 
 
	if (obj->status == FS_OPENINFO) 
	{ 
		char	buf[MAX_BUF]; 
		if (obj->dirCnt == 0) 
			strncpyz(buf, obj->fileInfo->Fname(), MAX_PATH); 
		else if (MakePath(buf, obj->path, *obj->fdata.cAlternateFileName ? obj->fdata.cAlternateFileName : obj->fdata.cFileName) >= MAX_PATH) 
			return	FALSE; 
		strncpyz(obj->path, buf, MAX_PATH); 
		obj->dirCnt++; 
		obj->status = FS_FIRSTINFO; 
	} 
 
	if (obj->status == FS_FIRSTINFO || obj->status == FS_NEXTINFO) 
	{ 
		if (obj->status == FS_FIRSTINFO) 
		{ 
			char	buf[MAX_BUF]; 
			MakePath(buf, obj->path, "*"); 
			find = (obj->hDir[obj->dirCnt -1] = ::FindFirstFile(buf, &obj->fdata)) == INVALID_HANDLE_VALUE ? FALSE : TRUE; 
		} 
		else find = ::FindNextFile(obj->hDir[obj->dirCnt -1], &obj->fdata); 
 
		while (find && (strcmp(obj->fdata.cFileName, ".") == 0 || strcmp(obj->fdata.cFileName, "..") == 0)) 
			find = ::FindNextFile(obj->hDir[obj->dirCnt -1], &obj->fdata); 
		obj->status = FS_MAKEINFO; 
	} 
 
	if (obj->status == FS_DIRFILESTART || obj->status == FS_MAKEINFO) 
	{ 
		if (obj->status == FS_DIRFILESTART) 
			find = TRUE; 
		if (find && (obj->dirCnt > 0 || obj->isDir == FALSE) && (obj->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) 
		{ 
			char	buf[MAX_BUF]; 
			int		len = MakePath(buf, obj->path, *obj->fdata.cAlternateFileName ? obj->fdata.cAlternateFileName : obj->fdata.cFileName); 
			BOOL	modifyCheck = (cfg->fileTransOpt & FT_STRICTDATE) && *(_int64 *)&obj->fdata.ftLastWriteTime > *(_int64 *)&obj->attachTime; 
			if (len >= MAX_PATH || modifyCheck || OpenSendFile(buf, obj) == FALSE) 
			{ 
				len = strlen(obj->fdata.cFileName); 
				strncpyz(obj->fdata.cFileName + len, " (Can't open)", MAX_PATH - len); 
				obj->fdata.nFileSizeHigh = obj->fdata.nFileSizeLow = 0; 
			} 
		} 
		if (find == FALSE && obj->isDir) 
			GetFileInfomation(obj->path, &obj->fdata); 
 
		obj->headerOffset = 0; 
		obj->headerLen = MakeDirHeader(obj, find); 
		if (find == FALSE) 
		{ 
			if (--obj->dirCnt >= 0 && obj->isDir) 
			{ 
				::FindClose(obj->hDir[obj->dirCnt]); 
				if (PathToDir(obj->path, obj->path) != TRUE && obj->dirCnt > 0) 
					return	FALSE; 
			} 
			if (obj->dirCnt <= 0) 
				obj->dirCnt--;	// 終了 
		} 
		obj->status = FS_TRANSINFO; 
	} 
 
	if (obj->status == FS_TRANSINFO) 
	{ 
		int	size = ::send(obj->conInfo->sd, obj->header + obj->headerOffset, obj->headerLen - obj->headerOffset, 0); 
		if (size < 0) 
			return	FALSE; 
		else { 
			if ((obj->headerOffset += size) < obj->headerLen) 
				return	TRUE; 
			obj->status = obj->dirCnt < 0 ? FS_COMPLETE : find == FALSE ? FS_NEXTINFO : (obj->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FS_OPENINFO : FS_TRANSFILE; 
		} 
	} 
 
	if (obj->status == FS_TRANSFILE) 
	{ 
		if (obj->mapAddr && SendFile(obj) != TRUE) 
		{ 
			CloseSendFile(obj); 
			return	FALSE; 
		} 
		else if (obj->mapAddr == NULL || obj->status == FS_ENDFILE) 
		{ 
			CloseSendFile(obj); 
			obj->status = obj->isDir ? FS_NEXTINFO : FS_MAKEINFO; 
		} 
	} 
	return	TRUE; 
} 
 
/* 
	ファイル送受信 
*/ 
BOOL TMainWin::SendFile(SendFileObj *obj) 
{ 
	if (obj == NULL || obj->hFile == INVALID_HANDLE_VALUE) 
		return	FALSE; 
 
	int		size = 0; 
	_int64	remain = obj->fileSize - obj->offset; 
 
	if (remain > 0 && (size = ::send(obj->conInfo->sd, obj->mapAddr + (obj->offset % cfg->ViewMax), remain > cfg->TransMax ? cfg->TransMax : (int)remain, 0)) < 0) 
		return	FALSE; 
 
	obj->offset += size; 
 
	if (obj->offset == obj->fileSize) 
		obj->status = obj->command == IPMSG_GETDIRFILES ? FS_ENDFILE : FS_COMPLETE; 
	else if ((obj->offset % cfg->ViewMax) == 0)	// 再マップの必要 
	{ 
		::UnmapViewOfFile(obj->mapAddr); 
		remain = obj->fileSize - obj->offset; 
		obj->mapAddr = (char *)::MapViewOfFile(obj->hMap, FILE_MAP_READ, (int)(obj->offset >> 32), (int)obj->offset, (int)(remain > cfg->ViewMax ? cfg->ViewMax : remain)); 
	} 
 
	obj->conInfo->lastTick = ::GetTickCount(); 
 
	return	TRUE; 
} 
 
BOOL TMainWin::EndSendFile(SendFileObj *obj) 
{ 
	if (obj == NULL) 
		return	FALSE; 
 
	if (obj->hThread) 
	{ 
		HANDLE	hThread = obj->hThread; 
		obj->hThread = 0;	// 中断の合図 
		::WaitForSingleObject(hThread, INFINITE); 
		::CloseHandle(hThread); 
	} 
	if (::closesocket(obj->conInfo->sd) != 0) 
		obj->status = FS_ERROR;	// error 扱いにする 
 
	CloseSendFile(obj); 
 
	if (obj->isDir) 
		free(obj->hDir); 
 
	shareMng->EndHostShare(obj->packetNo, &obj->host->hostSub, obj->fileInfo, obj->status == FS_COMPLETE ? TRUE : FALSE); 
	sendFileList.DelObj(obj); 
	delete obj->conInfo; 
	delete obj; 
	return	TRUE; 
} 
 
/* 
	Entry Packet受信処理 
*/ 
void TMainWin::MsgBrEntry(MsgBuf *msg) 
{ 
	AddrObj *obj = (AddrObj *)ansList->GetObj(FREE_LIST); 
	if (obj) { 
		obj->addr = msg->hostSub.addr; 
		obj->portNo = msg->hostSub.portNo; 
		ansList->PutObj(USED_LIST, obj); 
	} 
	if (obj == NULL || SetAnswerQueue(obj) != TRUE) 
		msgMng->Send(&msg->hostSub, IPMSG_ANSENTRY|HostStatus(), GetNickNameEx(), cfg->GroupNameStr); 
 
	AddHost(&msg->hostSub, msg->command, msg->msgBuf, msg->msgBuf + msg->exOffset); 
} 
 
BOOL TMainWin::SetAnswerQueue(AddrObj *obj) 
{ 
	if (ansTimerID) 
		return	TRUE; 
 
	int		hostCnt = hosts.HostCnt(), spawn; 
 
	if (hostCnt < 50 || ((msgMng->GetLocalHost()->addr ^ obj->addr) << 8) == 0) 
		spawn = 1023 & rand(); 
	else if (hostCnt < 300) 
		spawn = 2047 & rand(); 
	else 
		spawn = 4095 & rand(); 
 
	if ((ansTimerID = ::SetTimer(hWnd, IPMSG_ANS_TIMER, spawn, NULL)) == 0) 
		return	FALSE; 
 
	return	TRUE; 
} 
 
void TMainWin::ExecuteAnsQueue(void) 
{ 
	AddrObj *obj; 
 
	while ((obj = (AddrObj *)ansList->GetObj(USED_LIST)) != NULL) { 
		msgMng->Send(obj->addr, obj->portNo, IPMSG_ANSENTRY|HostStatus(), GetNickNameEx(), cfg->GroupNameStr); 
		ansList->PutObj(FREE_LIST, obj); 
	} 
} 
 
/* 
	Exit Packet受信処理 
*/ 
void TMainWin::MsgBrExit(MsgBuf *msg) 
{ 
	Host *host = cfg->priorityHosts.GetHostByName(&msg->hostSub); 
	if (host != NULL) 
		host->updateTime = Time(); 
	DelHost(&msg->hostSub); 
 
	for (ShareInfo *info=shareMng->Top(),*next; info; info = next) 
	{ 
		next = shareMng->Next(info); 
		shareMng->EndHostShare(info->packetNo, &msg->hostSub); 
	} 
} 
 
/* 
	AnsEntry Packet受信処理 
*/ 
void TMainWin::MsgAnsEntry(MsgBuf *msg) 
{ 
	AddHost(&msg->hostSub, msg->command, msg->msgBuf, msg->msgBuf + msg->exOffset); 
} 
 
/* 
	Absence Packet受信処理 
*/ 
void TMainWin::MsgBrAbsence(MsgBuf *msg) 
{ 
	AddHost(&msg->hostSub, msg->command, msg->msgBuf, msg->msgBuf + msg->exOffset); 
} 
 
/* 
	Send Packet受信処理 
*/ 
void TMainWin::MsgSendMsg(MsgBuf *msg) 
{ 
	TRecvDlg	*recvDlg; 
 
	if (TRecvDlg::GetCreateCnt() >= cfg->RecvMax) 
		return; 
 
	for (recvDlg = (TRecvDlg *)recvList.TopObj(); recvDlg != NULL; recvDlg = (TRecvDlg *)recvList.NextObj(recvDlg)) 
		if (recvDlg->IsSamePacket(msg)) 
			break; 
 
	if (recvDlg != NULL || IsLastPacket(msg)) 
	{ 
		if ((msg->command & IPMSG_SENDCHECKOPT) != 0 && (msg->command & (IPMSG_BROADCASTOPT | IPMSG_AUTORETOPT)) == 0) 
			msgMng->Send(&msg->hostSub, IPMSG_RECVMSG, msg->packetNo); 
		return; 
	} 
 
	if ((msg->command & IPMSG_BROADCASTOPT) == 0 && (msg->command & IPMSG_AUTORETOPT) == 0) 
	{ 
		if ((msg->command & IPMSG_SENDCHECKOPT) != 0) 
			msgMng->Send(&msg->hostSub, IPMSG_RECVMSG, msg->packetNo); 
 
		if (cfg->AbsenceCheck == TRUE && *cfg->AbsenceStr[cfg->AbsenceChoice]) 
			msgMng->Send(&msg->hostSub, IPMSG_SENDMSG|IPMSG_AUTORETOPT, cfg->AbsenceStr[cfg->AbsenceChoice]); 
		if ((msg->command & IPMSG_NOADDLISTOPT) == 0 && hosts.GetHostByAddr(&msg->hostSub) == NULL) 
			BroadcastEntrySub(&msg->hostSub, IPMSG_BR_ENTRY); 
	} 
	RecvDlgOpen(msg); 
} 
 
/* 
	Recv Packet受信処理 
*/ 
void TMainWin::MsgRecvMsg(MsgBuf *msg) 
{ 
	MsgInfoSub(msg); 
} 
 
/* 
	Read Packet受信処理 
*/ 
void TMainWin::MsgReadMsg(MsgBuf *msg) 
{ 
	MsgInfoSub(msg); 
} 
 
/* 
	HostList 送出可能問合せ Packet受信処理 
*/ 
void TMainWin::MsgBrIsGetList(MsgBuf *msg) 
{ 
	if (cfg->AllowSendList 
		&& (entryStartTime + ((ULONG)cfg->ListGetMSec / 1000) < (ULONG)Time()) 
			&& (cfg->ListGet == FALSE || (IPMSG_RETRYOPT & msg->command))) 
		msgMng->Send(&msg->hostSub, IPMSG_OKGETLIST); 
} 
 
/* 
	HostList 送出可能通知 Packet受信処理 
*/ 
void TMainWin::MsgOkGetList(MsgBuf *msg) 
{ 
	if (entryStartTime != IPMSG_GETLIST_FINISH) 
		msgMng->Send(&msg->hostSub, IPMSG_GETLIST); 
} 
 
/* 
	HostList 送出要求 Packet受信処理 
*/ 
void TMainWin::MsgGetList(MsgBuf *msg) 
{ 
	if (cfg->AllowSendList) 
		SendHostList(msg); 
} 
 
/* 
	HostList 送出 Packet受信処理 
*/ 
void TMainWin::MsgAnsList(MsgBuf *msg) 
{ 
	if (entryStartTime != IPMSG_GETLIST_FINISH) 
		AddHostList(msg); 
} 
 
/* 
	Version Information 要求 Packet受信処理 
*/ 
void TMainWin::MsgGetInfo(MsgBuf *msg) 
{ 
	char	buf[MAX_LISTBUF]; 
 
	wsprintf(buf, WIN32EDITION_MSGSTR, GetVerionStr()); 
	msgMng->Send(&msg->hostSub, IPMSG_SENDINFO, buf); 
} 
 
/* 
	Version Information 通知 Packet受信処理 
*/ 
void TMainWin::MsgSendInfo(MsgBuf *msg) 
{ 
	MsgInfoSub(msg); 
} 
 
/* 
	Public Key 要求 Packet受信処理 
*/ 
void TMainWin::MsgGetPubKey(MsgBuf *msg) 
{ 
	int		capa = strtoul(msg->msgBuf, 0, 16); 
 
	if ((capa &= cfg->smallPubKey.Capa()) == 0) 
		return; 
 
	PubKey	*pubKey = (capa & IPMSG_RSA_1024) ? &cfg->pubKey : &cfg->smallPubKey; 
 
	char	buf[MAX_BUF]; 
	wsprintf(buf, "%X:%X-", cfg->smallPubKey.Capa(), pubKey->Exponent()); 
	bin2hexstr_bigendian(pubKey->Key(), pubKey->KeyLen(), buf + strlen(buf)); 
	msgMng->Send(&msg->hostSub, IPMSG_ANSPUBKEY, buf); 
} 
 
/* 
	Public Key 送信 Packet受信処理 
*/ 
void TMainWin::MsgAnsPubKey(MsgBuf *msg) 
{ 
	if (cfg->pubKey.Key() == NULL && cfg->smallPubKey.Key() == NULL) 
		return; 
 
	BYTE	key[MAX_BUF]; 
	int		key_len, e, capa; 
	char	*capa_hex, *e_hex, *key_hex, *p; 
 
	if ((capa_hex = separate_token(msg->msgBuf, ':', &p)) == NULL) 
		return; 
	if ((e_hex = separate_token(NULL, '-', &p)) == NULL) 
		return; 
	if ((key_hex = separate_token(NULL, ':', &p)) == NULL) 
		return; 
 
	capa = strtoul(capa_hex, 0, 16); 
	e = strtoul(e_hex, 0, 16); 
	hexstr2bin_bigendian(key_hex, key, sizeof(key), &key_len); 
 
	for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
		if (sendDlg->SendPubKeyNotify(&msg->hostSub, key, key_len, e, capa)) 
			break; 
} 
 
/* 
	Information 通知処理 
*/ 
void TMainWin::MsgInfoSub(MsgBuf *msg) 
{ 
	int		cmd = GET_MODE(msg->command); 
 
	if (cmd == IPMSG_READMSG) 
	{ 
		if (GET_OPT(msg->command) & IPMSG_READCHECKOPT) 
			msgMng->Send(&msg->hostSub, IPMSG_ANSREADMSG, msg->packetNo); 
	} 
	else { 
		long	packet_no = (cmd == IPMSG_RECVMSG || cmd == IPMSG_ANSREADMSG) ? atol(msg->msgBuf) : 0; 
 
		if (cmd == IPMSG_ANSREADMSG) { 
			for (TRecvDlg *recvDlg = (TRecvDlg *)recvList.TopObj(); recvDlg != NULL; recvDlg = (TRecvDlg *)recvList.NextObj(recvDlg)) 
				if (recvDlg->SendFinishNotify(&msg->hostSub, packet_no)) 
					break; 
			return; 
		} 
		for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
			if (sendDlg->SendFinishNotify(&msg->hostSub, packet_no)) 
				break; 
		if (sendDlg == NULL) 
			return; 
	} 
	if (IsLastPacket(msg))		//重複チェック 
		return; 
 
	char	title[MAX_LISTBUF], *msg_text = msg->msgBuf, *p; 
	int		show_mode = cfg->MsgMinimize ? SW_MINIMIZE : SW_SHOW; 
	MakeListString(cfg, &msg->hostSub, &hosts, title); 
	separate_token(title, '(', &p); 
 
	switch (cmd) 
	{ 
	case IPMSG_READMSG: 
		if (cfg->OpenCheck == FALSE) 
			return; 
		{ 
			char	*str = Ctime(); 
			str = separate_token(str, ' ', &p); 
			str = separate_token(NULL, 0, &p); 
			*strrchr(str, ':') = 0; 
			wsprintf(msg_text, "%s\r\n(%s)", OPENFIN_MSGSTR, str); 
		} 
		break; 
 
	case IPMSG_SENDINFO: 
	case IPMSG_SENDABSENCEINFO: 
		show_mode = SW_SHOW; 
		break; 
 
	default: 
		return; 
	} 
 
	if (cmd == IPMSG_SENDABSENCEINFO) {	//将来的には TMsgDlgで処理 
		static int msg_cnt = 0;	// TMsgDlg 化した後は TMsgDlg::createCnt に移行 
		if (msg_cnt >= cfg->RecvMax) 
			return; 
		msg_cnt++; 
		MessageBox(msg_text, title); 
		msg_cnt--; 
	} 
	else { 
		if (TMsgDlg::GetCreateCnt() >= cfg->RecvMax * 4) 
			return; 
		TMsgDlg	*msgDlg = new TMsgDlg(IsNewShell() ? this : 0); 
		msgDlg->Create(msg_text, title, show_mode); 
		if (cmd == IPMSG_SENDINFO || cmd == IPMSG_SENDABSENCEINFO) 
			ActiveDlg(msgDlg); 
		msgList.AddObj(msgDlg); 
	} 
} 
 
/* 
	不在通知 Information 要求 Packet受信処理 
*/ 
void TMainWin::MsgGetAbsenceInfo(MsgBuf *msg) 
{ 
	msgMng->Send(&msg->hostSub, IPMSG_SENDABSENCEINFO, cfg->AbsenceCheck ? cfg->AbsenceStr[cfg->AbsenceChoice] : NOTABSENCE_MSGSTR); 
} 
 
/* 
	不在通知 Information 通知 Packet受信処理 
*/ 
void TMainWin::MsgSendAbsenceInfo(MsgBuf *msg) 
{ 
	MsgInfoSub(msg); 
} 
 
/* 
	添付ファイル破棄通知 Packet受信処理 
*/ 
void TMainWin::MsgReleaseFiles(MsgBuf *msg) 
{ 
	int	packet_no = atoi(msg->msgBuf); 
 
	shareMng->EndHostShare(packet_no, &msg->hostSub); 
} 
 
/* 
	送信Dialog生成。ただし、同一の迎撃送信Dialogが開いている場合は、 
	そのDialogを Activeにするのみ。 
*/ 
BOOL TMainWin::SendDlgOpen(HWND hRecvWnd, MsgBuf *msg) 
{ 
	TSendDlg *sendDlg; 
 
	if (hRecvWnd) 
	{ 
		for (sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
			if (sendDlg->GetRecvWnd() == hRecvWnd && sendDlg->IsSending() != TRUE) 
				return	ActiveDlg(sendDlg), TRUE; 
	} 
 
	if ((sendDlg = new TSendDlg(msgMng, shareMng, &hosts, cfg, logmng, hRecvWnd, msg)) == NULL) 
		return	FALSE; 
 
	sendList.AddObj(sendDlg); 
	sendDlg->Create(), sendDlg->Show(); 
	ControlIME(sendDlg, TRUE); 
 
// test 
	if (hosts.HostCnt() == 0 && cfg->ListGet == FALSE) 
		BroadcastEntrySub(inet_addr("127.0.0.1"), htons(portNo), IPMSG_BR_ENTRY); 
 
	return	TRUE; 
} 
 
/* 
	送信Dialog Hide通知(WM_SENDDLG_HIDE)処理。 
	伝えてきた送信Dialogに対応する、受信Dialogを破棄 
*/ 
void TMainWin::SendDlgHide(TSendDlg *sendDlg) 
{ 
	ControlIME(sendDlg, FALSE); 
 
	if (sendDlg->GetRecvWnd() && cfg->NoErase == FALSE) 
	{ 
		TRecvDlg *recvDlg; 
 
		for (recvDlg = (TRecvDlg *)recvList.TopObj(); recvDlg != NULL; recvDlg = (TRecvDlg *)recvList.NextObj(recvDlg)) 
		{ 
			if (recvDlg->hWnd == sendDlg->GetRecvWnd() && recvDlg->IsClosable()) 
			{ 
				recvDlg->EvCommand(0, IDCANCEL, 0); 
				break; 
			} 
		} 
	} 
} 
 
/* 
	送信Dialog Exit通知(WM_SENDDLG_EXIT)処理。 
	伝えてきた送信Dialog および対応する受信Dialogの破棄 
*/ 
void TMainWin::SendDlgExit(TSendDlg *sendDlg) 
{ 
	if (sendDlg->IsSending() == FALSE)	// 送信中の場合は HIDE で実行済み 
		ControlIME(sendDlg, FALSE); 
	sendList.DelObj(sendDlg); 
	delete sendDlg; 
} 
 
/* 
	受信Dialogを生成 
*/ 
BOOL TMainWin::RecvDlgOpen(MsgBuf *msg) 
{ 
	TRecvDlg *recvDlg; 
 
	if ((recvDlg = new TRecvDlg(msgMng, msg, &hosts, cfg, logmng)) == NULL) 
		return	FALSE; 
	if (recvDlg->Status() == FALSE)		// 暗号文の復号に失敗した 
	{ 
		delete recvDlg; 
		return	FALSE; 
	} 
 
	recvList.AddObj(recvDlg); 
 
	if (cfg->NoBeep == FALSE) 
	{ 
		char	*soundFile = cfg->SoundFile; 
#if 0 
		Host	*host = hosts.GetHostByAddr(&msg->hostSub); 
 
		if (host) 
		{ 
			int priorityLevel = (host->priority - DEFAULT_PRIORITY) / PRIORITY_OFFSET; 
 
			if (priorityLevel >= 0 && priorityLevel < cfg->PriorityMax) 
			{ 
				if (cfg->PrioritySound[priorityLevel]) 
					soundFile = cfg->PrioritySound[priorityLevel]; 
			} 
		} 
#endif 
		if (*soundFile == '\0' || PlaySound(soundFile, 0, SND_FILENAME|SND_ASYNC) != TRUE) 
			if (MessageBeep(MB_OK) != TRUE) 
				MessageBeep((UINT)~0); 
	} 
 
	if (cfg->NoPopupCheck || (cfg->AbsenceNonPopup && cfg->AbsenceCheck)) 
	{ 
		if (reverseTimerStatus == 0) 
		{ 
			ReverseIcon(TRUE); 
			if (::SetTimer(hWnd, IPMSG_REVERSEICON, IPMSG_TIMERINTERVAL, NULL)) 
				reverseTimerStatus = IPMSG_REVERSEICON; 
		} 
	} 
	else { 
		recvDlg->Create(); 
		recvDlg->Show(); 
		recvDlg->SetForceForegroundWindow(); 
	} 
 
	return	TRUE; 
} 
 
/* 
	受信Dialogを破棄 
*/ 
void TMainWin::RecvDlgExit(TRecvDlg *recvDlg) 
{ 
	recvList.DelObj(recvDlg); 
	delete recvDlg; 
} 
 
/* 
	確認Dialogを破棄 
*/ 
void TMainWin::MsgDlgExit(TMsgDlg *msgDlg) 
{ 
	msgList.DelObj(msgDlg); 
	delete msgDlg; 
} 
 
/* 
	Setup/About/Absence Dialogを生成 
*/ 
void TMainWin::MiscDlgOpen(TDlg *dlg) 
{ 
	if (dlg->hWnd == NULL) 
		dlg->Create(), dlg->Show(); 
	else 
		ActiveDlg(dlg); 
} 
 
/* 
	TaskTrayに指定iconを登録 
*/ 
BOOL TMainWin::TaskBar(int nimMode, HICON hSetIcon, LPCSTR tip) 
{ 
	NOTIFYICONDATA	tn; 
 
	memset(&tn, 0, sizeof(tn)); 
	tn.cbSize = sizeof(tn); 
	tn.hWnd = hWnd; 
	tn.uID = IPMSG_DEFAULT_PORT;		// test 
	tn.uFlags = NIF_MESSAGE|(hSetIcon ? NIF_ICON : 0)|(tip ? NIF_TIP : 0); 
	tn.uCallbackMessage = WM_IPMSG_NOTIFY; 
	tn.hIcon = hSetIcon; 
	if (tip) 
		strcpy(tn.szTip, tip); 
 
	return	Shell_NotifyIcon(nimMode, &tn); 
} 
 
/* 
	MainWindow or TaskTray Icon を clickした時の Popup Menu生成 
*/ 
void TMainWin::Popup(UINT resId) 
{ 
	HMENU	hMenu = ::LoadMenu(TApp::hI, (LPCSTR)resId); 
	HMENU	hSubMenu = ::GetSubMenu(hMenu, 0);	//かならず、最初の項目に定義 
 
	if (hMenu == NULL || hSubMenu == NULL) 
		return; 
 
	ShareCntInfo	info; 
	shareMng->GetShareCntInfo(&info); 
 
	char	buf[MAX_LISTBUF] = DOWNLOAD_MSGSTR; 
	if (info.packetCnt) 
		wsprintf(buf + strlen(buf), "(%d/%d)", info.fileCnt, info.transferCnt); 
	::InsertMenu(hSubMenu, 0, MF_BYPOSITION|MF_SEPARATOR, NULL, NULL); 
	::InsertMenu(hSubMenu, 0, MF_BYPOSITION|MF_STRING, MENU_SHARE, buf); 
 
	AddAbsenceMenu(hSubMenu, 2); 
 
	DWORD	pos = ::GetMessagePos(); 
 
	SetForegroundWindow();		//とっても大事! 
 
	::TrackPopupMenu(hSubMenu, TPM_RIGHTBUTTON, LOWORD(pos), HIWORD(pos), 0, hWnd, NULL); 
 
	::DestroyMenu(hMenu); 
} 
 
/* 
	NonPopup状態になっていた受信Dialogがあれば、出現させる 
*/ 
BOOL TMainWin::PopupCheck(void) 
{ 
	BOOL		result = FALSE;  
	TRecvDlg	*recvDlg; 
 
	for (recvDlg = (TRecvDlg *)recvList.TopObj(); recvDlg != NULL; recvDlg = (TRecvDlg *)recvList.NextObj(recvDlg)) 
	{ 
		if (recvDlg->hWnd == 0) 
		{ 
			recvDlg->Create(), recvDlg->Show(); 
			result = TRUE; 
		} 
	} 
 
	if (result == TRUE) 
	{ 
		::KillTimer(hWnd, IPMSG_REVERSEICON); 
		reverseTimerStatus = 0; 
		SetIcon(cfg->AbsenceCheck == FALSE ? hMainIcon : hRevIcon); 
	} 
 
	return	result; 
} 
 
/* 
	全Windowを前面にもってくる。hide == TRUEの場合、全Windowを hideに 
*/ 
void TMainWin::ActiveChildWindow(BOOL active) 
{ 
	ActiveDlg(aboutDlg, active); 
	ActiveDlg(setupDlg, active); 
	ActiveDlg(absenceDlg, active); 
	ActiveDlg(shareStatDlg, active); 
	ActiveListDlg(&recvList, active); 
	ActiveListDlg(&sendList, active); 
	ActiveListDlg(&msgList, active); 
 
	if (active == FALSE) 
		SetForegroundWindow(); 
} 
 
/* 
	HostDataのcopy 
*/ 
inline void TMainWin::SetHostData(Host *destHost, HostSub *hostSub, ULONG command, time_t update_time, char *nickName, char *groupName, int priority) 
{ 
	destHost->hostStatus = GET_OPT(command); 
	destHost->hostSub = *hostSub; 
	destHost->updateTime = update_time; 
	destHost->priority = priority; 
	strncpyz(destHost->nickName, nickName, sizeof(destHost->nickName)); 
	strncpyz(destHost->groupName, groupName, sizeof(destHost->groupName)); 
} 
 
/* 
	Host追加処理 
*/ 
void TMainWin::AddHost(HostSub *hostSub, ULONG command, char *nickName, char *groupName) 
{ 
	Host	*host, *tmp_host, *priorityHost; 
	time_t	now_time = Time(); 
	int		priority = DEFAULT_PRIORITY; 
 
	if (GET_MODE(command) == IPMSG_BR_ENTRY && (command & IPMSG_DIALUPOPT) && !IsSameHost(hostSub, msgMng->GetLocalHost())) 
	{ 
		for (AddrObj *obj = (AddrObj *)cfg->DialUpList.TopObj(); obj != NULL; obj = (AddrObj *)cfg->DialUpList.NextObj(obj)) 
			if (obj->addr == hostSub->addr && obj->portNo == hostSub->portNo) 
				break; 
 
		if (obj == NULL) 
		{ 
			obj = new AddrObj; 
			obj->addr	= hostSub->addr; 
			obj->portNo	= hostSub->portNo; 
			cfg->DialUpList.AddObj(obj); 
		} 
	} 
 
	if ((priorityHost = cfg->priorityHosts.GetHostByName(hostSub)) != NULL) 
	{ 
		priority = priorityHost->priority; 
//		command |= priorityHost->hostStatus & IPMSG_ENCRYPTOPT; 
	} 
 
	if ((host = hosts.GetHostByName(hostSub)) != NULL) 
	{ 
		if (host->hostSub.addr != hostSub->addr || host->hostSub.portNo != hostSub->portNo) 
		{ 
			if ((tmp_host = hosts.GetHostByAddr(hostSub)) != NULL) 
			{ 
				for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
					sendDlg->DelHost(tmp_host); 
				hosts.DelHost(tmp_host); 
				if (tmp_host->RefCnt() == 0) 
					delete tmp_host; 
			} 
			hosts.DelHost(host); 
			host->hostSub.addr = hostSub->addr; 
			host->hostSub.portNo = hostSub->portNo; 
			hosts.AddHost(host); 
		} 
		if (((command ^ host->hostStatus) & (IPMSG_ABSENCEOPT|IPMSG_FILEATTACHOPT|IPMSG_ENCRYPTOPT)) || strcmp(host->nickName, nickName) || strcmp(host->groupName, groupName)) 
		{ 
			SetHostData(host, hostSub, command, now_time, nickName, groupName, priority); 
			for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
				sendDlg->ModifyHost(host); 
		} 
		else { 
			host->hostStatus = GET_OPT(command); 
			host->updateTime = now_time; 
		} 
		return; 
	} 
 
	if ((host = hosts.GetHostByAddr(hostSub)) != NULL) 
	{ 
		for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
			sendDlg->DelHost(host); 
		hosts.DelHost(host); 
		if (host->RefCnt() == 0) 
			delete host; 
	} 
 
	if ((host = priorityHost) == NULL) 
		host = new Host; 
 
	SetHostData(host, hostSub, command, now_time, nickName, groupName, priority); 
	hosts.AddHost(host); 
//	if (priorityHost == NULL) 
//		cfg->priorityHosts.AddHost(host); 
 
	SetCaption(); 
 
	for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
		sendDlg->AddHost(host); 
} 
 
/* 
	全Hostの削除処理 
*/ 
void TMainWin::DelAllHost(void) 
{ 
	for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
		sendDlg->DelAllHost(); 
 
	while (hosts.HostCnt() > 0) 
		DelHostSub(hosts.GetHost(0)); 
} 
 
/* 
	特定Hostの削除処理 
*/ 
void TMainWin::DelHost(HostSub *hostSub) 
{ 
	Host *host; 
 
	if ((host = hosts.GetHostByAddr(hostSub)) != NULL) 
		DelHostSub(host); 
} 
 
/* 
	特定Hostの削除処理Sub 
*/ 
void TMainWin::DelHostSub(Host *host) 
{ 
	for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
		sendDlg->DelHost(host); 
 
	for (AddrObj *obj = (AddrObj *)cfg->DialUpList.TopObj(); obj != NULL; obj = (AddrObj *)cfg->DialUpList.NextObj(obj)) 
	{ 
		if (obj->addr == host->hostSub.addr && obj->portNo == host->hostSub.portNo) 
		{ 
			cfg->DialUpList.DelObj(obj); 
			delete obj; 
			break; 
		} 
	} 
	hosts.DelHost(host); 
	if (host->RefCnt() == 0) 
		delete host; 
	else if (host->pubKey.Key()) 
		host->pubKey.UnSet(); 
	SetCaption(); 
} 
 
/* 
	更新Button用処理。所有HostListの削除、および再Entry Packet送出。 
	なお、unRemoveFlg == TRUEの場合は、削除処理を行わない 
*/ 
void TMainWin::RefreshHost(BOOL unRemoveFlg) 
{ 
	time_t	now_time = Time(); 
 
	if (cfg->ListGet == TRUE && entryTimerStatus != 0 || refreshStartTime + IPMSG_ENTRYMINSEC >= now_time) 
		return; 
 
	if (unRemoveFlg != TRUE) 
	{ 
		if (cfg->UpdateTime == 0 || refreshStartTime + cfg->UpdateTime < now_time) { 
			DelAllHost(); 
		} 
		else { 
			for (int cnt=0; cnt < hosts.HostCnt(); ) 
			{ 
				if (hosts.GetHost(cnt)->updateTime + cfg->UpdateTime < now_time) 
					DelHostSub(hosts.GetHost(cnt)); 
				else 
					cnt++; 
			} 
		} 
	} 
	refreshStartTime = now_time; 
	EntryHost(); 
} 
 
/* 
	Main Window or TaskTray用 Captionの設定 
*/ 
void TMainWin::SetCaption(void) 
{ 
	char	buf[MAX_LISTBUF]; 
 
	wsprintf(buf, "IPMsg(%d)", hosts.HostCnt()); 
 
	if (IsNewShell()) 
		TaskBar(NIM_MODIFY, NULL, buf); 
	else 
		::SetWindowText(hWnd, buf); 
} 
 
/* 
	IPMSG_ENTRY/IPMSG_EXIT/IPMSG_ABSENCEパケット送出 
*/ 
void TMainWin::BroadcastEntry(ULONG mode) 
{ 
	for (TBroadcastObj *brobj=cfg->broadcastList.Top(); brobj; brobj=cfg->broadcastList.Next(brobj)) 
		BroadcastEntrySub(brobj->Addr(cfg->ResolveOpt & RS_REALTIME), htons(portNo), IPMSG_NOOPERATION); 
	BroadcastEntrySub((ULONG)~0, htons(portNo), IPMSG_NOOPERATION); 
 
	this->Sleep(cfg->DelayTime); 
 
	UINT host_status = mode | HostStatus(); 
 
	msgMng->Send((ULONG)~0, htons(portNo), host_status, GetNickNameEx(), cfg->GroupNameStr);	// local network broadcast 
 
	for (brobj=cfg->broadcastList.Top(); brobj; brobj=cfg->broadcastList.Next(brobj)) 
		BroadcastEntrySub(brobj->Addr(), htons(portNo), host_status); 
 
	for (AddrObj *obj = (AddrObj *)cfg->DialUpList.TopObj(); obj != NULL; obj = (AddrObj *)cfg->DialUpList.NextObj(obj)) 
		BroadcastEntrySub(obj->addr, obj->portNo, host_status); 
 
	if (mode == IPMSG_BR_ENTRY && cfg->ExtendEntry) 
		::SetTimer(hWnd, IPMSG_ENTRY_TIMER, IPMSG_ENTRYMINSEC * 1000, NULL); 
} 
 
/* 
	IPMSG_ENTRY/IPMSG_EXIT/IPMSG_ABSENCEパケット送出Sub 
*/ 
void TMainWin::BroadcastEntrySub(ULONG addr, int port_no, ULONG mode) 
{ 
	if (addr == 0) 
		return; 
 
	HostSub	hostSub; 
 
	hostSub.addr 	= addr; 
	hostSub.portNo	= port_no; 
 
	BroadcastEntrySub(&hostSub, mode); 
} 
 
void TMainWin::BroadcastEntrySub(HostSub *hostSub, ULONG mode) 
{ 
	if (mode == IPMSG_NOOPERATION) 
		msgMng->Send(hostSub, mode); 
	else 
		msgMng->Send(hostSub, mode | (cfg->DialUpCheck ? IPMSG_DIALUPOPT : 0) | HostStatus(), GetNickNameEx(),  cfg->GroupNameStr); 
} 
 
/* 
	icon 反転処理。startFlg == TRUEの場合、逆iconに Resetされる 
*/ 
void TMainWin::ReverseIcon(BOOL startFlg) 
{ 
	static	cnt = 0; 
 
	if (startFlg) 
		cnt = 0; 
 
	SetIcon(cnt++ % 2 ? hMainIcon : hRevIcon); 
} 
 
/* 
	指定iconを MainWindow or TaskTray にセット 
*/ 
void TMainWin::SetIcon(HICON hSetIcon) 
{ 
	if (IsNewShell()) 
		TaskBar(NIM_MODIFY, hSetIcon); 
	else { 
		::SetClassLong(hWnd, GCL_HICON, (LONG)hSetIcon); 
		::FlashWindow(hWnd, FALSE); 
	} 
} 
 
/* 
	HostList送出処理 
	手抜き ... デリミタやデータがない場合に特殊文字('\a','\b')を使用 
*/ 
void TMainWin::SendHostList(MsgBuf *msg) 
{ 
	int		start_no, len, total_len = 0, host_cnt = 0; 
	char	*buf = new char [MAX_UDPBUF]; 
	char	tmp[MAX_BUF]; 
 
	if ((start_no = atoi(msg->msgBuf)) < 0) 
		start_no = 0; 
 
	total_len = wsprintf(buf, "%5d%c%5d%c", 0, HOSTLIST_SEPARATOR, 0, HOSTLIST_SEPARATOR); 
 
	for (int cnt=start_no; cnt < hosts.HostCnt(); cnt++) 
	{ 
		Host	*host = hosts.GetHost(cnt); 
		if ((len = wsprintf(tmp, "%s%c%s%c%ld%c%s%c%d%c%s%c%s%c", 
			host->hostSub.userName, HOSTLIST_SEPARATOR, 
			host->hostSub.hostName, HOSTLIST_SEPARATOR, 
			host->hostStatus, HOSTLIST_SEPARATOR, 
			inet_ntoa(*(LPIN_ADDR)&host->hostSub.addr), HOSTLIST_SEPARATOR, 
			host->hostSub.portNo, HOSTLIST_SEPARATOR, 
			*host->nickName ? host->nickName : HOSTLIST_DUMMY, HOSTLIST_SEPARATOR, 
			*host->groupName ? host->groupName : HOSTLIST_DUMMY, HOSTLIST_SEPARATOR 
			)) + total_len +80 >= MAX_UDPBUF)	// +80 : ipmsg protocol header reserve 
		{ 
			break; 
		} 
		memcpy(buf + total_len, tmp, len +1); 
		total_len += len; 
		host_cnt++; 
	} 
	len = wsprintf(tmp, "%5d%c%5d", start_no + host_cnt == hosts.HostCnt() ? 0 : start_no + host_cnt, HOSTLIST_SEPARATOR, host_cnt); 
	memcpy(buf, tmp, len); 
	msgMng->Send(&msg->hostSub, IPMSG_ANSLIST, buf); 
	delete [] buf; 
} 
 
/* 
	HostList受信処理 
*/ 
void TMainWin::AddHostList(MsgBuf *msg) 
{ 
	char	*tok, *nickName, *groupName, *p; 
	HostSub	hostSub; 
	ULONG	host_status; 
	int		total_num, continue_cnt; 
 
	if ((tok = separate_token(msg->msgBuf, HOSTLIST_SEPARATOR, &p)) == NULL) 
		return; 
	continue_cnt = atoi(tok); 
 
	if ((tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
		return; 
	total_num = atoi(tok); 
 
	for (int host_cnt=0; (tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) != NULL; host_cnt++) 
	{ 
		nickName = groupName = NULL; 
		strncpyz(hostSub.userName, tok, sizeof(hostSub.userName)); 
 
		if ((tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		strncpyz(hostSub.hostName, tok, sizeof(hostSub.hostName)); 
 
		if ((tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		host_status = atol(tok); 
 
		if ((tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		hostSub.addr = inet_addr(tok); 
 
		if ((tok = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		hostSub.portNo = atoi(tok); 
 
		if ((nickName = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		if (strcmp(nickName, HOSTLIST_DUMMY) == 0) 
			nickName = ""; 
 
		if ((groupName = separate_token(NULL, HOSTLIST_SEPARATOR, &p)) == NULL) 
			break; 
		if (strcmp(groupName, HOSTLIST_DUMMY) == 0) 
			groupName = ""; 
 
		AddHost(&hostSub, IPMSG_BR_ENTRY|host_status, nickName, groupName); 
	} 
 
	if (continue_cnt || host_cnt < total_num) 
	{ 
		msgMng->Send(&msg->hostSub, IPMSG_GETLIST, abs(continue_cnt - (total_num - host_cnt))); 
		if (::SetTimer(hWnd, IPMSG_LISTGETRETRY_TIMER, cfg->ListGetMSec, NULL)) 
			entryTimerStatus = IPMSG_LISTGETRETRY_TIMER; 
	} 
	else { 
		entryStartTime = IPMSG_GETLIST_FINISH; 
		if (cfg->ListGet) 
			BroadcastEntry(IPMSG_BR_ENTRY); 
	} 
} 
 
/* 
	Logを開く 
*/ 
void TMainWin::LogOpen(void) 
{ 
	int		ret; 
 
	if ((ret = (int)ShellExecute(0, NULL, cfg->LogFile, NULL, NULL, SW_SHOW)) <= WINEXEC_ERR_MAX) 
	{ 
		switch (ret) 
		{ 
		case SE_ERR_NOASSOC: case SE_ERR_ASSOCINCOMPLETE: 
			MessageBox(FILEEXTERR_MSGSTR); 
			break; 
		default: 
			MessageBox(CANTOPENLOG_MSGSTR); 
			break; 
		} 
	} 
} 
 
/* 
	自Hostの Status (dialup mode / absence mode) 
*/ 
ULONG TMainWin::HostStatus(void) 
{ 
	return	(cfg->DialUpCheck ? IPMSG_DIALUPOPT : 0) | (cfg->AbsenceCheck ? IPMSG_ABSENCEOPT : 0) | (msgMng->IsAvailableTCP() ? IPMSG_FILEATTACHOPT : 0) | (cfg->pubKey.Key() || cfg->smallPubKey.Key() ? IPMSG_ENCRYPTOPT : 0); 
} 
 
/* 
	IPMSG用 icon初期化 
*/ 
void  TMainWin::InitIcon(void) 
{ 
	if (*cfg->IconFile == 0 || (hMainIcon = ::ExtractIcon(TApp::hI, cfg->IconFile, 0)) == NULL) 
		hMainIcon = ::LoadIcon(TApp::hI, (LPCSTR)IPMSG_ICON); 
	if (*cfg->RevIconFile == 0 || (hRevIcon = ::ExtractIcon(TApp::hI, cfg->RevIconFile, 0)) == NULL) 
		hRevIcon = ::LoadIcon(TApp::hI, (LPCSTR)RECV_ICON); 
} 
 
/* 
	MainWindow iconを教えてあげる。 
	この routineは static member function であり、SendDlgなどから呼ばれる。 
*/ 
HICON TMainWin::GetIPMsgIcon(void) 
{ 
	return	hMainIcon; 
} 
 
/* 
	ListDlg を Active or Hideに(単なる簡易ルーチン) 
*/ 
void TMainWin::ActiveListDlg(TList *list, BOOL active) 
{ 
	for (TListDlg *dlg = (TListDlg *)list->TopObj(); dlg != NULL; dlg = (TListDlg *)list->NextObj(dlg)) 
		ActiveDlg(dlg, active); 
} 
 
/* 
	ListDlg を Delete する(単なる簡易ルーチン) 
*/ 
void TMainWin::DeleteListDlg(TList *list) 
{ 
	TListDlg *dlg; 
 
	while ((dlg = (TListDlg *)list->TopObj()) != NULL) 
	{ 
		list->DelObj(dlg); 
		delete dlg; 
	} 
} 
 
/* 
	Dlg を Active or Hideに 
*/ 
void TMainWin::ActiveDlg(TDlg *dlg, BOOL active) 
{ 
	if (dlg->hWnd != 0) 
		active ? dlg->Show(), dlg->SetForegroundWindow() : dlg->Show(SW_HIDE); 
} 
 
/* 
	Extend NickName 
*/ 
char *TMainWin::GetNickNameEx(void) 
{ 
	static char buf[MAX_LISTBUF]; 
 
	if (cfg->AbsenceCheck && *cfg->AbsenceHead[cfg->AbsenceChoice]) 
		wsprintf(buf, "%s[%s]", *cfg->NickNameStr ? cfg->NickNameStr : msgMng->GetLocalHost()->userName, cfg->AbsenceHead[cfg->AbsenceChoice]); 
	else 
		strcpy(buf, *cfg->NickNameStr ? cfg->NickNameStr : msgMng->GetLocalHost()->userName); 
 
	return	buf; 
} 
 
/* VC4 で CryptoAPI を使用可能にする */ 
BOOL (WINAPI *pCryptAcquireContext)(HCRYPTPROV *, LPCSTR, LPCSTR, DWORD, DWORD); 
BOOL (WINAPI *pCryptDestroyKey)(HCRYPTKEY); 
BOOL (WINAPI *pCryptGetKeyParam)(HCRYPTKEY, DWORD, BYTE *, DWORD *, DWORD); 
BOOL (WINAPI *pCryptSetKeyParam)(HCRYPTKEY, DWORD, BYTE *, DWORD); 
BOOL (WINAPI *pCryptExportKey)(HCRYPTKEY, HCRYPTKEY, DWORD, DWORD, BYTE *, DWORD *); 
BOOL (WINAPI *pCryptGetUserKey)(HCRYPTPROV, DWORD, HCRYPTKEY *); 
BOOL (WINAPI *pCryptEncrypt)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE *, DWORD *, DWORD); 
BOOL (WINAPI *pCryptGenKey)(HCRYPTPROV, ALG_ID, DWORD, HCRYPTKEY *); 
BOOL (WINAPI *pCryptGenRandom)(HCRYPTPROV, DWORD, BYTE *); 
BOOL (WINAPI *pCryptImportKey)(HCRYPTPROV, CONST BYTE *, DWORD, HCRYPTKEY, DWORD, HCRYPTKEY *); 
BOOL (WINAPI *pCryptDecrypt)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE *, DWORD *); 
BOOL (WINAPI *pCryptReleaseContext)(HCRYPTPROV, DWORD); 
 
BOOL (WINAPI *pCryptCreateHash)(HCRYPTPROV, ALG_ID, HCRYPTKEY, DWORD, HCRYPTHASH *); 
BOOL (WINAPI *pCryptHashData)(HCRYPTHASH, BYTE *, DWORD, DWORD); 
BOOL (WINAPI *pCryptSignHash)(HCRYPTHASH, DWORD, LPCSTR, DWORD, BYTE *, DWORD *); 
BOOL (WINAPI *pCryptVerifySignature)(HCRYPTHASH, CONST BYTE *, DWORD, HCRYPTKEY, LPCSTR, DWORD); 
 
BOOL TMainWin::SetupCryptAPI(void) 
{ 
	HINSTANCE	advdll; 
 
	cfg->hCsp = cfg->hSmallCsp = NULL; 
 
	if ((advdll = ::LoadLibrary("advapi32.dll")) == NULL) 
		return	GetLastErrorMsg("advapi32"), FALSE; 
 
	pCryptAcquireContext = (BOOL (WINAPI *)(HCRYPTPROV *, LPCSTR, LPCSTR, DWORD, DWORD))::GetProcAddress(advdll, "CryptAcquireContextA"); 
	pCryptDestroyKey = (BOOL (WINAPI *)(HCRYPTKEY))::GetProcAddress(advdll, "CryptDestroyKey"); 
	pCryptGetKeyParam = (BOOL (WINAPI *)(HCRYPTKEY, DWORD, BYTE *, DWORD *, DWORD))::GetProcAddress(advdll, "CryptGetKeyParam"); 
	pCryptSetKeyParam = (BOOL (WINAPI *)(HCRYPTKEY, DWORD, BYTE *, DWORD))::GetProcAddress(advdll, "CryptSetKeyParam"); 
	pCryptExportKey = (BOOL (WINAPI *)(HCRYPTKEY, HCRYPTKEY, DWORD, DWORD, BYTE *, DWORD *))::GetProcAddress(advdll, "CryptExportKey"); 
	pCryptGetUserKey = (BOOL (WINAPI *)(HCRYPTPROV, DWORD, HCRYPTKEY *))::GetProcAddress(advdll, "CryptGetUserKey"); 
	pCryptEncrypt = (BOOL (WINAPI *)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE *, DWORD *, DWORD))::GetProcAddress(advdll, "CryptEncrypt"); 
	pCryptGenKey = (BOOL (WINAPI *)(HCRYPTPROV, ALG_ID, DWORD, HCRYPTKEY *))::GetProcAddress(advdll, "CryptGenKey"); 
	pCryptGenRandom = (BOOL (WINAPI *)(HCRYPTPROV, DWORD, BYTE *))::GetProcAddress(advdll, "CryptGenRandom"); 
	pCryptImportKey = (BOOL (WINAPI *)(HCRYPTPROV, CONST BYTE *, DWORD, HCRYPTKEY, DWORD, HCRYPTKEY *))::GetProcAddress(advdll, "CryptImportKey"); 
	pCryptDecrypt = (BOOL (WINAPI *)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE *, DWORD *))::GetProcAddress(advdll, "CryptDecrypt"); 
	pCryptCreateHash = (BOOL (WINAPI *)(HCRYPTPROV, ALG_ID, HCRYPTKEY, DWORD, HCRYPTHASH *))::GetProcAddress(advdll, "CryptCreateHash"); 
	pCryptHashData = (BOOL (WINAPI *)(HCRYPTHASH, BYTE *, DWORD, DWORD))::GetProcAddress(advdll, "CryptHashData"); 
	pCryptSignHash = (BOOL (WINAPI *)(HCRYPTHASH, DWORD, LPCSTR, DWORD, BYTE *, DWORD *))::GetProcAddress(advdll, "CryptSignHashA"); 
	pCryptVerifySignature = (BOOL (WINAPI *)(HCRYPTHASH, CONST BYTE *, DWORD, HCRYPTKEY, LPCSTR, DWORD))::GetProcAddress(advdll, "CryptVerifySignatureA"); 
	pCryptReleaseContext = (BOOL (WINAPI *)(HCRYPTPROV, DWORD))::GetProcAddress(advdll, "CryptReleaseContext"); 
 
	if (pCryptAcquireContext == NULL) 
		return	GetLastErrorMsg("GetProcAddress"), FALSE; 
 
	SetupCryptAPICore(); 
#define MAX_RETRY	3 
	int	cnt = 0; 
	while (cfg->hCsp && cfg->pubKey.Key() == NULL || cfg->hSmallCsp && cfg->smallPubKey.Key() == NULL) 
	{ 
		if (++cnt > MAX_RETRY) 
			break; 
		if (cfg->hCsp) 
			pCryptReleaseContext(cfg->hCsp, 0), cfg->hCsp = NULL; 
		if (cfg->hSmallCsp) 
			pCryptReleaseContext(cfg->hSmallCsp, 0), cfg->hSmallCsp = NULL; 
		::Sleep(1000); 
		SetupCryptAPICore(cnt == MAX_RETRY ? KEY_DIAG : 0); 
	} 
	if (cnt > MAX_RETRY || cfg->pubKey.Key() == NULL && cfg->smallPubKey.Key() == NULL) 
	{ 
		if (MessageBox("RSA failed. Create New RSA key?", "msg", MB_OKCANCEL) == IDOK) 
			SetupCryptAPICore(KEY_REBUILD|KEY_DIAG); 
	} 
 
	return	cfg->pubKey.Key() || cfg->smallPubKey.Key(); 
} 
 
BOOL TMainWin::SetupCryptAPICore(int ctl_flg) 
{ 
	BYTE		data[MAX_BUF]; 
	char		*contName = (char *)data; 
	HCRYPTKEY	hExKey; 
	int			len = sizeof(data); 
	int			capa = IPMSG_RSA_512 | IPMSG_RC2_40ALL; 
 
// 1024 bit RSA 鍵 
	wsprintf(contName, "ipmsg.rsa1024.%s", msgMng->GetLocalHost()->userName); 
 
	// rebuld 時には、事前に公開鍵を消去 
	if ((ctl_flg & KEY_REBUILD) && cfg->hCsp && cfg->pubKey.Key() == NULL) 
	{ 
		pCryptReleaseContext(cfg->hCsp, 0), cfg->hCsp = NULL; 
		if (!pCryptAcquireContext(&cfg->hCsp, contName, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET|CRYPT_MACHINE_KEYSET)) 
			if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptAcquireContext1024(destroy)"); 
		!pCryptAcquireContext(&cfg->hCsp, contName, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET); 
	} 
 
	// 公開鍵の取得 
	if (pCryptAcquireContext(&cfg->hCsp, contName, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET) 
	|| pCryptAcquireContext(&cfg->hCsp, contName, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)) 
	{ 
		if (!pCryptGetUserKey(cfg->hCsp, AT_KEYEXCHANGE, &hExKey)) 
			if (!pCryptGenKey(cfg->hCsp, CALG_RSA_KEYX, CRYPT_EXPORTABLE, &hExKey)) 
				GetLastErrorMsg("CryptGenKey"); 
		if (pCryptExportKey(hExKey, 0, PUBLICKEYBLOB, 0, data, (DWORD *)&len)) 
		{ 
			capa |= IPMSG_RSA_1024 | IPMSG_BLOWFISH_128ALL /* | IPMSG_BLOWFISH_256 */; 
			HCRYPTKEY	hKey; 
			if (pCryptGenKey(cfg->hCsp, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) 
			{ 
				DWORD		val=128;	// available 128bit RC2? 
				if (pCryptSetKeyParam(hKey, KP_EFFECTIVE_KEYLEN, (BYTE *)&val, 0)) 
					capa |= IPMSG_RC2_128ALL; 
				pCryptDestroyKey(hKey); 
			} 
			cfg->pubKey.SetByBlob(data, capa); 
		} else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptExportKey"); 
		pCryptDestroyKey(hExKey); 
	} /* else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptAcquireContext"); */ 
 
// 512 bit RSA 鍵 
	wsprintf(contName, "ipmsg.rsa512.%s", msgMng->GetLocalHost()->userName); 
 
	// REBUILD 時には、事前に公開鍵を消去 
	if ((ctl_flg & KEY_REBUILD) && cfg->hSmallCsp && cfg->smallPubKey.Key() == NULL) 
	{ 
		pCryptReleaseContext(cfg->hSmallCsp, 0), cfg->hSmallCsp = NULL; 
		if (!pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET|CRYPT_MACHINE_KEYSET)) 
			if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptAcquireContext512(destroy)"); 
		pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET); 
	} 
 
	// 公開鍵の取得 
	if (pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET) || pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, 0) 
	|| pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET) || pCryptAcquireContext(&cfg->hSmallCsp, contName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) 
	{ 
		if (!pCryptGetUserKey(cfg->hSmallCsp, AT_KEYEXCHANGE, &hExKey)) 
			pCryptGenKey(cfg->hSmallCsp, CALG_RSA_KEYX, CRYPT_EXPORTABLE, &hExKey); 
		if (pCryptExportKey(hExKey, 0, PUBLICKEYBLOB, 0, data, (DWORD *)&len)) 
		{ 
			cfg->smallPubKey.SetByBlob(data, capa); 
		} else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptExportKey512"); 
		pCryptDestroyKey(hExKey); 
	} else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptAcquireContext512"); 
 
// Self Check 1024bit 
	if (cfg->pubKey.Key()) { 
		BOOL	ret = FALSE; 
 
		cfg->pubKey.KeyBlob(data, sizeof(data), &len); 
		if (pCryptImportKey(cfg->hCsp, data, len, 0, 0, &hExKey)) { 
			len = 128/8; 
			if (pCryptEncrypt(hExKey, 0, TRUE, 0, data, (DWORD *)&len, MAX_BUF)) 
				ret = TRUE; 
			else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptEncrypt test1024"); 
			pCryptDestroyKey(hExKey); 
		} 
		else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptImportKey test1024"); 
 
		if (ret == TRUE) { 
			ret = FALSE; 
			if (pCryptGetUserKey(cfg->hCsp, AT_KEYEXCHANGE, &hExKey)) { 
				if (pCryptDecrypt(hExKey, 0, TRUE, 0, (BYTE *)data, (DWORD *)&len)) 
					ret = TRUE; 
				else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptDecrypt test1024"); 
				pCryptDestroyKey(hExKey); 
			} 
			else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptGetUserKey test1024"); 
		} 
 
		if (ret == FALSE) 
			cfg->pubKey.UnSet(); 
	} 
 
// Self Check 512bit 
	if (cfg->smallPubKey.Key()) { 
		BOOL		ret = FALSE; 
		BYTE		tmp[MAX_BUF]; 
		DWORD		tmplen = MAX_BUF / 2; 
		HCRYPTKEY	hKey; 
 
		cfg->smallPubKey.KeyBlob(data, sizeof(data), &len); 
		if (pCryptImportKey(cfg->hSmallCsp, data, len, 0, 0, &hExKey)) { 
			if (pCryptGenKey(cfg->hSmallCsp, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) { 
				pCryptExportKey(hKey, hExKey, SIMPLEBLOB, 0, NULL, (DWORD *)&len); 
				if (pCryptExportKey(hKey, hExKey, SIMPLEBLOB, 0, data, (DWORD *)&len)) { 
					if (pCryptEncrypt(hKey, 0, TRUE, 0, tmp, &tmplen, MAX_BUF)) 
						ret = TRUE; 
					else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptEncrypt test512"); 
				} 
				else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptExportKey test512"); 
				pCryptDestroyKey(hKey); 
			} 
			else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptGenKey test512"); 
			pCryptDestroyKey(hExKey); 
		} 
		else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptImportKey test512"); 
 
		if (ret == TRUE) { 
			ret = FALSE; 
			if (pCryptImportKey(cfg->hSmallCsp, data, len, 0, 0, &hKey)) { 
				if (pCryptDecrypt(hKey, 0, TRUE, 0, (BYTE *)tmp, (DWORD *)&tmplen)) 
					ret = TRUE; 
				else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptDecrypt test512"); 
				pCryptDestroyKey(hKey); 
			} 
			else if (ctl_flg & KEY_DIAG) GetLastErrorMsg("CryptImportKey test512"); 
		} 
 
		if (ret == FALSE) 
			cfg->smallPubKey.UnSet(); 
	} 
 
	return	cfg->pubKey.Key() || cfg->smallPubKey.Key(); 
} 
 
void TMainWin::ControlIME(TWin *win, BOOL open) 
{ 
	HWND	targetWnd = (win && win->hWnd) ? win->GetDlgItem(SEND_EDIT) : hWnd; 
 
	if (win && win->hWnd && open == FALSE) 
		::SetFocus(targetWnd);		// ATOK残像 暫定対策... 
 
	if (cfg->ControlIME == FALSE) 
		return; 
 
	if (open == FALSE) 
	{ 
		for (TSendDlg *sendDlg = (TSendDlg *)sendList.TopObj(); sendDlg != NULL; sendDlg = (TSendDlg *)sendList.NextObj(sendDlg)) 
			if (sendDlg != win && sendDlg->IsSending() != TRUE) 
				return; 
	} 
 
//	SetImeOpenStatus(targetWnd, open); 
	if (GetImeOpenStatus(targetWnd) != open) 
		SetImeOpenStatus(targetWnd, open); 
} 
 
/* 
	MainWindow を教えてあげる。 
*/ 
HWND GetMainWnd(void) 
{ 
	return	hMainWnd; 
} 
 
/* 
	Version文字列 
*/ 
char *GetVerionStr(void) 
{ 
	return	strstr(mainwin_id, "Ver"); 
}