From 7954c7a4bdbf73baa7fb15fbabf90937e1c6f6f0 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Thu, 8 Aug 2013 09:49:56 +0000 Subject: WinPopup moved to NotAdopted coz don't work git-svn-id: http://svn.miranda-ng.org/main/trunk@5626 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/!NotAdopted/WinPopup/src/netbios_name.cpp | 630 ++++++++++++++++++++++ 1 file changed, 630 insertions(+) create mode 100644 plugins/!NotAdopted/WinPopup/src/netbios_name.cpp (limited to 'plugins/!NotAdopted/WinPopup/src/netbios_name.cpp') diff --git a/plugins/!NotAdopted/WinPopup/src/netbios_name.cpp b/plugins/!NotAdopted/WinPopup/src/netbios_name.cpp new file mode 100644 index 0000000000..befffb04e5 --- /dev/null +++ b/plugins/!NotAdopted/WinPopup/src/netbios_name.cpp @@ -0,0 +1,630 @@ +/* + +WinPopup Protocol plugin for Miranda IM. + +Copyright (C) 2004-2011 Nikolay Raspopov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +//////////////////////////////////////////////////////////////////////// +// Class netbios_name + +netbios_name::netbios_name(LPCTSTR n, UCHAR type, bool group, UCHAR lana) : + m_managed (false), + m_registered (false), + m_duplicated (false), + m_error (false), + m_lana (lana), + m_listener (NULL), + m_dgreceiver (NULL), + m_term (NULL) +{ + // Преобразование имени в NetBIOS-имя + int len = NCBNAMSZ - 1; + CT2A nA( n ); + LPCSTR src = (LPCSTR)nA; + LPSTR dst = (LPSTR)netbiosed.name; + for ( ; len && *src; --len, ++dst, ++src ) + *dst = *src; + for ( ; len; --len ) + *dst++ = ' '; + *dst = (CHAR)type; + CharUpperBuffA( (LPSTR)netbiosed.name, NCBNAMSZ - 1 ); + CharToOemBuffA( (LPSTR)netbiosed.name, (LPSTR)netbiosed.name, NCBNAMSZ - 1 ); + netbiosed.name_num = 0; + netbiosed.name_flags = (UCHAR)( group ? GROUP_NAME : UNIQUE_NAME ); + + original = GetANSIName(); +} + +netbios_name::netbios_name(const NAME_BUFFER& n, UCHAR lana) : + m_managed (false), + m_registered (false), + m_duplicated (false), + m_error (false), + m_lana (lana), + m_listener (NULL), + m_dgreceiver (NULL), + m_term (NULL) +{ + CopyMemory (&netbiosed, &n, sizeof (NAME_BUFFER)); + original = GetANSIName(); +} + +netbios_name& netbios_name::operator=(const netbios_name& n) +{ + _ASSERTE (m_managed == false); + m_managed = n.m_managed; + _ASSERTE (m_registered == false); + m_registered = n.m_registered; + _ASSERTE (m_duplicated == false); + m_duplicated = n.m_duplicated; + _ASSERTE (m_error == false); + m_error = n.m_error; + m_lana = n.m_lana; + _ASSERTE( m_listener == NULL ); + m_listener = NULL; + _ASSERTE( m_dgreceiver == NULL ); + m_dgreceiver = NULL; + _ASSERTE( m_term == NULL ); + m_term = NULL; + CopyMemory (&netbiosed, &n.netbiosed, sizeof( NAME_BUFFER )); + original = n.original; + return *this; +} + +netbios_name& netbios_name::operator= (const UCHAR* n) +{ + _ASSERTE (m_managed == false); + m_managed = false; + _ASSERTE (m_registered == false); + m_registered = false; + _ASSERTE (m_duplicated == false); + m_duplicated = false; + _ASSERTE (m_error == false); + m_error = false; + m_lana = 0; + _ASSERTE( m_listener == NULL ); + m_listener = NULL; + _ASSERTE( m_dgreceiver == NULL ); + m_dgreceiver = NULL; + _ASSERTE( m_term == NULL ); + m_term = NULL; + CopyMemory (netbiosed.name, n, NCBNAMSZ); + netbiosed.name_num = 0; + netbiosed.name_flags = UNIQUE_NAME; + original = GetANSIName(); + + return *this; +} + +bool netbios_name::operator== (const NAME_BUFFER& n) const +{ + return ( netbiosed.name [NCBNAMSZ - 1] == n.name [NCBNAMSZ - 1] ) && + ( ( netbiosed.name_flags & GROUP_NAME ) == ( n.name_flags & GROUP_NAME ) ) && + ( memcmp( netbiosed.name, n.name, NCBNAMSZ - 1 ) == 0 ); +} + +bool netbios_name::operator!= (const NAME_BUFFER& n) const +{ + return ! operator==( n ); +} + +bool netbios_name::operator== (const netbios_name& n) const +{ + return ( m_lana == n.m_lana ) && operator==( n.netbiosed ); +} + +bool netbios_name::operator!= (const netbios_name& n) const +{ + return ( m_lana != n.m_lana ) || operator!=( n.netbiosed ); +} + +bool netbios_name::Register() +{ + m_managed = true; + + UCHAR ret = AddName (); + LOG("Register NetBIOS name \"%s\" on lana %d num=%d : 0x%02x \"%s\"", GetANSIFullName(), m_lana, netbiosed.name_num, ret, GetNetbiosError( ret ) ); + m_registered = (ret == NRC_GOODRET); + m_duplicated = (ret == NRC_DUPNAME); + if ( ret != NRC_GOODRET && ret != NRC_DUPNAME ) + { + WarningBox (NULL, (DWORD)MAKE_HRESULT (0, FACILITY_NETBIOS, ret), + _T("%s: %s"), TranslateT ("Cannot register NetBIOS name"), (LPCTSTR)CA2T( GetANSIFullName() ) ); + } + + if (!m_term) + m_term = CreateEvent (NULL, TRUE, FALSE, NULL); + else + ResetEvent (m_term); + + if ( m_term && !m_listener ) + m_listener = (HANDLE)mir_forkthread( ListenerThread, this ); + + if ( m_term && !m_dgreceiver && + // NOTE: Под Win9x нельзя запускать ожидание датаграмм для имён-дубликатов + // т.к. потом невозможно выбить управление из функции Netbios() даже если + // разрегистрировать имя + !m_duplicated ) + { + m_dgreceiver = (HANDLE)mir_forkthread( DatagramReceiverThread, this ); + } + + return m_registered; +} + +void netbios_name::AskForDestroy() +{ + if (m_term) + SetEvent (m_term); +} + +void netbios_name::Destroy() +{ + // Запрос останова рабочего потока-слушателя + if ( m_term ) SetEvent( m_term ); + + // Удаление имени (если не удалить, то слушатель не завершиться) + UCHAR ret = DeleteName (); + LOG("Unregister NetBIOS name \"%s\" on lana %d num=%d : 0x%02x \"%s\"", GetANSIFullName(), m_lana, netbiosed.name_num, ret, GetNetbiosError( ret ) ); + m_registered = !(ret == NRC_GOODRET); + if ( m_duplicated ) + { + // Восстановление имени + m_duplicated = false; + + // NOTE: Восстанавливать не надо - проблем больше + // uReturn = AddName (); + // LOG("Restore NetBIOS name \"%s\" on lana %d : 0x%02x", GetANSIFullName(), m_lana, uReturn); + } + + // Ожидание, а затем принудительный останов + if ( m_listener ) + { + if ( m_term ) SetEvent( m_term ); + if (WaitForSingleObject (m_listener, ALMOST_INFINITE) == WAIT_TIMEOUT) + { + LOG("Terminate NetBIOS listener!"); + TerminateThread (m_listener, 0); + } + m_listener = NULL; + } + + if ( m_dgreceiver ) + { + if ( m_term ) SetEvent( m_term ); + if (WaitForSingleObject (m_dgreceiver, ALMOST_INFINITE) == WAIT_TIMEOUT) + { + LOG("Terminate NetBIOS datagram receiver!"); + TerminateThread (m_dgreceiver, 0); + } + m_dgreceiver = NULL; + } + + if ( m_term ) + { + CloseHandle (m_term); + m_term = NULL; + } +} + +CStringA netbios_name::GetANSIName() const +{ + CStringA sName; + LPSTR szName = sName.GetBuffer( NCBNAMSZ ); + CopyMemory( szName, (LPCSTR)netbiosed.name, NCBNAMSZ - 1 ); + szName[ NCBNAMSZ - 1 ] = 0; + sName.ReleaseBuffer(); + sName.Trim(); + sName.OemToAnsi(); + return sName; +} + +CStringA netbios_name::GetANSIFullName() const +{ + CStringA sType; + sType.Format( " <%02X>", GetType() ); + return original + sType; +} + +UCHAR netbios_name::GetType () const +{ + return netbiosed.name [NCBNAMSZ - 1]; +} + +bool netbios_name::IsGroupName () const +{ + return ((netbiosed.name_flags & GROUP_NAME) == GROUP_NAME); +} + +bool netbios_name::IsRegistered () const +{ + return m_registered; +} + +bool netbios_name::IsDuplicated () const +{ + return m_duplicated; +} + +bool netbios_name::IsError () const +{ + return m_error; +} + +bool netbios_name::IsOwnName () const +{ + return m_managed; +} + +UCHAR netbios_name::GetLana () const +{ + return m_lana; +} + +bool netbios_name::GetRealSender (UCHAR lsn, CStringA& sRealFrom) const +{ + sRealFrom.Empty (); + + SESSION_INFO_BLOCK sibSession = {}; + UCHAR dwInfoRes = pluginNetBIOS.Stat( *this, &sibSession ); + if ( dwInfoRes == NRC_GOODRET ) + { + for ( int i = 0; i < sibSession.sib_header.num_sess; i++ ) + { + if ( sibSession.sib_Names [i].lsn == lsn ) + { + // Наша сессия + const char* n = (const char*)sibSession.sib_Names [i].remote_name; + BYTE j = NCBNAMSZ - 2; + for ( ; j && ( n [ j ] == ' ' ); --j ); + sRealFrom.Append( n, j + 1 ); + sRealFrom.OemToAnsi(); + return true; + } + } + } + return false; +} + +size_t netbios_name::GetLength() const +{ + return (size_t)original.GetLength(); +} + +UCHAR netbios_name::AddName() +{ + return pluginNetBIOS.AddName( *this ); +} + +UCHAR netbios_name::DeleteName() +{ + return pluginNetBIOS.DeleteName( *this ); +} + +typedef struct _ReceiverData +{ + netbios_name* self; + UCHAR lsn; +} ReceiverData; + +void netbios_name::Listener() +{ + m_error = false; + while ( WaitForSingleObject( m_term, 50 ) == WAIT_TIMEOUT ) + { + UCHAR lsn = 0; + UCHAR ret = pluginNetBIOS.Listen( *this, lsn ); + if ( ret != NRC_GOODRET ) + { + LOG( "Listener : Closing \"%s\"", GetANSIFullName() ); + m_error = true; + break; + } + + LOG( "Listener : Got packet for \"%s\"", GetANSIFullName() ); + if ( ReceiverData* data = (ReceiverData*)mir_alloc( sizeof( ReceiverData ) ) ) + { + data->self = this; + data->lsn = lsn; + mir_forkthread( ReceiverThread, data ); + } + } +} + +void netbios_name::ListenerThread(LPVOID param) +{ + if ( netbios_name* pName = (netbios_name*)param ) + { + pName->Listener(); + pName->m_listener = NULL; + } +} + +void netbios_name::DatagramReceiver() +{ + UCHAR* SMBBlock = (UCHAR*)mir_alloc( 65536 ); + if ( ! SMBBlock ) + { + m_error = true; + return; + } + + m_error = false; + while ( WaitForSingleObject ( m_term, 50 ) == WAIT_TIMEOUT ) + { + ZeroMemory( SMBBlock, 65536 ); + + WORD iReadedBytes = 65535; + netbios_name nname_from; + UCHAR ret = pluginNetBIOS.RecvDatagram( nname_from, *this, SMBBlock, iReadedBytes ); + if ( ret != NRC_GOODRET ) + { + // Ошибка - выход + m_error = true; + break; + } + + nname_from.m_lana = m_lana; + + LOG( "Got datagram from \"%s\" to \"%s\"", nname_from.GetANSIFullName(), GetANSIFullName() ); + + // Свое собственное сообщение? + if ( IsItMe ( CA2T( nname_from.original ) ) ) + { + LOG( "DatagramReceiver : Ignoring my datagram" ); + continue; + } + + // Обработка датаграмм + if ( iReadedBytes > 2 && *(WORD*)SMBBlock == SM_MAGIC ) + { + UCHAR iMsgType = SMBBlock[ 2 ]; + switch ( iMsgType ) + { + case SM_GETSTATUS: + // Отвечаем своим статусом + LOG( "DatagramReceiver : It's status request" ); + pluginNetBIOS.SendStatus( *this, nname_from ); + break; + + case SM_SENDSTATUS: + // Находим контакт и ставим его статус + if ( iReadedBytes == 2 + 1 + 4 ) + { + HANDLE hContact = GetContact( CA2T( nname_from.original ) ); + if ( hContact ) + { + LOG( "DatagramReceiver : It's status answer" ); + SetContactStatus( hContact, *(__int32*)(SMBBlock + 2 + 1), false ); + } + else + LOG( "DatagramReceiver : Unknown contact" ); + } + else + LOG( "DatagramReceiver : Invalid format" ); + break; + + case SM_GETAWAYMESSAGE: + // Отвечаем своим эвей-сообщением + LOG( "DatagramReceiver : It's away request" ); + pluginNetBIOS.SendAway( *this, nname_from ); + break; + + case SM_SENDAWAYMESSAGE: + // Находим контакт и ставим его эвей-сообщение + if ( iReadedBytes >= 2 + 1 + 4 ) + { + if ( HANDLE hContact = GetContact( CA2T( nname_from.original ) ) ) + { + LPCSTR szAway = (LPCSTR)( SMBBlock + 2 + 1 + 4 ); + SMBBlock[ iReadedBytes ] = 0; // ASCII -> ASCIIZ + + LOG( "DatagramReceiver : It's away answer \"%s\"", szAway ); + SetContactAway( hContact, szAway ); + } + else + LOG( "DatagramReceiver : Unknown contact" ); + } + else + LOG( "DatagramReceiver : Invalid format" ); + break; + + case SM_GETAVATAR: + // Отвечаем своим аватаром + LOG( "DatagramReceiver : It's avatar request." ); + pluginNetBIOS.SendAvatar( *this, nname_from ); + break; + + case SM_SENDAVATAR: + // Находим контакт и ставим его аватар + if ( iReadedBytes >= 2 + 1 && iReadedBytes < MAX_AVATAR_SIZE + 3 ) + { + if ( HANDLE hContact = GetContact( CA2T( nname_from.original ) ) ) + { + LOG( "DatagramReceiver : It's avatar answer" ); + SetContactAvatar( hContact, SMBBlock + 2 + 1, (DWORD)iReadedBytes - 3 ); + } + else + LOG( "DatagramReceiver : Unknown contact" ); + } + else + LOG( "DatagramReceiver : Invalid format or too big avatar" ); + break; + + default: + LOG( "DatagramReceiver : Unsupported message type 0x%02x", iMsgType ); + } + } + else + LOG( "DatagramReceiver : Unsupported data 0x%04x", *(WORD*)SMBBlock ); + } + + mir_free( SMBBlock ); +} + +void netbios_name::DatagramReceiverThread(LPVOID param) +{ + if ( netbios_name* pName = (netbios_name*)param ) + { + pName->DatagramReceiver(); + pName->m_dgreceiver = NULL; + } +} + +void netbios_name::Receiver(UCHAR lsn) +{ + // Created by Ilja Razinkov (also known as IPv6), 2002, IPv6Intendo@yandex.ru + // Keep this comment if you redistribute this file + + UCHAR* SMBBlock = (UCHAR*)mir_alloc( 65536 ); + if ( ! SMBBlock ) + return; + + CStringA sTo, sFrom, sMessage; + UCHAR nRes; + for (;;) + { + ZeroMemory( SMBBlock, 65536 ); + + // Получение очередного блока данных + WORD iReadedBytes = 65535; + nRes = pluginNetBIOS.Recv (m_lana, lsn, SMBBlock, iReadedBytes); + if (nRes != NRC_GOODRET) + { + LOG( "Receiver : Error while receiving data block" ); + break; + } + + // Смотрим что к нам пришло - сообщение или что-то неизвестное + if ( iReadedBytes < 4 || *(DWORD*)SMBBlock != SMB_MAGIC ) + { + LOG( "Receiver : Unsupported data 0x%08x", *(DWORD*)SMBBlock ); + break; + } + + UCHAR iMsgType = SMBBlock [4]; + if (iMsgType != SMBsends && + iMsgType != SMBsendstrt && + iMsgType != SMBsendend && + iMsgType != SMBsendtxt) + { + LOG( "Receiver : Unsupported message type 0x%02x", iMsgType ); + break; + } + + // Шлём подтверждение + UCHAR szReply [SMB_HEADER_SIZE + 5]; + UCHAR* szReplyData = + pluginNetBIOS.SetSMBHeaderCommand (szReply, iMsgType, sizeof (szReply)); + if (iMsgType == SMBsendstrt) + { + // Код сообщения + static UCHAR rnd = 1; + szReplyData [0] = 1; // Номер сообщения + szReplyData [1] = rnd++; // + if ( rnd > 5 ) + rnd = 1; + } + nRes = pluginNetBIOS.Send (m_lana, lsn, szReply, + (WORD)( (iMsgType == SMBsendstrt) ? (SMB_HEADER_SIZE + 5) : (SMB_HEADER_SIZE + 3) ) ); + if ( nRes != NRC_GOODRET ) + { + // Нефатальная ошибка + LOG( "Receiver : Error while sending ack" ); + } + + // Действия в зависимости от типа сообщения + if (iMsgType == SMBsends) + { + LOG( "Receiver : Got single-block message" ); + // Короткое сообщение, вытаскиваем данные и выходим... + sFrom = (const char*) SMBBlock + SMB_HEADER_SIZE + 4; + int iFromOffset = sFrom.GetLength (); + sTo = (const char*) SMBBlock + SMB_HEADER_SIZE + 4 + iFromOffset + 2; + int iToOffset = sTo.GetLength (); + sMessage = (const char*) SMBBlock + SMB_HEADER_SIZE + 4 + iFromOffset + 2 + + iToOffset + 4; + break; + } + else if (iMsgType == SMBsendstrt) + { + LOG( "Receiver : Got start of multi-block message" ); + // Кусочковое сообщение, начало, смотрим от кого и кому + sFrom = (const char*) SMBBlock + SMB_HEADER_SIZE + 4; + int iFromOffset = sFrom.GetLength (); + sTo = (const char*) SMBBlock + SMB_HEADER_SIZE + iFromOffset + 4 + 2; + } + else if (iMsgType == SMBsendtxt) + { + // Кусочковое сообщение, блок с данными, конкатенируем... + int iConcatSize = iReadedBytes - SMB_HEADER_SIZE - 8; + LOG( "Receiver : Got text (%d-%d bytes) of multi-block message", sMessage.GetLength(), sMessage.GetLength() + iConcatSize - 1 ); + sMessage.Append ((const char*) (SMBBlock + SMB_HEADER_SIZE + 8), iConcatSize); + } + else if (iMsgType == SMBsendend) + { + LOG( "Receiver : Got end of multi-block message" ); + // Кусочковое сообщение, конец, все получено, выходим + break; + } + } + + sMessage.Replace( "\x14", "\r\n" ); // <14> -> + + sTo.OemToAnsi(); + sFrom.OemToAnsi(); + sMessage.OemToAnsi(); + + // Смотрим информацию о сессии + CStringA sRealFrom; + if (GetRealSender (lsn, sRealFrom)) + { + LOG( "Receiver : Message from \"%s\" (real \"%s\") to \"%s\"", (LPCSTR)sFrom, (LPCSTR)sRealFrom, (LPCSTR)sTo); + sFrom = sRealFrom; + } + else + { + LOG( "Receiver : Message from \"%s\" (real sender unknown) to \"%s\"", (LPCSTR)sFrom, (LPCSTR)sTo); + } + + // Скажем до свиданья... + pluginNetBIOS.Hangup (m_lana, lsn); + + // Открываем сообщение (пустое игнорируем) + if ( ! sMessage.IsEmpty() ) + { + ReceiveContactMessage( CA2T( sFrom ), CA2T( sTo ), CA2T( sMessage ), sMessage.GetLength ()); + } + else + { + LOG( "Receiver : Ignoring empty message" ); + } + + mir_free( SMBBlock ); +} + +void netbios_name::ReceiverThread(LPVOID param) +{ + if ( ReceiverData* data = (ReceiverData*)param ) + { + data->self->Receiver( data->lsn ); + mir_free( data ); + } +} -- cgit v1.2.3