/* Jabber Protocol Plugin for Miranda IM Tlen Protocol Plugin for Miranda NG Copyright (C) 2002-2004 Santithorn Bunchua Copyright (C) 2004-2007 Piotr Piastucki 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 "jabber.h" #include "jabber_list.h" #include #include HANDLE HookEventObj_Ex(const char *name, TlenProtocol *proto, MIRANDAHOOKOBJ hook) { proto->hookNum ++; proto->hHooks = (HANDLE *) mir_realloc(proto->hHooks, sizeof(HANDLE) * (proto->hookNum)); proto->hHooks[proto->hookNum - 1] = HookEventObj(name, hook, proto); return proto->hHooks[proto->hookNum - 1] ; } HANDLE CreateServiceFunction_Ex(const char *name, TlenProtocol *proto, MIRANDASERVICEOBJ service) { proto->serviceNum++; proto->hServices = (HANDLE *) mir_realloc(proto->hServices, sizeof(HANDLE) * (proto->serviceNum)); proto->hServices[proto->serviceNum - 1] = CreateServiceFunctionObj(name, service, proto); return proto->hServices[proto->serviceNum - 1] ; } void UnhookEvents_Ex(TlenProtocol *proto) { unsigned int i; for (i=0; ihookNum; ++i) { if (proto->hHooks[i] != NULL) { UnhookEvent(proto->hHooks[i]); } } mir_free(proto->hHooks); proto->hookNum = 0; proto->hHooks = NULL; } void DestroyServices_Ex(TlenProtocol *proto) { unsigned int i; for (i=0; iserviceNum; ++i) { if (proto->hServices[i] != NULL) { DestroyServiceFunction(proto->hServices[i]); } } mir_free(proto->hServices); proto->serviceNum = 0; proto->hServices = NULL; } void JabberSerialInit(TlenProtocol *proto) { InitializeCriticalSection(&proto->csSerial); proto->serial = 0; } void JabberSerialUninit(TlenProtocol *proto) { DeleteCriticalSection(&proto->csSerial); } unsigned int JabberSerialNext(TlenProtocol *proto) { unsigned int ret; EnterCriticalSection(&proto->csSerial); ret = proto->serial; proto->serial++; LeaveCriticalSection(&proto->csSerial); return ret; } void JabberLog(TlenProtocol *proto, const char *fmt, ...) { #ifdef ENABLE_LOGGING char *str; va_list vararg; int strsize; char *text; char *p, *q; int extra; va_start(vararg, fmt); str = (char *) mir_alloc(strsize=2048); while (_vsnprintf(str, strsize, fmt, vararg) == -1) str = (char *) mir_realloc(str, strsize+=2048); va_end(vararg); extra = 0; for (p=str; *p != '\0'; p++) if (*p == '\n' || *p == '\r') extra++; text = (char *) mir_alloc(strlen("TLEN")+2+strlen(str)+2+extra); sprintf(text, "[%s]", "TLEN"); for (p=str,q=text+strlen(text); *p != '\0'; p++,q++) { if (*p == '\r') { *q = '\\'; *(q+1) = 'r'; q++; } else if (*p == '\n') { *q = '\\'; *(q+1) = 'n'; q++; } else *q = *p; } *q = '\n'; *(q+1) = '\0'; if (proto->hNetlibUser != NULL) { CallService(MS_NETLIB_LOG, (WPARAM) proto->hNetlibUser, (LPARAM) text); } //OutputDebugString(text); mir_free(text); mir_free(str); #endif } // Caution: DO NOT use JabberSend() to send binary (non-string) data int JabberSend(TlenProtocol *proto, const char *fmt, ...) { char *str; int size; va_list vararg; int result = 0; EnterCriticalSection(&proto->csSend); va_start(vararg,fmt); size = 512; str = (char *) mir_alloc(size); while (_vsnprintf(str, size, fmt, vararg) == -1) { size += 512; str = (char *) mir_realloc(str, size); } va_end(vararg); JabberLog(proto, "SEND:%s", str); size = (int)strlen(str); if (proto->threadData != NULL) { if (proto->threadData->useAES) { result = JabberWsSendAES(proto, str, size, &proto->threadData->aes_out_context, proto->threadData->aes_out_iv); } else { result = JabberWsSend(proto, proto->threadData->s, str, size); } } LeaveCriticalSection(&proto->csSend); mir_free(str); return result; } char *JabberResourceFromJID(const char *jid2) { char *p; char *nick; char* jid = mir_strdup(jid2); p=strchr(jid, '/'); if (p != NULL && p[1] != '\0') { p++; if ((nick=(char *) mir_alloc(1+strlen(jid)-(p-jid))) != NULL) { strncpy(nick, p, strlen(jid)-(p-jid)); nick[strlen(jid)-(p-jid)] = '\0'; } } else { nick = mir_strdup(jid); } mir_free(jid); return nick; } char *JabberNickFromJID(const char *jid2) { char *p; char *nick; char* jid = mir_strdup(jid2); if ((p=strchr(jid, '@')) == NULL) p = strchr(jid, '/'); if (p != NULL) { if ((nick=(char *) mir_alloc((p-jid)+1)) != NULL) { strncpy(nick, jid, p-jid); nick[p-jid] = '\0'; } } else { nick = mir_strdup(jid); } mir_free(jid); return nick; } char *JabberLoginFromJID(const char *jid2) { char *p; char *nick; char* jid = mir_strdup(jid2); p = strchr(jid, '/'); if (p != NULL) { if ((nick=(char *) mir_alloc((p-jid)+1)) != NULL) { strncpy(nick, jid, p-jid); nick[p-jid] = '\0'; } } else { nick = mir_strdup(jid); } mir_free(jid); return nick; } char *JabberLocalNickFromJID(const char *jid) { char *p; char *localNick; p = JabberNickFromJID(jid); localNick = JabberTextDecode(p); mir_free(p); return localNick; } char *JabberSha1(char *str) { mir_sha1_ctx sha; DWORD digest[5]; char* result; if ( str == NULL ) return NULL; mir_sha1_init( &sha ); mir_sha1_append( &sha, (mir_sha1_byte_t* )str, (int)strlen( str )); mir_sha1_finish( &sha, (mir_sha1_byte_t* )digest ); if ((result=(char *)mir_alloc(41)) == NULL) return NULL; sprintf(result, "%08x%08x%08x%08x%08x", (int)htonl(digest[0]), (int)htonl(digest[1]), (int)htonl(digest[2]), (int)htonl(digest[3]), (int)htonl(digest[4])); return result; } char *TlenSha1(char *str, int len) { mir_sha1_ctx sha; mir_sha1_byte_t digest[20]; char* result; int i; if ( str == NULL ) return NULL; mir_sha1_init( &sha ); mir_sha1_append( &sha, (mir_sha1_byte_t* )str, len); mir_sha1_finish( &sha, digest ); if (( result=( char* )mir_alloc( 20 )) == NULL ) return NULL; for (i=0; i<20; i++) result[i]=digest[4*(i>>2)+(3-(i&0x3))]; return result; } char *TlenPasswordHash(const char *str) { int magic1 = 0x50305735, magic2 = 0x12345671, sum = 7; char *p, *res; if (str == NULL) return NULL; for (p=(char *)str; *p != '\0'; p++) { if (*p != ' ' && *p != '\t') { magic1 ^= (((magic1 & 0x3f) + sum) * ((char) *p)) + (magic1 << 8); magic2 += (magic2 << 8) ^ magic1; sum += ((char) *p); } } magic1 &= 0x7fffffff; magic2 &= 0x7fffffff; res = (char *) mir_alloc(17); sprintf(res, "%08x%08x", magic1, magic2); return res; } char *TlenUrlEncode(const char *str) { char *p, *q, *res; unsigned char c; if (str == NULL) return NULL; res = (char *) mir_alloc(3*strlen(str) + 1); for (p=(char *)str,q=res; *p != '\0'; p++,q++) { if (*p == ' ') { *q = '+'; } else if (*p < 0x20 || *p >= 0x7f || strchr("%&+:'<>\"", *p) != NULL) { // Convert first from CP1252 to ISO8859-2 switch ((unsigned char) *p) { case 0xa5: c = (unsigned char) 0xa1; break; case 0x8c: c = (unsigned char) 0xa6; break; case 0x8f: c = (unsigned char) 0xac; break; case 0xb9: c = (unsigned char) 0xb1; break; case 0x9c: c = (unsigned char) 0xb6; break; case 0x9f: c = (unsigned char) 0xbc; break; default: c = (unsigned char) *p; break; } sprintf(q, "%%%02X", c); q += 2; } else { *q = *p; } } *q = '\0'; return res; } void TlenUrlDecode(char *str) { char *p, *q; unsigned int code; if (str == NULL) return; for (p=q=str; *p != '\0'; p++,q++) { if (*p == '+') { *q = ' '; } else if (*p == '%' && *(p+1) != '\0' && isxdigit(*(p+1)) && *(p+2) != '\0' && isxdigit(*(p+2))) { sscanf(p+1, "%2x", &code); *q = (char) code; // Convert from ISO8859-2 to CP1252 switch ((unsigned char) *q) { case 0xa1: *q = (char) 0xa5; break; case 0xa6: *q = (char) 0x8c; break; case 0xac: *q = (char) 0x8f; break; case 0xb1: *q = (char) 0xb9; break; case 0xb6: *q = (char) 0x9c; break; case 0xbc: *q = (char) 0x9f; break; } p += 2; } else { *q = *p; } } *q = '\0'; } char * TlenGroupDecode(const char *str) { char *p, *q; if (str == NULL) return NULL; p = q = JabberTextDecode(str); for (; *p != '\0'; p++) { if (*p == '/') { *p = '\\'; } } return q; } char * TlenGroupEncode(const char *str) { char *p, *q; if (str == NULL) return NULL; p = q = mir_strdup(str); for (; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } p = JabberTextEncode(q); mir_free(q); return p; } char *JabberTextEncode(const char *str) { char *s1; if (str == NULL) return NULL; if ((s1=TlenUrlEncode(str)) == NULL) return NULL; return s1; } char *JabberTextDecode(const char *str) { char *s1; if (str == NULL) return NULL; s1 = mir_strdup(str); TlenUrlDecode(s1); return s1; } static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *JabberBase64Encode(const char *buffer, int bufferLen) { int n; unsigned char igroup[3]; char *p, *peob; char *res, *r; if (buffer == NULL || bufferLen <= 0) return NULL; if ((res=(char *) mir_alloc((((bufferLen+2)/3)*4) + 1)) == NULL) return NULL; for (p=(char*)buffer,peob=p+bufferLen,r=res; 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; } static unsigned char b64rtable[256]; char *JabberBase64Decode(const char *str, int *resultLen) { char *res; unsigned char *p, *r, igroup[4], a[4]; int n, num, count; if (str == NULL || resultLen == NULL) return NULL; if ((res=(char *) mir_alloc(((strlen(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 (p=(unsigned char *)str,r=(unsigned char *)res; *p != '\0';) { for (n=0; n<4; n++) { if ( *p == '\r' || *p == '\n' ) { n--; p++; continue; } if ( *p=='\0' ) { if ( n == 0 ) goto LBL_Exit; mir_free( res ); return NULL; } if ( b64rtable[*p] == 0x80 ) { mir_free( res ); return NULL; } a[n] = *p; igroup[n] = b64rtable[*p]; p++; } 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; } /* * Apply Polish Daylight Saving Time rules to get "DST-unbiased" timestamp */ time_t TlenTimeToUTC(time_t time) { struct tm *timestamp; timestamp = gmtime(&time); if ( (timestamp->tm_mon > 2 && timestamp->tm_mon < 9) || (timestamp->tm_mon == 2 && timestamp->tm_mday - timestamp->tm_wday >= 25) || (timestamp->tm_mon == 9 && timestamp->tm_mday - timestamp->tm_wday < 25)) { //time -= 3600; } else { //time += 3600; } return time; } time_t JabberIsoToUnixTime(char *stamp) { struct tm timestamp; char date[9]; char *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 (sscanf(p, "%d:%d:%d", &(timestamp.tm_hour), &(timestamp.tm_min), &(timestamp.tm_sec)) != 3) return (time_t) 0; timestamp.tm_isdst = 0; // DST is already present in _timezone below _tzset(); t = mktime(×tamp); t -= _timezone; t = TlenTimeToUTC(t); if (t >= 0) return t; else return (time_t) 0; } void 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 = (int)strlen(*str); size = *sizeAlloced - (int)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); } int 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, "\xFF\xD8", 2 ) == 0 ) return PA_FORMAT_JPEG; } return PA_FORMAT_UNKNOWN; } BOOL IsAuthorized(TlenProtocol *proto, const char *jid) { JABBER_LIST_ITEM *item = JabberListGetItemPtr(proto, LIST_ROSTER, jid); if (item != NULL) { return item->subscription == SUB_BOTH || item->subscription == SUB_FROM; } return FALSE; } void TlenLogMessage(TlenProtocol *proto, HANDLE hContact, DWORD flags, const char *message) { int size = (int)strlen(message) + 2; char *localMessage = (char *)mir_alloc(size); strcpy(localMessage, message); localMessage[size - 1] = '\0'; JabberDBAddEvent(proto, hContact, EVENTTYPE_MESSAGE, flags, (PBYTE)message, (DWORD)size); mir_free(localMessage); }