Beispiel #1
0
void CVkProto::AppendChatMessage(int id, JSONNODE *pMsg, bool bIsHistory)
{
	CVkChatInfo *cc = AppendChat(id, NULL);
	if (cc == NULL)
		return;

	int mid = json_as_int(json_get(pMsg, "mid"));
	int isOut = json_as_int(json_get(pMsg, "out"));
	int uid = json_as_int(json_get(pMsg, "uid"));

	int msgTime = json_as_int(json_get(pMsg, "date"));
	time_t now = time(NULL);
	if (!msgTime || msgTime > now)
		msgTime = now;

	ptrT tszBody(json_as_string(json_get(pMsg, "body")));
	JSONNODE *pAttachments = json_get(pMsg, "attachments");
	if (pAttachments != NULL)
		tszBody = mir_tstrdup(CMString(tszBody) + GetAttachmentDescr(pAttachments));

	if (cc->m_bHistoryRead)
		AppendChatMessage(cc, mid, uid, msgTime, tszBody, bIsHistory);
	else {
		CVkChatMessage *cm = cc->m_msgs.find((CVkChatMessage *)&mid);
		if (cm == NULL)
			cc->m_msgs.insert(cm = new CVkChatMessage(mid));

		cm->m_uid = uid;
		cm->m_date = msgTime;
		cm->m_tszBody = tszBody.detouch();
		cm->m_bHistory = bIsHistory;
	}
}
Beispiel #2
0
void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveMessages %d", reply->resultCode);
	if (reply->resultCode != 200)
		return;

	JSONNode jnRoot;
	const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
	if (!jnResponse)
		return;
	if (!jnResponse["Msgs"])
		return;

	CMStringA mids;
	int numMessages = jnResponse["Msgs"]["count"].as_int();
	const JSONNode &jnMsgs = jnResponse["Msgs"]["items"];
	const JSONNode &jnFUsers = jnResponse["fwd_users"];

	debugLogA("CVkProto::OnReceiveMessages numMessages = %d", numMessages);

	for (auto it = jnMsgs.begin(); it != jnMsgs.end(); ++it) {
		const JSONNode &jnMsg = (*it);
		if (!jnMsg) {
			debugLogA("CVkProto::OnReceiveMessages pMsg == NULL");
			break;
		}

		UINT mid = jnMsg["id"].as_int();
		CMString tszBody(jnMsg["body"].as_mstring());
		int datetime = jnMsg["date"].as_int();
		int isOut = jnMsg["out"].as_int();
		int isRead = jnMsg["read_state"].as_int();
		int uid = jnMsg["user_id"].as_int();

		const JSONNode &jnFwdMessages = jnMsg["fwd_messages"];
		if (jnFwdMessages) {
			CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_vkOptions.BBCForAttachments());
			if (!tszBody.IsEmpty())
				tszFwdMessages = _T("\n") + tszFwdMessages;
			tszBody +=  tszFwdMessages;
		}

		CMString tszAttachmentDescr;
		const JSONNode &jnAttachments = jnMsg["attachments"];
		if (jnAttachments) {
			tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_vkOptions.BBCForAttachments());
			if (!tszBody.IsEmpty())
				tszBody += _T("\n");
			tszBody += tszAttachmentDescr;
		}

		MCONTACT hContact = NULL;
		int chat_id = jnMsg["chat_id"].as_int();
		if (chat_id == 0)
			hContact = FindUser(uid, true);

		char szMid[40];
		_itoa(mid, szMid, 10);
		if (m_vkOptions.iMarkMessageReadOn == MarkMsgReadOn::markOnReceive || chat_id != 0) {
			if (!mids.IsEmpty())
				mids.AppendChar(',');
			mids.Append(szMid);
		}

		if (chat_id != 0) {
			debugLogA("CVkProto::OnReceiveMessages chat_id != 0");
			CMString action_chat = jnMsg["action"].as_mstring();
			int action_mid = _ttoi(jnMsg["action_mid"].as_mstring());
			if ((action_chat == "chat_kick_user") && (action_mid == m_myUserId))
				KickFromChat(chat_id, uid, jnMsg, jnFUsers);
			else {
				MCONTACT chatContact = FindChat(chat_id);
				if (chatContact && getBool(chatContact, "kicked", true))
					db_unset(chatContact, m_szModuleName, "kicked");
				AppendChatMessage(chat_id, jnMsg, jnFUsers, false);
			}
			continue;
		}

		PROTORECVEVENT recv = { 0 };
		bool bUseServerReadFlag = m_vkOptions.bSyncReadMessageStatusFromServer ? true : !m_vkOptions.bMesAsUnread;
		if (isRead && bUseServerReadFlag)
			recv.flags |= PREF_CREATEREAD;
		if (isOut)
			recv.flags |= PREF_SENT;
		else if (m_vkOptions.bUserForceInvisibleOnActivity && time(NULL) - datetime < 60 * m_vkOptions.iInvisibleInterval)
			SetInvisible(hContact);

		T2Utf pszBody(tszBody);
		recv.timestamp = m_vkOptions.bUseLocalTime ? time(NULL) : datetime;
		recv.szMessage = pszBody;
		recv.lParam = isOut;
		recv.pCustomData = szMid;
		recv.cbCustomDataSize = (int)mir_strlen(szMid);
		Sleep(100);

		debugLogA("CVkProto::OnReceiveMessages mid = %d, datetime = %d, isOut = %d, isRead = %d, uid = %d", mid, datetime, isOut, isRead, uid);

		if (!CheckMid(m_sendIds, mid)) {
			debugLogA("CVkProto::OnReceiveMessages ProtoChainRecvMsg");
			ProtoChainRecvMsg(hContact, &recv);
			if (mid > getDword(hContact, "lastmsgid", -1))
				setDword(hContact, "lastmsgid", mid);
			if (!isOut)
				m_incIds.insert((HANDLE)mid);
		}
		else if (m_vkOptions.bLoadSentAttachments && !tszAttachmentDescr.IsEmpty() && isOut) {
			T2Utf pszAttach(tszAttachmentDescr);
			recv.timestamp = time(NULL); // only local time
			recv.szMessage = pszAttach;
			ProtoChainRecvMsg(hContact, &recv);
		}
	}

	if (!mids.IsEmpty())
		MarkMessagesRead(mids);
}
Beispiel #3
0
void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveMessages %d", reply->resultCode);
	if (reply->resultCode != 200)
		return;

	JSONROOT pRoot;
	JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot);
	if (pResponse == NULL)
		return;

	JSONNODE *pDlgs = json_as_array(json_get(pResponse, "dlgs"));
	if (pDlgs != NULL) {
		int numDialogs = json_as_int(json_at(pDlgs, 0));
		for (int i = 1; i <= numDialogs; i++) {
			JSONNODE *pDlg = json_at(pDlgs, i);
			if (pDlg == NULL)
				continue;

			int chatid = json_as_int(json_get(pDlg, "chat_id"));
			if (chatid != 0)
			if (m_chats.find((CVkChatInfo*)&chatid) == NULL) {
				AppendChat(chatid, pDlg);
			}
		}
	}

	CMStringA mids, lmids;
	bool bDirectArray = false;

	JSONNODE *pMsgs = json_as_array(json_get(pResponse, "msgs"));
	if (pMsgs == NULL) {
		pMsgs = pResponse;
		bDirectArray = true;
	}

	int numMessages = json_as_int(json_at(pMsgs, 0));
	for (int i = 1; i <= numMessages; i++) {
		JSONNODE *pMsg = json_at(pMsgs, i);
		if (pMsg == NULL)
			continue;

		char szMid[40];
		int mid = json_as_int(json_get(pMsg, "mid"));
		_itoa(mid, szMid, 10);
		if (!mids.IsEmpty())
			mids.AppendChar(',');
		mids.Append(szMid);

		int chat_id = json_as_int(json_get(pMsg, "chat_id"));
		if (chat_id != 0) {
			AppendChatMessage(chat_id, pMsg, false);
			continue;
		}

		// VK documentation lies: even if you specified preview_length=0, 
		// long messages get cut out. So we need to retrieve them from scratch
		ptrT ptszBody(json_as_string(json_get(pMsg, "body")));
		if (!bDirectArray && _tcslen(ptszBody) > 1000) {
			if (!lmids.IsEmpty())
				lmids.AppendChar(',');
			lmids.Append(szMid);
			continue;
		}

		int datetime = json_as_int(json_get(pMsg, "date"));
		int isOut = json_as_int(json_get(pMsg, "out"));
		int uid = json_as_int(json_get(pMsg, "uid"));
		int isRead = json_as_int(json_get(pMsg, "read_state"));

		JSONNODE *pAttachments = json_get(pMsg, "attachments");
		if (pAttachments != NULL)
			ptszBody = mir_tstrdup(CMString(ptszBody) + GetAttachmentDescr(pAttachments));

		MCONTACT hContact = FindUser(uid, true);

		PROTORECVEVENT recv = { 0 };
		recv.flags = PREF_TCHAR;
		if (isRead)
			recv.flags |= PREF_CREATEREAD;
		if (isOut)
			recv.flags |= PREF_SENT;
		recv.timestamp = datetime;
		recv.tszMessage = ptszBody;
		recv.lParam = isOut;
		recv.pCustomData = szMid;
		recv.cbCustomDataSize = (int)strlen(szMid);
		ProtoChainRecvMsg(hContact, &recv);
	}

	MarkMessagesRead(mids);
	RetrieveMessagesByIds(lmids);
}
Beispiel #4
0
CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLIST<CVkUserInfo> &vkUsers, bool isRepost)
{
	bool bPostLink = true;
	CVKNewsItem *vkNewsItem = new CVKNewsItem();
	if (!jnItem)
		return vkNewsItem;

	LONG iSourceId = jnItem["source_id"].isnull() ? jnItem["owner_id"].as_int() : jnItem["source_id"].as_int();
	LONG iPostId = jnItem["post_id"].as_int();
	CMString tszText(jnItem["text"].as_mstring());

	vkNewsItem->tszType = jnItem["type"].as_mstring();
	vkNewsItem->vkUser = GetVkUserInfo(iSourceId, vkUsers);
	vkNewsItem->bIsGroup = vkNewsItem->vkUser->m_bIsGroup;
	vkNewsItem->tDate = jnItem["date"].as_int();

	if (!tszText.IsEmpty())
		tszText += _T("\n");

	debugLog(_T("CVkProto::GetVkNewsItem %d %d %s"), iSourceId, iPostId, vkNewsItem->tszType);

	if (vkNewsItem->tszType == _T("photo_tag")) {
		bPostLink = false;
		const JSONNode &jnPhotos = jnItem["photo_tags"];
		if (!jnPhotos.isnull()) {			
			const JSONNode &jnPhotoItems = jnPhotos["items"];
			if (!jnPhotoItems.isnull()) {				
				tszText = TranslateT("User was tagged in these photos:");
				for (auto it = jnPhotoItems.begin(); it != jnPhotoItems.end(); ++it)
					tszText += _T("\n") + GetVkPhotoItem((*it), m_iBBCForNews);
			}
		}
	}
	else if (vkNewsItem->tszType == _T("photo") || vkNewsItem->tszType == _T("wall_photo")) {
		bPostLink = false;
		const JSONNode &jnPhotos = jnItem["photos"];
		int i = 0;
		if (!jnPhotos.isnull()) {
			const JSONNode &jnPhotoItems = jnPhotos["items"];
			if (!jnPhotoItems.isnull())
				for (auto it = jnPhotoItems.begin(); it != jnPhotoItems.end(); ++it) {
					const JSONNode &jnPhotoItem = (*it);
					tszText += GetVkPhotoItem(jnPhotoItem, m_iBBCForNews) + _T("\n");
					if (i == 0 && vkNewsItem->tszType == _T("wall_photo")) {						
						if (!jnPhotoItem["post_id"].isnull()) {
							bPostLink = true;
							iPostId = jnPhotoItem["post_id"].as_int();
							break; // max 1 wall_photo when photo post_id !=0
						}					
					}
					i++;
				}
		}
	} 
	else if (vkNewsItem->tszType == _T("post") || vkNewsItem->tszType.IsEmpty()) {
		bPostLink = true;
		const JSONNode &jnRepost = jnItem["copy_history"];
		if (!jnRepost.isnull()) {
			CVKNewsItem *vkRepost = GetVkNewsItem((*jnRepost.begin()), vkUsers, true);
			vkRepost->tszText.Replace(_T("\n"), _T("\n\t"));
			tszText += vkRepost->tszText;
			tszText += _T("\n");
			vkNewsItem->bIsRepost = true;
			delete vkRepost;
		}

		const JSONNode &jnAttachments = jnItem["attachments"];
		if (!jnAttachments.isnull()) {
			if (!tszText.IsEmpty())
				tszText.AppendChar(_T('\n'));
			tszText += GetAttachmentDescr(jnAttachments, m_bUseBBCOnAttacmentsAsNews ? m_iBBCForNews : m_iBBCForAttachments);
		}
	}

	CMString tszResFormat;	

	if (!isRepost)
		tszResFormat = Translate("News from %s\n%s");
	else {
		tszResFormat = Translate("\tRepost from %s\n%s");
		bPostLink = false;
	}
		
	vkNewsItem->tszText.AppendFormat(tszResFormat, 
		SetBBCString(vkNewsItem->vkUser->m_tszUserNick, m_iBBCForNews, vkbbcUrl, 
		vkNewsItem->vkUser->m_tszLink), tszText);
	
	vkNewsItem->tszId.AppendFormat(_T("%d_%d"), vkNewsItem->vkUser->m_UserId, iPostId);
	if (bPostLink) {
		vkNewsItem->tszLink = CMString(_T("https://vk.com/wall")) + vkNewsItem->tszId;
		vkNewsItem->tszText.AppendChar(_T('\n'));
		vkNewsItem->tszText += SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNewsItem->tszLink);
	}

	debugLog(_T("CVkProto::GetVkNewsItem %d %d <\n%s\n>"), iSourceId, iPostId, vkNewsItem->tszText);

	return vkNewsItem;
}
void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveHistoryMessages %d", reply->resultCode);
	if (reply->resultCode != 200 || !pReq->pUserInfo)
		return;

	JSONNode jnRoot;
	CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo;
	const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
	if (!jnResponse) {
		if (!pReq->bNeedsRestart || m_bTerminated) {
			delete param;
			pReq->pUserInfo = NULL;
		}
		return;
	}
	
	int iTime = jnResponse["datetime"].as_int(); 
	const JSONNode &jnMsgs = jnResponse["items"];
	const JSONNode &jnFUsers = jnResponse["fwd_users"];

	int iLastMsgId = getDword(param->hContact, "lastmsgid", -1);
	time_t tLastReadMessageTime = 0;
	int count = 0;

	for (auto it = jnMsgs.rbegin(); it != jnMsgs.rend(); ++it) {
		const JSONNode &jnMsg = (*it);

		int mid = jnMsg["id"].as_int();
		if (iLastMsgId < mid) 
			iLastMsgId = mid;

		char szMid[40];
		_itoa(mid, szMid, 10);

		CMString tszBody(jnMsg["body"].as_mstring());
		int datetime = jnMsg["date"].as_int();
		int isOut = jnMsg["out"].as_int();
		int isRead = jnMsg["read_state"].as_int(); 
		int uid = jnMsg["user_id"].as_int(); 
		
		const JSONNode &jnFwdMessages = jnMsg["fwd_messages"];
		if (jnFwdMessages) {
			CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_iBBCForAttachments);
			if (!tszBody.IsEmpty())
				tszFwdMessages = _T("\n") + tszFwdMessages;
			tszBody += tszFwdMessages;
		}
		
		const JSONNode &jnAttachments = jnMsg["attachments"];
		if (jnAttachments) {
			CMString tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_iBBCForAttachments);
			if (!tszBody.IsEmpty())
				tszAttachmentDescr = _T("\n") + tszAttachmentDescr;
			tszBody += tszAttachmentDescr;
		}

		T2Utf pszBody(tszBody);
		MCONTACT hContact = FindUser(uid, true);
		PROTORECVEVENT recv = { 0 };
		if (isRead)
			recv.flags |= PREF_CREATEREAD;
		if (isOut)
			recv.flags |= PREF_SENT;
		recv.timestamp = datetime;
		recv.szMessage = pszBody;
		recv.lParam = isOut;
		recv.pCustomData = szMid;
		recv.cbCustomDataSize = (int)mir_strlen(szMid);
		ProtoChainRecvMsg(hContact, &recv);

		if (isRead && isOut && datetime > tLastReadMessageTime)
			tLastReadMessageTime = datetime;

		count++;
	}
	setDword(param->hContact, "lastmsgid", iLastMsgId);

	if (ServiceExists(MS_MESSAGESTATE_UPDATE)) {
		MessageReadData data(tLastReadMessageTime, MRD_TYPE_MESSAGETIME);
		CallService(MS_MESSAGESTATE_UPDATE, param->hContact, (LPARAM)&data);
	}

	int once = jnResponse["once"].as_int();
	int iRCount = jnResponse["rcount"].as_int();
	if (count == iRCount && once == 0)
		GetServerHistory(param->hContact, param->iCount + count, iRCount, iTime, param->iMsgID);

	if (!pReq->bNeedsRestart || m_bTerminated) {
		delete param;
		pReq->pUserInfo = NULL;
	}
}
Beispiel #6
0
void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveHistoryMessages %d", reply->resultCode);
	if (reply->resultCode != 200 || !pReq->pUserInfo) {
		mir_cslock lck(m_csLoadHistoryTask);
		if (m_iLoadHistoryTask > 0)
			m_iLoadHistoryTask--;
		debugLog(_T("CVkProto::OnReceiveHistoryMessages error m_iLoadHistoryTask=%d"), m_iLoadHistoryTask);
		MsgPopup(NULL, TranslateT("Error loading message history from server"), TranslateT("Error"), true);

		if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) {
			MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history"));
			m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false;
		}

		return;
	}

	JSONNode jnRoot;
	CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo;
	const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
	if (!jnResponse) {
		if (!pReq->bNeedsRestart || m_bTerminated) {
			mir_cslock lck(m_csLoadHistoryTask);
			if (m_iLoadHistoryTask > 0) 
				m_iLoadHistoryTask--;
			
			ptrT ptszNick(db_get_tsa(param->hContact, m_szModuleName, "Nick"));
			CMString str(FORMAT, _T("%s %s %s"), TranslateT("Error loading message history from server"), TranslateT("for"), ptszNick);

			MsgPopup(param->hContact, str, TranslateT("Error"), true);
			debugLog(_T("CVkProto::OnReceiveHistoryMessages error for %s m_iLoadHistoryTask=%d"), ptszNick, m_iLoadHistoryTask);

			if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) {
				MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history"));
				m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false;
			}

			delete param;
			pReq->pUserInfo = NULL;
		}
		return;
	}

	int iTime = jnResponse["datetime"].as_int(); 
	const JSONNode &jnMsgs = jnResponse["items"];
	const JSONNode &jnFUsers = jnResponse["fwd_users"];

	int iLastMsgId = getDword(param->hContact, "lastmsgid", -1);
	time_t tLastReadMessageTime = 0;
	int count = 0;

	for (auto it = jnMsgs.rbegin(); it != jnMsgs.rend(); ++it) {
		const JSONNode &jnMsg = (*it);

		int mid = jnMsg["id"].as_int();
		if (iLastMsgId < mid) 
			iLastMsgId = mid;

		char szMid[40];
		_itoa(mid, szMid, 10);

		CMString tszBody(jnMsg["body"].as_mstring());
		int datetime = jnMsg["date"].as_int();
		int isOut = jnMsg["out"].as_int();
		int isRead = jnMsg["read_state"].as_int(); 
		int uid = jnMsg["user_id"].as_int(); 

		const JSONNode &jnFwdMessages = jnMsg["fwd_messages"];
		if (jnFwdMessages) {
			CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_vkOptions.BBCForAttachments());
			if (!tszBody.IsEmpty())
				tszFwdMessages = _T("\n") + tszFwdMessages;
			tszBody += tszFwdMessages;
		}

		const JSONNode &jnAttachments = jnMsg["attachments"];
		if (jnAttachments) {
			CMString tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_vkOptions.BBCForAttachments());
			if (!tszBody.IsEmpty())
				tszAttachmentDescr = _T("\n") + tszAttachmentDescr;
			tszBody += tszAttachmentDescr;
		}

		T2Utf pszBody(tszBody);
		MCONTACT hContact = FindUser(uid, true);
		PROTORECVEVENT recv = { 0 };
		if (isRead)
			recv.flags |= PREF_CREATEREAD;
		if (isOut)
			recv.flags |= PREF_SENT;
		recv.timestamp = datetime;
		recv.szMessage = pszBody;
		recv.lParam = isOut;
		recv.pCustomData = szMid;
		recv.cbCustomDataSize = (int)mir_strlen(szMid);
		ProtoChainRecvMsg(hContact, &recv);

		if (isRead && isOut && datetime > tLastReadMessageTime)
			tLastReadMessageTime = datetime;

		count++;
	}
	setDword(param->hContact, "lastmsgid", iLastMsgId);

	if (ServiceExists(MS_MESSAGESTATE_UPDATE)) {
		MessageReadData data(tLastReadMessageTime, MRD_TYPE_MESSAGETIME);
		CallService(MS_MESSAGESTATE_UPDATE, param->hContact, (LPARAM)&data);
	}

	int once = jnResponse["once"].as_int();
	int iRCount = jnResponse["rcount"].as_int();
	if (count == iRCount && once == 0)
		GetServerHistory(param->hContact, param->iCount + count, iRCount, iTime, param->iMsgID);
	else {
		mir_cslock lck(m_csLoadHistoryTask);
		if (m_iLoadHistoryTask > 0)
			m_iLoadHistoryTask--;

		ptrT ptszNick(db_get_tsa(param->hContact, m_szModuleName, "Nick"));
		CMString str(FORMAT, TranslateT("Loading messages for %s is completed"), ptszNick);
		debugLog(_T("CVkProto::OnReceiveHistoryMessages for %s m_iLoadHistoryTask=%d"), ptszNick, m_iLoadHistoryTask);

		if (m_bNotifyForEndLoadingHistory)
			MsgPopup(param->hContact, str, TranslateT("Loading history"));

		if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) {
			MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history"));
			m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false;		
		}
	}

	if (!pReq->bNeedsRestart || m_bTerminated) {
		delete param;
		pReq->pUserInfo = NULL;
	}
}