diff options
Diffstat (limited to 'miranda-wine/protocols/JabberG/jabber_util.cpp')
-rw-r--r-- | miranda-wine/protocols/JabberG/jabber_util.cpp | 1133 |
1 files changed, 1133 insertions, 0 deletions
diff --git a/miranda-wine/protocols/JabberG/jabber_util.cpp b/miranda-wine/protocols/JabberG/jabber_util.cpp new file mode 100644 index 0000000..d725f98 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_util.cpp @@ -0,0 +1,1133 @@ +/*
+
+Jabber Protocol Plugin for Miranda IM
+Copyright ( C ) 2002-04 Santithorn Bunchua
+Copyright ( C ) 2005-06 George Hazan
+
+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.
+
+File name : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_util.cpp,v $
+Revision : $Revision: 3667 $
+Last change on : $Date: 2006-08-31 18:10:18 +0400 (Чтв, 31 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+#include "jabber_list.h"
+#include "sha1.h"
+
+extern CRITICAL_SECTION mutex;
+extern UINT jabberCodePage;
+
+static CRITICAL_SECTION serialMutex;
+static unsigned int serial;
+
+void __stdcall JabberSerialInit( void )
+{
+ InitializeCriticalSection( &serialMutex );
+ serial = 0;
+}
+
+void __stdcall JabberSerialUninit( void )
+{
+ DeleteCriticalSection( &serialMutex );
+}
+
+unsigned int __stdcall JabberSerialNext( void )
+{
+ unsigned int ret;
+
+ EnterCriticalSection( &serialMutex );
+ ret = serial;
+ serial++;
+ LeaveCriticalSection( &serialMutex );
+ return ret;
+}
+
+void __stdcall JabberLog( const char* fmt, ... )
+{
+ va_list vararg;
+ va_start( vararg, fmt );
+ char* str = ( char* )alloca( 32000 );
+ mir_vsnprintf( str, 32000, fmt, vararg );
+ va_end( vararg );
+
+ JCallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+}
+
+// Caution: DO NOT use JabberSend() to send binary ( non-string ) data
+int __stdcall JabberSend( HANDLE hConn, XmlNode& node )
+{
+ char* str = node.getText();
+ int size = strlen( str ), result;
+
+ EnterCriticalSection( &mutex );
+
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+int __stdcall JabberSend( HANDLE hConn, const char* fmt, ... )
+{
+ int result;
+
+ EnterCriticalSection( &mutex );
+
+ va_list vararg;
+ va_start( vararg,fmt );
+ int size = 512;
+ char* str = ( char* )mir_alloc( size );
+ while ( _vsnprintf( str, size, fmt, vararg ) == -1 ) {
+ size += 512;
+ str = ( char* )mir_realloc( str, size );
+ }
+ va_end( vararg );
+
+ size = strlen( str );
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberHContactFromJID - looks for the HCONTACT with required JID
+
+HANDLE __stdcall JabberHContactFromJID( const TCHAR* jid )
+{
+ if ( jid == NULL )
+ return ( HANDLE )NULL;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, jid );
+
+ HANDLE hContactMatched = NULL;
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( jabberProtoName, szProto )) {
+ DBVARIANT dbv;
+ int result = JGetStringT( hContact, "jid", &dbv );
+ if ( result )
+ result = JGetStringT( hContact, "ChatRoomID", &dbv );
+
+ if ( !result ) {
+ int result;
+ if ( item != NULL )
+ result = lstrcmpi( jid, dbv.ptszVal );
+ else
+ result = JabberCompareJids( jid, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if ( !result ) {
+ hContactMatched = hContact;
+ break;
+ } } }
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ return hContactMatched;
+}
+
+TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid )
+{
+ const TCHAR* p;
+ TCHAR* nick;
+
+ if (( p = _tcschr( jid, '@' )) == NULL )
+ p = _tcschr( jid, '/' );
+
+ if ( p != NULL ) {
+ if (( nick=( TCHAR* )mir_alloc( sizeof(TCHAR)*( int( p-jid )+1 ))) != NULL ) {
+ _tcsncpy( nick, jid, p-jid );
+ nick[p-jid] = '\0';
+ }
+ }
+ else nick = mir_tstrdup( jid );
+ return nick;
+}
+
+char* __stdcall JabberUrlDecode( char* str )
+{
+ char* p, *q;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !strncmp( p, "&", 5 )) { *q = '&'; p += 4; }
+ else if ( !strncmp( p, "'", 6 )) { *q = '\''; p += 5; }
+ else if ( !strncmp( p, ">", 4 )) { *q = '>'; p += 3; }
+ else if ( !strncmp( p, "<", 4 )) { *q = '<'; p += 3; }
+ else if ( !strncmp( p, """, 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+ return str;
+}
+
+void __stdcall JabberUrlDecodeW( WCHAR* str )
+{
+ if ( str == NULL )
+ return;
+
+ WCHAR* p, *q;
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !wcsncmp( p, L"&", 5 )) { *q = '&'; p += 4; }
+ else if ( !wcsncmp( p, L"'", 6 )) { *q = '\''; p += 5; }
+ else if ( !wcsncmp( p, L">", 4 )) { *q = '>'; p += 3; }
+ else if ( !wcsncmp( p, L"<", 4 )) { *q = '<'; p += 3; }
+ else if ( !wcsncmp( p, L""", 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+}
+
+char* __stdcall JabberUrlEncode( const char* str )
+{
+ char* s, *p, *q;
+ int c;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( c=0,p=( char* )str; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': c += 5; break;
+ case '\'': c += 6; break;
+ case '>': c += 4; break;
+ case '<': c += 4; break;
+ case '"': c += 6; break;
+ default: c++; break;
+ }
+ }
+ if (( s=( char* )mir_alloc( c+1 )) != NULL ) {
+ for ( p=( char* )str,q=s; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': strcpy( q, "&" ); q += 5; break;
+ case '\'': strcpy( q, "'" ); q += 6; break;
+ case '>': strcpy( q, ">" ); q += 4; break;
+ case '<': strcpy( q, "<" ); q += 4; break;
+ case '"': strcpy( q, """ ); q += 6; break;
+ default: *q = *p; q++; break;
+ }
+ }
+ *q = '\0';
+ }
+
+ return s;
+}
+
+static void __stdcall sttUtf8Decode( const BYTE* str, wchar_t* tempBuf )
+{
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F ) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+}
+
+
+char* __stdcall JabberUtf8Decode( char* str, WCHAR** ucs2 )
+{
+ if ( str == NULL )
+ return NULL;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return str;
+ }
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ sttUtf8Decode(( BYTE* )str, tempBuf );
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )mir_alloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+ return str;
+}
+
+char* __stdcall JabberUtf8EncodeW( const WCHAR* wstr )
+{
+ const WCHAR* w;
+
+ // Convert unicode to utf8
+ int len = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 ) len++;
+ else if ( *w < 0x0800 ) len += 2;
+ else len += 3;
+ }
+
+ unsigned char* szOut = ( unsigned char* )mir_alloc( len+1 );
+ if ( szOut == NULL )
+ return NULL;
+
+ int i = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 )
+ szOut[i++] = ( unsigned char ) *w;
+ else if ( *w < 0x0800 ) {
+ szOut[i++] = 0xc0 | (( *w ) >> 6 );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ }
+ else {
+ szOut[i++] = 0xe0 | (( *w ) >> 12 );
+ szOut[i++] = 0x80 | (( ( *w ) >> 6 ) & 0x3f );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ } }
+
+ szOut[ i ] = '\0';
+ return ( char* )szOut;
+}
+
+void __stdcall JabberUtfToTchar( const char* pszValue, size_t cbLen, LPTSTR& dest )
+{
+ char* pszCopy = ( char* )alloca( cbLen+1 );
+ memcpy( pszCopy, pszValue, cbLen );
+ pszCopy[ cbLen ] = 0;
+
+ JabberUrlDecode( pszCopy );
+
+ #if defined( _UNICODE )
+ JabberUtf8Decode( pszCopy, &dest );
+ #else
+ JabberUtf8Decode( pszCopy, NULL );
+ dest = mir_strdup( pszCopy );
+ #endif
+}
+
+char* __stdcall JabberUtf8Encode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ // Convert local codepage to unicode
+ int len = strlen( str );
+ WCHAR* wszTemp = ( WCHAR* )alloca( sizeof( WCHAR )*( len+1 ));
+ MultiByteToWideChar( jabberCodePage, 0, str, -1, wszTemp, len+1 );
+
+ return JabberUtf8EncodeW( wszTemp );
+}
+
+char* __stdcall JabberSha1( char* str )
+{
+ SHA1Context sha;
+ uint8_t digest[20];
+ char* result;
+ int i;
+
+ if ( str == NULL )
+ return NULL;
+
+ SHA1Reset( &sha );
+ SHA1Input( &sha, ( const unsigned __int8* )str, strlen( str ));
+ SHA1Result( &sha, digest );
+ if (( result=( char* )mir_alloc( 41 )) == NULL )
+ return NULL;
+
+ for ( i=0; i<20; i++ )
+ sprintf( result+( i<<1 ), "%02x", digest[i] );
+ return result;
+}
+
+char* __stdcall JabberUnixToDos( const char* str )
+{
+ char* p, *q, *res;
+ int extra;
+
+ if ( str==NULL || str[0]=='\0' )
+ return NULL;
+
+ extra = 0;
+ for ( p=( char* )str; *p!='\0'; p++ ) {
+ if ( *p == '\n' )
+ extra++;
+ }
+ if (( res=( char* )mir_alloc( strlen( str )+extra+1 )) != NULL ) {
+ for ( p=( char* )str,q=res; *p!='\0'; p++,q++ ) {
+ if ( *p == '\n' ) {
+ *q = '\r';
+ q++;
+ }
+ *q = *p;
+ }
+ *q = '\0';
+ }
+ return res;
+}
+
+WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str )
+{
+ if ( str==NULL || str[0]=='\0' )
+ return NULL;
+
+ const WCHAR* p;
+ WCHAR* q, *res;
+ int extra = 0;
+
+ for ( p = str; *p!='\0'; p++ ) {
+ if ( *p == '\n' )
+ extra++;
+ }
+ if (( res = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str ) + extra + 1 )) ) != NULL ) {
+ for ( p = str,q=res; *p!='\0'; p++,q++ ) {
+ if ( *p == '\n' ) {
+ *q = '\r';
+ q++;
+ }
+ *q = *p;
+ }
+ *q = '\0';
+ }
+ return res;
+}
+
+char* __stdcall JabberHttpUrlEncode( const char* str )
+{
+ unsigned char* p, *q, *res;
+
+ if ( str == NULL ) return NULL;
+ res = ( BYTE* ) mir_alloc( 3*strlen( str ) + 1 );
+ for ( p=( BYTE* )str,q=res; *p!='\0'; p++,q++ ) {
+ if (( *p>='A' && *p<='Z' ) || ( *p>='a' && *p<='z' ) || ( *p>='0' && *p<='9' ) || strchr( "$-_.+!*'(),", *p )!=NULL ) {
+ *q = *p;
+ }
+ else {
+ sprintf(( char* )q, "%%%02X", *p );
+ q += 2;
+ }
+ }
+ *q = '\0';
+ return ( char* )res;
+}
+
+void __stdcall JabberHttpUrlDecode( char* str )
+{
+ unsigned char* p, *q;
+ unsigned int code;
+
+ if ( str == NULL ) return;
+ for ( p=q=( BYTE* )str; *p!='\0'; p++,q++ ) {
+ if ( *p=='%' && *( p+1 )!='\0' && isxdigit( *( p+1 )) && *( p+2 )!='\0' && isxdigit( *( p+2 )) ) {
+ sscanf(( char* )p+1, "%2x", &code );
+ *q = ( unsigned char ) code;
+ p += 2;
+ }
+ else {
+ *q = *p;
+ } }
+
+ *q = '\0';
+}
+
+int __stdcall JabberCombineStatus( int status1, int status2 )
+{
+ // Combine according to the following priority ( high to low )
+ // ID_STATUS_FREECHAT
+ // ID_STATUS_ONLINE
+ // ID_STATUS_DND
+ // ID_STATUS_AWAY
+ // ID_STATUS_NA
+ // ID_STATUS_INVISIBLE ( valid only for TLEN_PLUGIN )
+ // ID_STATUS_OFFLINE
+ // other ID_STATUS in random order ( actually return status1 )
+ if ( status1==ID_STATUS_FREECHAT || status2==ID_STATUS_FREECHAT )
+ return ID_STATUS_FREECHAT;
+ if ( status1==ID_STATUS_ONLINE || status2==ID_STATUS_ONLINE )
+ return ID_STATUS_ONLINE;
+ if ( status1==ID_STATUS_DND || status2==ID_STATUS_DND )
+ return ID_STATUS_DND;
+ if ( status1==ID_STATUS_AWAY || status2==ID_STATUS_AWAY )
+ return ID_STATUS_AWAY;
+ if ( status1==ID_STATUS_NA || status2==ID_STATUS_NA )
+ return ID_STATUS_NA;
+ if ( status1==ID_STATUS_INVISIBLE || status2==ID_STATUS_INVISIBLE )
+ return ID_STATUS_INVISIBLE;
+ if ( status1==ID_STATUS_OFFLINE || status2==ID_STATUS_OFFLINE )
+ return ID_STATUS_OFFLINE;
+ return status1;
+}
+
+struct tagErrorCodeToStr {
+ int code;
+ TCHAR* str;
+}
+static JabberErrorCodeToStrMapping[] = {
+ { JABBER_ERROR_REDIRECT, _T("Redirect") },
+ { JABBER_ERROR_BAD_REQUEST, _T("Bad request") },
+ { JABBER_ERROR_UNAUTHORIZED, _T("Unauthorized") },
+ { JABBER_ERROR_PAYMENT_REQUIRED, _T("Payment required") },
+ { JABBER_ERROR_FORBIDDEN, _T("Forbidden") },
+ { JABBER_ERROR_NOT_FOUND, _T("Not found") },
+ { JABBER_ERROR_NOT_ALLOWED, _T("Not allowed") },
+ { JABBER_ERROR_NOT_ACCEPTABLE, _T("Not acceptable") },
+ { JABBER_ERROR_REGISTRATION_REQUIRED, _T("Registration required") },
+ { JABBER_ERROR_REQUEST_TIMEOUT, _T("Request timeout") },
+ { JABBER_ERROR_CONFLICT, _T("Conflict") },
+ { JABBER_ERROR_INTERNAL_SERVER_ERROR, _T("Internal server error") },
+ { JABBER_ERROR_NOT_IMPLEMENTED, _T("Not implemented") },
+ { JABBER_ERROR_REMOTE_SERVER_ERROR, _T("Remote server error") },
+ { JABBER_ERROR_SERVICE_UNAVAILABLE, _T("Service unavailable") },
+ { JABBER_ERROR_REMOTE_SERVER_TIMEOUT, _T("Remote server timeout") },
+ { -1, _T("Unknown error") }
+};
+
+TCHAR* __stdcall JabberErrorStr( int errorCode )
+{
+ int i;
+
+ for ( i=0; JabberErrorCodeToStrMapping[i].code!=-1 && JabberErrorCodeToStrMapping[i].code!=errorCode; i++ );
+ return JabberErrorCodeToStrMapping[i].str;
+}
+
+TCHAR* __stdcall JabberErrorMsg( XmlNode *errorNode )
+{
+ TCHAR* errorStr, *str;
+ int errorCode;
+
+ errorStr = ( TCHAR* )mir_alloc( 256 * sizeof( TCHAR ));
+ if ( errorNode == NULL ) {
+ mir_sntprintf( errorStr, 256, _T("%s -1: %s"), TranslateT( "Error" ), TranslateT( "Unknown error message" ));
+ return errorStr;
+ }
+
+ errorCode = -1;
+ if (( str=JabberXmlGetAttrValue( errorNode, "code" )) != NULL )
+ errorCode = _ttoi( str );
+ if (( str=errorNode->text ) != NULL )
+ mir_sntprintf( errorStr, 256, _T("%s %d: %s\r\n%s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )), str );
+ else
+ mir_sntprintf( errorStr, 256, _T("%s %d: %s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )) );
+ return errorStr;
+}
+
+void __stdcall JabberSendVisibleInvisiblePresence( BOOL invisible )
+{
+ if ( !jabberOnline ) return;
+
+ for ( int i = 0; ( i=JabberListFindNext( LIST_ROSTER, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item == NULL )
+ continue;
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact == NULL )
+ continue;
+
+ WORD apparentMode = JGetWord( hContact, "ApparentMode", 0 );
+ if ( invisible==TRUE && apparentMode==ID_STATUS_OFFLINE ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid ); p.addAttr( "type", "invisible" );
+ JabberSend( jabberThreadInfo->s, p );
+ }
+ else if ( invisible==FALSE && apparentMode==ID_STATUS_ONLINE )
+ JabberSendPresenceTo( jabberStatus, item->jid, NULL );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = JabberUrlEncode( str );
+ if ( s1 == NULL )
+ return NULL;
+
+ // Convert invalid control characters to space
+ if ( *s1 ) {
+ char* p, *q;
+
+ for ( p = s1; *p != '\0'; p++ )
+ if ( *p > 0 && *p < 0x20 && *p != 0x09 && *p != 0x0a && *p != 0x0d )
+ *p = ( char )0x20;
+
+ for ( p = q = s1; *p!='\0'; p++ ) {
+ if ( *p != '\r' ) {
+ *q = *p;
+ q++;
+ } }
+
+ *q = '\0';
+ }
+
+ char* s2 = JabberUtf8Encode( s1 );
+ mir_free( s1 );
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncodeW( const wchar_t* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ const wchar_t *s;
+ int resLen = 1;
+
+ for ( s = str; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': resLen += 5; break;
+ case '\'': resLen += 6; break;
+ case '>':
+ case '<': resLen += 6; break;
+ case '\"': resLen += 6; break;
+ default: resLen++; break;
+ } }
+
+ wchar_t* tmp = ( wchar_t* )alloca( resLen * sizeof( wchar_t )), *d;
+
+ for ( s = str, d = tmp; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': wcscpy( d, L"&" ); d += 5; break;
+ case '\'': wcscpy( d, L"'" ); d += 6; break;
+ case '>': wcscpy( d, L">" ); d += 4; break;
+ case '<': wcscpy( d, L"<" ); d += 4; break;
+ case '\"': wcscpy( d, L""" ); d += 6; break;
+ default:
+ if ( *s > 0 && *s < 0x20 && *s != 0x09 && *s != 0x0a && *s != 0x0d )
+ *d++ = ' ';
+ else
+ *d++ = *s;
+ } }
+
+ *d = 0;
+
+ return JabberUtf8EncodeW( tmp );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextDecode - retrieve a text from the encoded string
+
+char* __stdcall JabberTextDecode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = ( char* )alloca( strlen( str )+1 ), *s2;
+ strcpy( s1, str );
+
+ JabberUtf8Decode( s1, NULL );
+ JabberUrlDecode( s1 );
+ if (( s2 = JabberUnixToDos( s1 )) == NULL )
+ return NULL;
+
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberBase64Encode
+
+static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen )
+{
+ if ( buffer==NULL || bufferLen<=0 )
+ return NULL;
+
+ char* res = (char*)mir_alloc(((( bufferLen+2 )*4 )/3 ) + 1);
+ if ( res == NULL )
+ return NULL;
+
+ unsigned char igroup[3];
+ int nGroups = 0;
+ char *r = res;
+ const char* peob = buffer + bufferLen;
+ for ( const char* p = buffer; p < peob; ) {
+ igroup[ 0 ] = igroup[ 1 ] = igroup[ 2 ] = 0;
+ int n;
+ for ( n=0; n<3; n++ ) {
+ if ( p >= peob ) break;
+ igroup[n] = ( unsigned char ) *p;
+ p++;
+ }
+
+ if ( n > 0 ) {
+ r[0] = b64table[ igroup[0]>>2 ];
+ r[1] = b64table[ (( igroup[0]&3 )<<4 ) | ( igroup[1]>>4 ) ];
+ r[2] = b64table[ (( igroup[1]&0xf )<<2 ) | ( igroup[2]>>6 ) ];
+ r[3] = b64table[ igroup[2]&0x3f ];
+
+ if ( n < 3 ) {
+ r[3] = '=';
+ if ( n < 2 )
+ r[2] = '=';
+ }
+ r += 4;
+ } }
+
+ *r = '\0';
+
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberBase64Decode
+
+static unsigned char b64rtable[256];
+
+char* __stdcall JabberBase64Decode( const TCHAR* str, int *resultLen )
+{
+ char* res;
+ unsigned char* r, igroup[4], a[4];
+ int n, num, count;
+
+ if ( str==NULL || resultLen==NULL ) return NULL;
+ if (( res=( char* )mir_alloc(( ( _tcslen( str )+3 )/4 )*3 )) == NULL ) return NULL;
+
+ for ( n=0; n<256; n++ )
+ b64rtable[n] = ( unsigned char ) 0x80;
+ for ( n=0; n<26; n++ )
+ b64rtable['A'+n] = n;
+ for ( n=0; n<26; n++ )
+ b64rtable['a'+n] = n + 26;
+ for ( n=0; n<10; n++ )
+ b64rtable['0'+n] = n + 52;
+ b64rtable['+'] = 62;
+ b64rtable['/'] = 63;
+ b64rtable['='] = 0;
+ count = 0;
+ for ( r=( unsigned char* )res; *str != '\0'; ) {
+ for ( n=0; n<4; n++ ) {
+ if ( BYTE(*str) == '\r' || BYTE(*str) == '\n' ) {
+ n--; str++;
+ continue;
+ }
+
+ if ( BYTE(*str)=='\0' ) {
+ if ( n == 0 )
+ goto LBL_Exit;
+ mir_free( res );
+ return NULL;
+ }
+
+ if ( b64rtable[BYTE(*str)]==0x80 ) {
+ mir_free( res );
+ return NULL;
+ }
+
+ a[n] = BYTE(*str);
+ igroup[n] = b64rtable[BYTE(*str)];
+ str++;
+ }
+ r[0] = igroup[0]<<2 | igroup[1]>>4;
+ r[1] = igroup[1]<<4 | igroup[2]>>2;
+ r[2] = igroup[2]<<6 | igroup[3];
+ r += 3;
+ num = ( a[2]=='='?1:( a[3]=='='?2:3 ));
+ count += num;
+ if ( num < 3 ) break;
+ }
+LBL_Exit:
+ *resultLen = count;
+ return res;
+}
+
+char* __stdcall JabberGetVersionText()
+{
+ char filename[MAX_PATH], *fileVersion, *res;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA( hInst, filename, sizeof( filename ));
+ verInfoSize = GetFileVersionInfoSizeA( filename, &unused );
+ if (( pVerInfo=mir_alloc( verInfoSize )) != NULL ) {
+ GetFileVersionInfoA( filename, 0, verInfoSize, pVerInfo );
+ VerQueryValueA( pVerInfo, "\\StringFileInfo\\040904b0\\FileVersion", ( LPVOID* )&fileVersion, &blockSize );
+ if ( strstr( fileVersion, "cvs" )) {
+ res = ( char* )mir_alloc( strlen( fileVersion ) + strlen( __DATE__ ) + 2 );
+ sprintf( res, "%s %s", fileVersion, __DATE__ );
+ }
+ else {
+ res = mir_strdup( fileVersion );
+ }
+ mir_free( pVerInfo );
+ return res;
+ }
+ return NULL;
+}
+
+time_t __stdcall JabberIsoToUnixTime( TCHAR* stamp )
+{
+ struct tm timestamp;
+ TCHAR date[9];
+ TCHAR* p;
+ int i, y;
+ time_t t;
+
+ if ( stamp == NULL ) return ( time_t ) 0;
+
+ p = stamp;
+
+ // Get the date part
+ for ( i=0; *p!='\0' && i<8 && isdigit( *p ); p++,i++ )
+ date[i] = *p;
+
+ // Parse year
+ if ( i == 6 ) {
+ // 2-digit year ( 1970-2069 )
+ y = ( date[0]-'0' )*10 + ( date[1]-'0' );
+ if ( y < 70 ) y += 100;
+ }
+ else if ( i == 8 ) {
+ // 4-digit year
+ y = ( date[0]-'0' )*1000 + ( date[1]-'0' )*100 + ( date[2]-'0' )*10 + date[3]-'0';
+ y -= 1900;
+ }
+ else
+ return ( time_t ) 0;
+ timestamp.tm_year = y;
+ // Parse month
+ timestamp.tm_mon = ( date[i-4]-'0' )*10 + date[i-3]-'0' - 1;
+ // Parse date
+ timestamp.tm_mday = ( date[i-2]-'0' )*10 + date[i-1]-'0';
+
+ // Skip any date/time delimiter
+ for ( ; *p!='\0' && !isdigit( *p ); p++ );
+
+ // Parse time
+ if ( _stscanf( p, _T("%d:%d:%d"), ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec ) != 3 )
+ return ( time_t ) 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime( ×tamp );
+
+ _tzset();
+ t -= _timezone;
+
+ if ( t >= 0 )
+ return t;
+ else
+ return ( time_t ) 0;
+}
+
+struct MyCountryListEntry
+{
+ int id;
+ TCHAR* szName;
+}
+static extraCtry[] =
+{
+ { 1, _T("United States") },
+ { 1, _T("United States of America") },
+ { 1, _T("US") },
+ { 44, _T("England") }
+};
+
+int __stdcall JabberCountryNameToId( TCHAR* ctry )
+{
+ int ctryCount, i;
+ MyCountryListEntry *ctryList;
+
+ // Check for some common strings not present in the country list
+ ctryCount = sizeof( extraCtry )/sizeof( extraCtry[0] );
+ for ( i=0; i<ctryCount && _tcsicmp( extraCtry[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return extraCtry[i].id;
+
+ // Check Miranda country list
+ JCallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM ) &ctryCount, ( LPARAM )&ctryList );
+ for ( i=0; i<ctryCount && _tcsicmp( ctryList[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return ctryList[i].id;
+ else
+ return 0xffff; // Unknown
+}
+
+void __stdcall JabberSendPresenceTo( int status, TCHAR* to, XmlNode* extra )
+{
+ if ( !jabberOnline ) return;
+
+ // Send <presence/> update for status ( we won't handle ID_STATUS_OFFLINE here )
+ // Note: jabberModeMsg is already encoded using JabberTextEncode()
+ EnterCriticalSection( &modeMsgMutex );
+
+ char szPriority[40];
+ itoa( JGetWord( NULL, "Priority", 0 ), szPriority, 10 );
+
+ XmlNode p( "presence" ); p.addChild( "priority", szPriority );
+ if ( to != NULL )
+ p.addAttr( "to", to );
+
+ if ( extra )
+ p.addChild( extra );
+
+ if ( JGetByte( "EnableAvatars", TRUE )) {
+ char hashValue[ 50 ];
+ if ( !JGetStaticString( "AvatarHash", NULL, hashValue, sizeof hashValue )) {
+ XmlNode* x = p.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:avatar" );
+ x->addChild( "hash", hashValue );
+
+ x = p.addChild( "x" ); x->addAttr( "xmlns", "vcard-temp:x:update" );
+ x->addChild( "photo", hashValue );
+ } }
+
+ switch ( status ) {
+ case ID_STATUS_ONLINE:
+ if ( modeMsgs.szOnline )
+ p.addChild( "status", modeMsgs.szOnline );
+ break;
+ case ID_STATUS_INVISIBLE:
+ p.addAttr( "type", "invisible" );
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ p.addChild( "show", "away" );
+ if ( modeMsgs.szAway )
+ p.addChild( "status", modeMsgs.szAway );
+ break;
+ case ID_STATUS_NA:
+ p.addChild( "show", "xa" );
+ if ( modeMsgs.szNa )
+ p.addChild( "status", modeMsgs.szNa );
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ p.addChild( "show", "dnd" );
+ if ( modeMsgs.szDnd )
+ p.addChild( "status", modeMsgs.szDnd );
+ break;
+ case ID_STATUS_FREECHAT:
+ p.addChild( "show", "chat" );
+ if ( modeMsgs.szFreechat )
+ p.addChild( "status", modeMsgs.szFreechat );
+ break;
+ default:
+ // Should not reach here
+ break;
+ }
+ JabberSend( jabberThreadInfo->s, p );
+ LeaveCriticalSection( &modeMsgMutex );
+}
+
+void __stdcall JabberSendPresence( int status )
+{
+ JabberSendPresenceTo( status, NULL, NULL );
+ JabberSendVisibleInvisiblePresence( status == ID_STATUS_INVISIBLE );
+
+ // Also update status in all chatrooms
+ for ( int i = 0; ( i=JabberListFindNext( LIST_CHATROOM, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item != NULL )
+ JabberSendPresenceTo( status, item->jid, NULL );
+} }
+
+void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... )
+{
+ va_list vararg;
+ char* p;
+ int size, len;
+
+ if ( str == NULL ) return;
+
+ if ( *str==NULL || *sizeAlloced<=0 ) {
+ *sizeAlloced = size = 2048;
+ *str = ( char* )mir_alloc( size );
+ len = 0;
+ }
+ else {
+ len = strlen( *str );
+ size = *sizeAlloced - strlen( *str );
+ }
+
+ p = *str + len;
+ va_start( vararg, fmt );
+ while ( _vsnprintf( p, size, fmt, vararg ) == -1 ) {
+ size += 2048;
+ ( *sizeAlloced ) += 2048;
+ *str = ( char* )mir_realloc( *str, *sizeAlloced );
+ p = *str + len;
+ }
+ va_end( vararg );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberGetClientJID - adds a resource postfix to a JID
+
+TCHAR* __stdcall JabberGetClientJID( const TCHAR* jid, TCHAR* dest, size_t destLen )
+{
+ if ( jid == NULL )
+ return NULL;
+
+ size_t len = _tcslen( jid );
+ if ( len >= destLen )
+ len = destLen-1;
+
+ _tcsncpy( dest, jid, len );
+ dest[ len ] = '\0';
+
+ TCHAR* p = _tcschr( dest, '/' );
+ if ( p == NULL ) {
+ TCHAR* resource = JabberListGetBestResourceNamePtr( jid );
+ if ( resource != NULL )
+ mir_sntprintf( dest+len, destLen-len-1, _T("/%s"), resource );
+ }
+
+ return dest;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberStripJid - strips a resource postfix from a JID
+
+TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen )
+{
+ if ( jid == NULL )
+ *dest = 0;
+ else {
+ size_t len = _tcslen( jid );
+ if ( len >= destLen )
+ len = destLen-1;
+
+ memcpy( dest, jid, len * sizeof( TCHAR ));
+ dest[ len ] = 0;
+
+ TCHAR* p = _tcschr( dest, '/' );
+ if ( p != NULL )
+ *p = 0;
+ }
+
+ return dest;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetPictureType - tries to autodetect the picture type from the buffer
+
+int __stdcall JabberGetPictureType( const char* buf )
+{
+ if ( buf != NULL ) {
+ if ( memcmp( buf, "GIF89", 5 ) == 0 ) return PA_FORMAT_GIF;
+ if ( memcmp( buf, "\x89PNG", 4 ) == 0 ) return PA_FORMAT_PNG;
+ if ( memcmp( buf, "BM", 2 ) == 0 ) return PA_FORMAT_BMP;
+ if ( memcmp( buf+6, "JFIF", 4 ) == 0 ) return PA_FORMAT_JPEG;
+ }
+
+ return PA_FORMAT_UNKNOWN;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unicode functions
+
+char* t2a( const TCHAR* src )
+{
+ #if defined( _UNICODE )
+ return u2a( src );
+ #else
+ return mir_strdup( src );
+ #endif
+}
+
+char* u2a( const wchar_t* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+wchar_t* a2u( const char* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
|