diff options
Diffstat (limited to 'protocols/Sametime/src/sametime_session.cpp')
| -rw-r--r-- | protocols/Sametime/src/sametime_session.cpp | 634 | 
1 files changed, 634 insertions, 0 deletions
diff --git a/protocols/Sametime/src/sametime_session.cpp b/protocols/Sametime/src/sametime_session.cpp new file mode 100644 index 0000000000..bc03f86a03 --- /dev/null +++ b/protocols/Sametime/src/sametime_session.cpp @@ -0,0 +1,634 @@ +#include "StdAfx.h"
 +#include "sametime.h"
 +
 +/// not in CSametimeProto (used at NETLIBOPENCONNECTION_tag.waitcallback)
 +bool continue_connect;
 +
 +#define MS_SAMETIME_MENUANNOUNCESESSION		"/SessionAnnounce"
 +
 +// utf8 encoded
 +struct {
 +	char* szOnline;
 +	char* szAway;
 +	char* szDND;
 +} AwayMessages;
 +
 +
 +void __cdecl SessionClear(mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionClear()"));
 +}
 +
 +int __cdecl SessionWrite(mwSession* session, const unsigned char* buf, gsize len)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionWrite()  server_connection=[%d], len=[%d]"), proto->server_connection, len);
 +	if (!proto->server_connection) return 1;
 +	if (Netlib_Send(proto->server_connection, (const char*)buf, len, 0) == SOCKET_ERROR)
 +		return 1;
 +	return 0;
 +}
 +
 +void __cdecl SessionClose(mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionClose()  server_connection=[%d]"), proto->server_connection);
 +	Netlib_CloseHandle(proto->server_connection);
 +	proto->server_connection = 0;
 +}
 +
 +void CSametimeProto::SessionStarted()
 +{
 +	UserListCreate();
 +	if (options.get_server_contacts) UserListAddStored();
 +}
 +
 +void CSametimeProto::SessionStopping()
 +{
 +	UserListDestroy();
 +}
 +
 +void CSametimeProto::InitMeanwhileServices()
 +{
 +	debugLog(_T("InitMeanwhileServices() start"));
 +
 +	if (options.encrypt_session) {
 +		mwSession_addCipher(session, mwCipher_new_RC2_128(session));
 +		mwSession_addCipher(session, mwCipher_new_RC2_40(session));
 +	}
 +
 +	InitUserList();
 +	InitMessaging();
 +	InitFiles();
 +	InitConference();
 +
 +	mwSession_setProperty(session, "PROTO_STRUCT_PTR", this, NULL);
 +
 +	///TODO InitMeanwhileServices DeinitMeanwhileServices on LogIn LogOut, do not need restart
 +	mwSession_setProperty(session, mwSession_AUTH_USER_ID, options.id, NULL);
 +	mwSession_setProperty(session, mwSession_AUTH_PASSWORD, options.pword, NULL);
 +	mwSession_setProperty(session, mwSession_CLIENT_TYPE_ID, (void*)options.client_id, NULL);
 +
 +	if (options.use_old_default_client_ver) {
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMajor", MW_PROTOCOL_VERSION_MAJOR)), 0);
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", MW_PROTOCOL_VERSION_MINOR)), 0);
 +	} else {
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MAJOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMajor", 0x001e)), 0);
 +		mwSession_setProperty(session, mwSession_CLIENT_VER_MINOR, GUINT_TO_POINTER(db_get_w(0, m_szModuleName, "ClientVersionMinor", 0x196f)), 0);
 +	}
 +
 +}
 +
 +void CSametimeProto::DeinitMeanwhileServices()
 +{
 +	debugLog(_T("DeinitMeanwhileServices() start"));
 +	DeinitConference();
 +	DeinitFiles();
 +	DeinitMessaging();
 +	DeinitUserList();
 +	mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_40));
 +	mwCipher_free(mwSession_getCipher(session, mwCipher_RC2_128));
 +}
 +
 +void __cdecl SessionStateChange(mwSession* session, mwSessionState state, gpointer info)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionStateChange()  state=[%d]"), state);
 +
 +	switch(state) {
 +
 +	case mwSession_STARTING:
 +		break;
 +
 +	case mwSession_HANDSHAKE:
 +		break;
 +
 +	case mwSession_HANDSHAKE_ACK:
 +		break;
 +
 +	case mwSession_STARTED: 
 +		proto->SessionStarted();
 +		break;
 +
 +	case mwSession_STOPPING:
 +		if ((int)info) {// & ERR_FAILURE) {
 +			char *msg = mwError((int)info);
 +			TCHAR *msgT = mir_utf8decodeT(msg);
 +			proto->showPopup(TranslateTS(msgT), SAMETIME_POPUP_ERROR);
 +			mir_free(msgT);
 +			g_free(msg);
 +		}
 +		proto->SessionStopping();
 +		break;
 +
 +	case mwSession_STOPPED:
 +		break;
 +		
 +	case mwSession_LOGIN_REDIR:
 +		proto->debugLog(_T("SessionStateChange()  mwSession_LOGIN_REDIR  info=[%s]"), _A2T((char*)info));
 +		//options.server_name = str((char*)info);
 +		strcpy(proto->options.server_name, (char*)info);
 +		proto->LogOut();
 +		proto->LogIn(proto->login_status, proto->m_hNetlibUser);
 +		break;
 +
 +	case mwSession_LOGIN_CONT:
 +		break;
 +
 +	case mwSession_LOGIN:
 +		break;
 +
 +	case mwSession_LOGIN_ACK:
 +		break;
 +
 +	case mwSession_UNKNOWN:
 +		break;
 +
 +	}
 +}
 +
 +void __cdecl SessionAdmin(struct mwSession* session, const char* text)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionAdmin()"));
 +	TCHAR* tt = mir_utf8decodeT(text);
 +	MessageBox(0, tt, TranslateT("Sametime Administrator Message"), MB_OK);
 +	mir_free(tt);
 +}
 +
 +void __cdecl SessionAnnounce(struct mwSession* session, struct mwLoginInfo* from, gboolean may_reply, const char* text)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionAnnounce()"));
 +	TCHAR* stzFrom;
 +	TCHAR* stzText;
 +	TCHAR stzFromBuff[256];
 +	stzFrom = mir_utf8decodeT(from->user_name);
 +	stzText = mir_utf8decodeT(text);
 +	mir_sntprintf(stzFromBuff, 256, TranslateT("Session Announcement - from '%s'"), stzFrom);
 +	MessageBox(0, TranslateTS(stzText), stzFromBuff, MB_OK);
 +	mir_free(stzText);
 +	mir_free(stzFrom);
 +}
 +
 +void __cdecl SessionSetPrivacyInfo(struct mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	proto->debugLog(_T("SessionSetPrivacyInfo()"));
 +}
 +
 +void __cdecl SessionSetUserStatus(struct mwSession* session)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)mwSession_getProperty(session, "PROTO_STRUCT_PTR");
 +	
 +	int new_status;
 +	struct mwUserStatus us;
 +	mwUserStatus_clone(&us, mwSession_getUserStatus(session));
 +
 +	proto->debugLog(_T("SessionSetUserStatus()  us.status=[%d]"), us.status);
 +
 +	switch(us.status) {
 +
 +	case mwStatus_ACTIVE:
 +		new_status = ID_STATUS_ONLINE; 
 +		break;
 +
 +	case mwStatus_AWAY:
 +		new_status = ID_STATUS_AWAY; 
 +		if (proto->idle_status) {
 +			// ignore setting to away by idle module, after we've set ourselves idle
 +			// most standard clients represent idle and away the same way anyway,
 +			// but this allows miranda users to make use of the idle timestamp
 +			// but show our status in clist as away
 +			proto->BroadcastNewStatus(new_status);
 +			mwUserStatus_clear(&us);
 +			return;
 +		}
 +		break;
 +
 +	case mwStatus_BUSY:
 +		new_status = ID_STATUS_DND; 
 +		break;
 +
 +	case mwStatus_IDLE:
 +		new_status = ID_STATUS_AWAY; 
 +		if (!proto->first_online && !proto->options.idle_as_away) { // show our status in clist as away if idle when going online or treating idle as away
 +			mwUserStatus_clear(&us);
 +			return;
 +		}
 +		break;
 +
 +	case 8: // new 'in a meeting' status, not handled by meanwhile lib
 +		new_status = ID_STATUS_OCCUPIED;
 +		break;
 +
 +	default:
 +		{
 +			TCHAR buff[512];
 +			mir_sntprintf(buff, 512, TranslateT("Unknown user status: %d"), us.status);
 +			proto->showPopup(buff, SAMETIME_POPUP_ERROR);
 +			proto->debugLog(buff);
 +		}
 +		mwUserStatus_clear(&us);
 +		// just go online...to prevent us getting stuck 'connecting'
 +		new_status = ID_STATUS_ONLINE;
 +		break;
 +
 +	}
 +
 +	proto->m_iDesiredStatus = new_status;
 +
 +	if (proto->first_online) {
 +		proto->first_online = false;
 +		//proto->showPopup(TranslateT("Setting login status"), SAMETIME_POPUP_INFO);
 +		proto->debugLog(_T("Setting login status"));
 +		proto->SetSessionStatus(proto->login_status);
 +	} else {
 +		proto->BroadcastNewStatus(new_status);
 +	}
 +
 +	mwUserStatus_clear(&us);
 +}
 +
 +void CSametimeProto::UpdateSelfStatus()
 +{
 +	EnterCriticalSection(&session_cs);
 +	if (session) SessionSetUserStatus(session);
 +	LeaveCriticalSection(&session_cs);
 +}
 +
 +int CSametimeProto::SetSessionStatus(int status)
 +{
 +	struct mwUserStatus us;
 +	debugLog(_T("SetSessionStatus() start  status=[%d]"), status);
 +
 +	if (idle_timerid) KillTimer(0, idle_timerid);
 +
 +	us.time = (DWORD)time(0);
 +	//us.time = 0;
 +
 +	switch(status) {
 +		case ID_STATUS_FREECHAT:
 +		case ID_STATUS_ONLINE: 
 +			us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE; 
 +			break;
 +		case ID_STATUS_NA:
 +		case ID_STATUS_INVISIBLE:
 +		case ID_STATUS_ONTHEPHONE:
 +		case ID_STATUS_OUTTOLUNCH:
 +		case ID_STATUS_AWAY: 
 +			us.desc = AwayMessages.szAway; us.status = mwStatus_AWAY; 
 +			break;
 +		case ID_STATUS_OCCUPIED:
 +		case ID_STATUS_DND: 
 +			us.desc = AwayMessages.szDND; us.status = mwStatus_BUSY; 
 +			break;
 +		default:
 +			// act as online for unsupported status
 +			us.desc = AwayMessages.szOnline; us.status = mwStatus_ACTIVE; break;
 +	}
 +
 +	debugLog(_T("SetSessionStatus() mwSession_setUserStatus  us.status=[%d], us.desc:len=[%d]"), us.status, us.desc == NULL ? -1 : strlen(us.desc));
 +	mwSession_setUserStatus(session, &us);
 +
 +	return 0;
 +}
 +
 +VOID CALLBACK IdleTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)idEvent;
 +
 +	KillTimer(0, proto->idle_timerid);
 +	proto->idle_timerid = 0;
 +
 +	if (proto->idle_status) {
 +		struct mwUserStatus us;
 +		us.time = (DWORD)time(0);
 +		us.status = mwStatus_IDLE;
 +		us.desc = 0;
 +		mwSession_setUserStatus(proto->session, &us);
 +	} else {
 +		proto->SetSessionStatus(proto->m_iStatus);
 +	}
 +}
 +
 +int CSametimeProto::SetIdle(bool idle)
 +{
 +	// set a timer, to wait for any autoaway module which might set our status 
 +	debugLog(_T("CSametimeProto::SetIdle()  idle=[%d], idle_status=[%d], idle_timerid=[%d]"), idle, idle_status, idle_timerid);
 +	if (idle && !idle_status) {
 +		idle_status = true;
 +		if (!idle_timerid) 
 +			idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
 +	} else if (idle_status) {
 +		idle_status = false;
 +		if (!idle_timerid) 
 +			idle_timerid = SetTimer(0, (UINT_PTR)this, 200, IdleTimerProc);
 +	}
 +	return 0;
 +}
 +
 +void CSametimeProto::SetSessionAwayMessage(int status, const PROTOCHAR* msgT)
 +{
 +	debugLog(_T("SetSessionAwayMessage() status=[%d], msgT:len=[%d]"), status, msgT == NULL ? -1 : _tcslen(msgT));
 +
 +	ptrA msg(mir_utf8encodeT(msgT));
 +	if (status == ID_STATUS_ONLINE) {
 +		mir_free(AwayMessages.szOnline);
 +		if (msg) {
 +			AwayMessages.szOnline = mir_strdup(msg);
 +		} else AwayMessages.szOnline = 0;
 +	} else if (status == ID_STATUS_AWAY) {
 +		mir_free(AwayMessages.szAway);
 +		if (msg) {
 +			AwayMessages.szAway = mir_strdup(msg);
 +		} else AwayMessages.szAway = 0;
 +	} else if (status == ID_STATUS_DND) {
 +		mir_free(AwayMessages.szDND);
 +		if (msg) {
 +			AwayMessages.szDND = mir_strdup(msg);
 +		} else AwayMessages.szDND = 0;
 +	} else 
 +		return; // unsupported status
 +
 +	if (session){
 +		SetSessionStatus(status); // update current away message
 +	}
 +}
 +
 +static VOID CALLBACK NullAPC (DWORD_PTR)
 +{
 +	// This function intentionally left blank
 +}
 +
 +void WakeThread(HANDLE hThread)
 +{
 +	QueueUserAPC(NullAPC, hThread, 0);
 +}
 +
 +void __cdecl KeepAliveThread(LPVOID param)
 +{
 +	CSametimeProto* proto = (CSametimeProto*)param;
 +	int i = 120;
 +	proto->debugLog(_T("KeepAliveThread() start"));
 +
 +	while(1) {
 +		
 +		if (i <= 0){
 +			i = 120;
 +			// send keepalive every 120 * 250 = 30000[ms]
 +			if (mwSession_isStarted(proto->session) && proto->session){
 +				mwSession_sendKeepalive(proto->session);
 +			}
 +		}
 +		
 +		i--;
 +		
 +		SleepEx(250, TRUE);
 +		
 +		EnterCriticalSection(&(proto->session_cs));
 +		if (Miranda_Terminated() || !proto->session) {
 +			LeaveCriticalSection(&(proto->session_cs));
 +			proto->debugLog(_T("KeepAliveThread() end"));
 +			break;
 +		}
 +		LeaveCriticalSection(&(proto->session_cs));
 +	}
 +
 +	return;
 +}
 +
 +int waitcallback(unsigned int* timeout)
 +{
 +	return continue_connect ? 1 : 0;
 +}
 +
 +void __cdecl SessionThread(LPVOID param)
 +{
 +
 +	CSametimeProto* proto = (CSametimeProto*)param;
 +	HANDLE hNetlibUser = proto->m_hNetlibUser;
 +	proto->debugLog(_T("SessionThread() start"));
 +
 +	continue_connect = true;
 +
 +	//setup
 +	NETLIBOPENCONNECTION conn_data = {0};
 +	conn_data.cbSize = sizeof(NETLIBOPENCONNECTION);
 +	conn_data.flags = NLOCF_V2;
 +	conn_data.szHost = proto->options.server_name;
 +	conn_data.wPort = proto->options.port;
 +	conn_data.timeout = 20;
 +	conn_data.waitcallback = waitcallback;
 +
 +	proto->BroadcastNewStatus(ID_STATUS_CONNECTING);
 +
 +	proto->server_connection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibUser, (LPARAM)&conn_data);
 +
 +	if (!proto->server_connection) {
 +
 +		proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
 +
 +		if (continue_connect) {
 +			// real timeout - not user cancelled
 +			proto->showPopup(TranslateT("No server connection!"), SAMETIME_POPUP_ERROR);
 +		}
 +
 +		proto->debugLog(_T("SessionThread() end, no server_connection, continue_connect=[%d]"), continue_connect);
 +		return;
 +	}
 +
 +	mwSessionHandler handler = {0};
 +	handler.clear = SessionClear;
 +	handler.io_write = SessionWrite;
 +	handler.io_close = SessionClose;
 +	handler.on_stateChange = SessionStateChange;
 +	handler.on_admin = SessionAdmin;
 +	handler.on_announce = SessionAnnounce;
 +	handler.on_setPrivacyInfo = SessionSetPrivacyInfo;
 +	handler.on_setUserStatus = SessionSetUserStatus;
 +	
 +	EnterCriticalSection(&proto->session_cs);
 +	proto->session = mwSession_new(&handler);
 +
 +	proto->InitMeanwhileServices();
 +
 +	mwSession_start(proto->session);
 +	LeaveCriticalSection(&proto->session_cs);
 +
 +	mir_forkthread(KeepAliveThread, (void*)proto);
 +
 +	unsigned char* recv_buffer = (unsigned char*)mir_alloc(1024 * 32);
 +	int bytes;
 +	//while(session && server_connection && mwSession_getState(session) != mwSession_STOPPED) {
 +	while(proto->server_connection) {// && session) {// && !mwSession_isStopped(session)) { // break on error
 +		bytes = Netlib_Recv(proto->server_connection, (char *)recv_buffer, 1024 * 32, 0);
 +		proto->debugLog(_T("SessionThread() Netlib_Recv'ed bytes=[%d]"), bytes);
 +
 +		if (bytes == 0) {
 +			break;
 +		} else if (bytes == SOCKET_ERROR) {
 +			// this is normal - e.g. socket closed due to log off, during blocking read above
 +			break;
 +		} else {
 +			EnterCriticalSection(&proto->session_cs);
 +			mwSession_recv(proto->session, recv_buffer, bytes);
 +			LeaveCriticalSection(&proto->session_cs);
 +		}
 +	}
 +	mir_free(recv_buffer);
 +
 +	EnterCriticalSection(&proto->session_cs);
 +	proto->DeinitMeanwhileServices();
 +	mwSession* old_session = proto->session;
 +	proto->session = 0; // kills keepalive thread, if awake
 +	mwSession_free(old_session);
 +	LeaveCriticalSection(&proto->session_cs);
 +
 +	proto->BroadcastNewStatus(ID_STATUS_OFFLINE);
 +	proto->SetAllOffline();
 +	proto->first_online = true;
 +
 +	proto->debugLog(_T("SessionThread() end"));
 +	return;
 +}
 +
 +WORD CSametimeProto::GetClientVersion()
 +{
 +	if (!session) return 0;
 +
 +	WORD retval = 0;
 +	retval = (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MAJOR) << 8;
 +	retval |= (int)mwSession_getProperty(session, mwSession_CLIENT_VER_MINOR);
 +	return retval;
 +}
 +
 +WORD CSametimeProto::GetServerVersion()
 +{
 +	if (!session) return 0;
 +
 +	WORD retval = 0;
 +	retval = (int)mwSession_getProperty(session, mwSession_SERVER_VER_MAJOR) << 8;
 +	retval |= (int)mwSession_getProperty(session, mwSession_SERVER_VER_MINOR);
 +	return retval;
 +}
 +
 +int CSametimeProto::LogIn(int ls, HANDLE hNetlibUser)
 +{
 +	debugLog(_T("LogIn() start"));
 +
 +	EnterCriticalSection(&session_cs);
 +	if (session) {
 +		LeaveCriticalSection(&session_cs);
 +		debugLog(_T("LogIn() end, currently in session"));
 +		return 0;
 +	}
 +	LeaveCriticalSection(&session_cs);
 +
 +	login_status = ls;
 +
 +	mir_forkthread(SessionThread, (void*)this);
 +
 +	return 0;
 +}
 +
 +int CSametimeProto::LogOut()
 +{
 +	debugLog(_T("LogOut() start"));
 +	continue_connect = false;
 +
 +	EnterCriticalSection(&session_cs);
 +	if (session && server_connection && m_iStatus != ID_STATUS_OFFLINE && !mwSession_isStopped(session) && !mwSession_isStopping(session)) {
 +		debugLog(_T("LogOut() mwSession_stop"));
 +		mwSession_stop(session, 0);
 +	}
 +	LeaveCriticalSection(&session_cs);
 +	
 +	return 0;
 +}
 +
 +void CSametimeProto::InitAwayMsg()
 +{
 +	AwayMessages.szOnline = 0;
 +	AwayMessages.szAway = 0;
 +	AwayMessages.szDND = 0;
 +}
 +
 +void CSametimeProto::DeinitAwayMsg()
 +{
 +	mir_free(AwayMessages.szOnline);
 +	mir_free(AwayMessages.szAway);
 +	mir_free(AwayMessages.szDND);
 +}
 +
 +void SendAnnouncement(SendAnnouncementFunc_arg* arg)
 +{
 +	CSametimeProto* proto = arg->proto;
 +	char* utfs = mir_utf8encodeT(arg->msg);
 +	if (proto->session && arg->recipients) mwSession_sendAnnounce(proto->session, false , utfs, arg->recipients);
 +	mir_free(utfs);
 +}
 +
 +INT_PTR CSametimeProto::SessionAnnounce(WPARAM wParam, LPARAM lParam)
 +{
 +	debugLog(_T("CSametimeProto::SessionAnnounce() start"));
 +	SessionAnnounceDialogProc_arg* sadpArg = (SessionAnnounceDialogProc_arg*)mir_calloc(sizeof(SessionAnnounceDialogProc_arg));
 +	sadpArg->proto = this;
 +	sadpArg->sendAnnouncementFunc = SendAnnouncement;
 +	CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SESSIONANNOUNCE), GetDesktopWindow(), SessionAnnounceDialogProc, (LPARAM)sadpArg);
 +	return 0;
 +}
 +
 +void CSametimeProto::InitSessionMenu()
 +{
 +	debugLog(_T("CSametimeProto::InitSessionMenu()"));
 +
 +	CreateProtoService(MS_SAMETIME_MENUANNOUNCESESSION, &CSametimeProto::SessionAnnounce);
 +
 +	char service[128];
 +
 +	CLISTMENUITEM mi = { sizeof(mi) };
 +	mi.flags = CMIF_TCHAR;
 +	mi.popupPosition = 500085001;
 +	mi.position = 2000060000;
 +	mi.ptszName = LPGENT("Send Announcement...");
 +	mir_snprintf(service, sizeof(service), "%s%s", m_szModuleName, MS_SAMETIME_MENUANNOUNCESESSION);
 +	mi.pszService = service;
 +	mi.icolibItem = GetIconHandle(IDI_ICON_ANNOUNCE);
 +	mi.pszContactOwner = m_szModuleName;
 +	hSessionAnnounceMenuItem = Menu_AddContactMenuItem(&mi);
 +}
 +
 +void CSametimeProto::DeinitSessionMenu()
 +{
 +	debugLog(_T("CSametimeProto::DeinitSessionMenu()"));
 +	CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hSessionAnnounceMenuItem, (LPARAM)0);
 +}
 +
 +void CSametimeProto::InitCritSection()
 +{
 +	debugLog(_T("CSametimeProto::InitCritSection()"));
 +	InitializeCriticalSection(&session_cs);
 +}
 +
 +void CSametimeProto::DeinitCritSection()
 +{
 +	debugLog(_T("CSametimeProto::DeinitCritSection()"));
 +	DeleteCriticalSection(&session_cs);
 +}
 +
 +void CSametimeProto::InitGroupChats()
 +{
 +	debugLog(_T("CSametimeProto::InitGroupChats()"));
 +
 +	// register with chat module
 +	GCREGISTER gcr = { sizeof(gcr) };
 +	gcr.pszModule = m_szModuleName;
 +	gcr.ptszDispName = m_tszUserName;
 +	gcr.dwFlags = 0;
 +	gcr.iMaxText = MAX_MESSAGE_SIZE;
 +	gcr.nColors = 0;
 +	gcr.pColors = 0;
 +	CallService(MS_GC_REGISTER, 0, (LPARAM)(GCREGISTER*) &gcr);
 +}
  | 
