/* * $Id: avatar.cpp 14178 2012-03-11 15:02:54Z borkra $ * * myYahoo Miranda Plugin * * Authors: Gennady Feldman (aka Gena01) * Laurent Marechal (aka Peorth) * * This code is under GPL and is based on AIM, MSN and Miranda source code. * I want to thank Robert Rainwater and George Hazan for their code and support * and for answering some of my questions during development of this plugin. */ #include "stdafx.h" #include #include #include "m_folders.h" #include "avatar.h" #include "resource.h" // 31 bit hash function - this is based on g_string_hash function from glib int YAHOO_avt_hash(const char *key, DWORD len) { // Thank you Pidgin and Kopete devs. It seems that both clients are using this code now. const unsigned char *p = (const unsigned char *)key; int checksum = 0, g, i = len; while (i--) { checksum = (checksum << 4) + *p++; if ((g = (checksum & 0xf0000000)) != 0) checksum ^= g >> 23; checksum &= ~g; } return checksum; } /**************** Send Avatar ********************/ void upload_avt(int, INT_PTR fd, int error, void *data) { yahoo_file_info *sf = (yahoo_file_info*)data; unsigned long size = 0; char buf[1024]; int rw; /* */ if (fd < 1 || error) { LOG(("[get_fd] Connect Failed!")); return; } HANDLE myhFile = CreateFileA(sf->filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); if (myhFile == INVALID_HANDLE_VALUE) { LOG(("[get_fd] Can't open file for reading?!")); return; } LOG(("Sending file: %s size: %ld", sf->filename, sf->filesize)); do { DWORD dwRead; rw = ReadFile(myhFile, buf, sizeof(buf), &dwRead, NULL); if (rw != 0) { rw = Netlib_Send((HANDLE)fd, buf, dwRead, MSG_NODUMP); if (rw < 1) { LOG(("Upload Failed. Send error?")); break; } size += rw; } } while (rw >= 0 && size < sf->filesize); CloseHandle(myhFile); do { rw = Netlib_Recv((HANDLE)fd, buf, sizeof(buf), 0); LOG(("Got: %d bytes", rw)); } while (rw > 0); LOG(("File send complete!")); } void __cdecl CYahooProto::send_avt_thread(void *psf) { yahoo_file_info *sf = (yahoo_file_info*)psf; if (sf == NULL) { debugLogA("[yahoo_send_avt_thread] SF IS NULL!!!"); return; } setByte("AvatarUL", 1); yahoo_send_avatar(m_id, sf->filename, sf->filesize, &upload_avt, sf); free(sf->filename); free(sf); if (getByte("AvatarUL", 1) == 1) setByte("AvatarUL", 0); } void CYahooProto::SendAvatar(const wchar_t *szFile) { struct _stat statbuf; if (_wstat(szFile, &statbuf) != 0) { LOG(("[YAHOO_SendAvatar] Error reading File information?!")); return; } yahoo_file_info *sf = y_new(yahoo_file_info, 1); sf->filesize = statbuf.st_size; wchar_t tszFilename[MAX_PATH]; wcsncpy(tszFilename, szFile, _countof(tszFilename) - 1); GetShortPathNameW(szFile, tszFilename, _countof(tszFilename)); char szFilename[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, tszFilename, -1, szFilename, MAX_PATH, 0, 0); sf->filename = strdup(szFilename); debugLogA("[Uploading avatar] filename: %s size: %ld", sf->filename, sf->filesize); ForkThread(&CYahooProto::send_avt_thread, sf); } struct avatar_info { char *who; char *pic_url; int cksum; }; void __cdecl CYahooProto::recv_avatarthread(void *pavt) { avatar_info *avt = (avatar_info*)pavt; int error = 0; wchar_t buf[4096]; if (avt == NULL) { debugLogA("AVT IS NULL!!!"); return; } if (!m_bLoggedIn) { debugLogA("We are not logged in!!!"); return; } // ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); LOG(("yahoo_recv_avatarthread who:%s url:%s checksum: %d", avt->who, avt->pic_url, avt->cksum)); MCONTACT hContact = getbuddyH(avt->who); if (!hContact) { LOG(("ERROR: Can't find buddy: %s", avt->who)); error = 1; } else if (!error) { setDword(hContact, "PictCK", avt->cksum); setDword(hContact, "PictLoading", 1); } if (!error) { NETLIBHTTPREQUEST nlhr = { 0 }, *nlhrReply; nlhr.cbSize = sizeof(nlhr); nlhr.requestType = REQUEST_GET; nlhr.flags = NLHRF_NODUMP; nlhr.szUrl = avt->pic_url; nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&nlhr); if (nlhrReply) { if (nlhrReply->resultCode != 200) { LOG(("Update server returned '%d' instead of 200. It also sent the following: %s", nlhrReply->resultCode, nlhrReply->szResultDescr)); // make sure it's a real problem and not a problem w/ our connection yahoo_send_picture_info(m_id, avt->who, 3, avt->pic_url, avt->cksum); error = 1; } else if (nlhrReply->dataLength < 1 || nlhrReply->pData == NULL) { LOG(("No data??? Got %d bytes.", nlhrReply->dataLength)); error = 1; } else { GetAvatarFileName(hContact, buf, 1024, getByte(hContact, "AvatarType", 0)); DeleteFile(buf); LOG(("Saving file: %s size: %u", buf, nlhrReply->dataLength)); HANDLE myhFile = CreateFile(buf, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (myhFile != INVALID_HANDLE_VALUE) { DWORD c; WriteFile(myhFile, nlhrReply->pData, nlhrReply->dataLength, &c, NULL); CloseHandle(myhFile); setDword(hContact, "PictLastCheck", 0); } else { LOG(("Can not open file for writing: %s", buf)); error = 1; } } CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply); } } if (getDword(hContact, "PictCK", 0) != avt->cksum) { LOG(("WARNING: Checksum updated during download?!")); error = 1; /* don't use this one? */ } setDword(hContact, "PictLoading", 0); LOG(("File download complete!?")); if (error) buf[0] = '\0'; free(avt->who); free(avt->pic_url); free(avt); PROTO_AVATAR_INFORMATION ai; ai.format = PA_FORMAT_PNG; ai.hContact = hContact; wcsncpy_s(ai.filename, buf, _TRUNCATE); if (error) setDword(hContact, "PictCK", 0); ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, !error ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)&ai, 0); } void CYahooProto::ext_got_picture(const char*, const char *who, const char *pic_url, int cksum, int type) { MCONTACT hContact = 0; LOG(("[ext_yahoo_got_picture] for %s with url %s (checksum: %d) type: %d", who, pic_url, cksum, type)); /* Type: 1 - Send Avatar Info 2 - Got Avatar Info 3 - YIM6 didn't like my avatar? Expired? We need to invalidate and re-load */ switch (type) { case 1: { DBVARIANT dbv; /* need to send avatar info */ if (!getByte("ShowAvatars", 1)) { LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!")); yahoo_send_picture_update(m_id, who, 0); // no avatar (disabled) return; } LOG(("[ext_yahoo_got_picture] Getting ready to send info!")); /* need to read CheckSum */ int savedSum = getDword("AvatarHash", 0); if (savedSum) { if (!getString("AvatarURL", &dbv)) { LOG(("[ext_yahoo_got_picture] Sending url: %s checksum: %d to '%s'!", dbv.pszVal, savedSum, who)); //void yahoo_send_picture_info(int id, const char *me, const char *who, const char *pic_url, int savedSum) yahoo_send_picture_info(m_id, who, 2, dbv.pszVal, savedSum); db_free(&dbv); break; } else LOG(("No AvatarURL???")); /* * Try to re-upload the avatar */ if (getByte("AvatarUL", 0) != 1) { // NO avatar URL?? if (!getTString("AvatarFile", &dbv)) { struct _stat statbuf; if (_wstat(dbv.ptszVal, &statbuf) != 0) { LOG(("[ext_yahoo_got_picture] Avatar File Missing? Can't find file: %s", dbv.ptszVal)); } else { setString("AvatarInv", who); SendAvatar(dbv.ptszVal); } db_free(&dbv); } else LOG(("[ext_yahoo_got_picture] No Local Avatar File??? ")); } else LOG(("[ext_yahoo_got_picture] Another avatar upload in progress?")); } } break; case 2: // We got Avatar Info for our buddy. if (!getByte("ShowAvatars", 1)) { LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!")); return; } // got avatar info, so set miranda up hContact = getbuddyH(who); if (!hContact) { LOG(("[ext_yahoo_got_picture] Buddy not on my buddy list?.")); return; } if (!cksum && pic_url) { const char *chk = strstr(pic_url, "chksum="); if (chk) cksum = strtol(chk + 7, NULL, 10); } if (!cksum || cksum == -1) { LOG(("[ext_yahoo_got_picture] Resetting avatar.")); setDword(hContact, "PictCK", 0); reset_avatar(hContact); } else { if (pic_url == NULL) { LOG(("[ext_yahoo_got_picture] WARNING: Empty URL for avatar?")); return; } wchar_t z[1024]; GetAvatarFileName(hContact, z, 1024, getByte(hContact, "AvatarType", 0)); if (getDword(hContact, "PictCK", 0) != cksum || _waccess(z, 0) != 0) { debugLogA("[ext_yahoo_got_picture] Checksums don't match or avatar file is missing. Current: %d, New: %d", getDword(hContact, "PictCK", 0), cksum); avatar_info *avt = (avatar_info*)malloc(sizeof(avatar_info)); avt->who = strdup(who); avt->pic_url = strdup(pic_url); avt->cksum = cksum; ForkThread(&CYahooProto::recv_avatarthread, avt); } } break; case 3: // Our Avatar is not good anymore? Need to re-upload?? /* who, pic_url, cksum */ { int mcksum = 0; DBVARIANT dbv; /* need to send avatar info */ if (!getByte("ShowAvatars", 1)) { LOG(("[ext_yahoo_got_picture] We are not using/showing avatars!")); yahoo_send_picture_update(m_id, who, 0); // no avatar (disabled) return; } LOG(("[ext_yahoo_got_picture] Getting ready to send info!")); /* need to read CheckSum */ mcksum = getDword("AvatarHash", 0); if (mcksum == 0) { /* this should NEVER Happen??? */ LOG(("[ext_yahoo_got_picture] No personal checksum? and Invalidate?!")); yahoo_send_picture_update(m_id, who, 0); // no avatar (disabled) return; } LOG(("[ext_yahoo_got_picture] My Checksum: %d", mcksum)); if (!getString("AvatarURL", &dbv)) { if (mir_strcmpi(pic_url, dbv.pszVal) == 0) { DBVARIANT dbv2; /*time_t ts; DWORD ae;*/ if (mcksum != cksum) LOG(("[ext_yahoo_got_picture] WARNING: Checksums don't match!")); /*time(&ts); ae = getDword("AvatarExpires", 0); if (ae != 0 && ae > (ts - 300)) { LOG(("[ext_yahoo_got_picture] Current Time: %lu Expires: %lu ", ts, ae)); LOG(("[ext_yahoo_got_picture] We just reuploaded! Stop screwing with Yahoo FT. ")); // don't leak stuff db_free(&dbv); break; }*/ LOG(("[ext_yahoo_got_picture] Buddy: %s told us this is bad??Expired??. Re-uploading", who)); delSetting("AvatarURL"); if (!getTString("AvatarFile", &dbv2)) { setString("AvatarInv", who); SendAvatar(dbv2.ptszVal); db_free(&dbv2); } else { LOG(("[ext_yahoo_got_picture] No Local Avatar File??? ")); } } else { LOG(("[ext_yahoo_got_picture] URL doesn't match? Tell them the right thing!!!")); yahoo_send_picture_info(m_id, who, 2, dbv.pszVal, mcksum); } // don't leak stuff db_free(&dbv); } else { LOG(("[ext_yahoo_got_picture] no AvatarURL?")); } } break; default: LOG(("[ext_yahoo_got_picture] Unknown request/packet type exiting!")); } LOG(("ext_yahoo_got_picture exiting")); } void CYahooProto::ext_got_picture_checksum(const char*, const char *who, int cksum) { LOG(("ext_yahoo_got_picture_checksum for %s checksum: %d", who, cksum)); MCONTACT hContact = getbuddyH(who); if (hContact == NULL) { LOG(("Buddy Not Found. Skipping avatar update")); return; } /* Last thing check the checksum and request new one if we need to */ if (!cksum || cksum == -1) { setDword(hContact, "PictCK", 0); reset_avatar(hContact); } else { if (getDword(hContact, "PictCK", 0) != cksum) { // Now save the new checksum. No rush requesting new avatar yet. setDword(hContact, "PictCK", cksum); // Need to delete the Avatar File!! wchar_t szFile[MAX_PATH]; GetAvatarFileName(hContact, szFile, _countof(szFile) - 1, 0); DeleteFile(szFile); // Reset the avatar and cleanup. reset_avatar(hContact); // Request new avatar here... (might also want to check the sharing status?) if (getByte("ShareAvatar", 0) == 2) request_avatar(who); } } } void CYahooProto::ext_got_picture_update(const char*, const char *who, int buddy_icon) { LOG(("ext_got_picture_update for %s buddy_icon: %d", who, buddy_icon)); MCONTACT hContact = getbuddyH(who); if (hContact == NULL) { LOG(("Buddy Not Found. Skipping avatar update")); return; } setByte(hContact, "AvatarType", buddy_icon); /* Last thing check the checksum and request new one if we need to */ reset_avatar(hContact); } void CYahooProto::ext_got_picture_status(const char*, const char *who, int buddy_icon) { MCONTACT hContact = 0; LOG(("ext_yahoo_got_picture_status for %s buddy_icon: %d", who, buddy_icon)); hContact = getbuddyH(who); if (hContact == NULL) { LOG(("Buddy Not Found. Skipping avatar update")); return; } setByte(hContact, "AvatarType", buddy_icon); /* Last thing check the checksum and request new one if we need to */ reset_avatar(hContact); } void CYahooProto::ext_got_picture_upload(const char*, const char *url, unsigned int ts) { int cksum = 0; DBVARIANT dbv; LOG(("[ext_yahoo_got_picture_upload] url: %s timestamp: %d", url, ts)); if (!url) { LOG(("[ext_yahoo_got_picture_upload] Problem with upload?")); return; } cksum = getDword("TMPAvatarHash", 0); if (cksum != 0) { LOG(("[ext_yahoo_got_picture_upload] Updating Checksum to: %d", cksum)); setDword("AvatarHash", cksum); delSetting("TMPAvatarHash"); // This is only meant for message sessions, but we don't got those in miranda yet //YAHOO_bcast_picture_checksum(cksum); yahoo_send_picture_checksum(m_id, NULL, cksum); // need to tell the stupid Yahoo that our icon updated //YAHOO_bcast_picture_update(2); } else cksum = getDword("AvatarHash", 0); setString("AvatarURL", url); //YAHOO_SetDword("AvatarExpires", ts); if (!getString("AvatarInv", &dbv)) { LOG(("[ext_yahoo_got_picture_upload] Buddy: %s told us this is bad??", dbv.pszVal)); LOG(("[ext_yahoo_got_picture] Sending url: %s checksum: %d to '%s'!", url, cksum, dbv.pszVal)); //void yahoo_send_picture_info(int id, const char *me, const char *who, const char *pic_url, int cksum) yahoo_send_picture_info(m_id, dbv.pszVal, 2, url, cksum); delSetting("AvatarInv"); db_free(&dbv); } } void CYahooProto::ext_got_avatar_share(int buddy_icon) { LOG(("[ext_yahoo_got_avatar_share] buddy icon: %d", buddy_icon)); setByte("ShareAvatar", buddy_icon); } void CYahooProto::reset_avatar(MCONTACT hContact) { LOG(("[YAHOO_RESET_AVATAR]")); ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0); } void CYahooProto::request_avatar(const char* who) { if (!getByte("ShowAvatars", 1)) { LOG(("Avatars disabled, but available for: %s", who)); return; } MCONTACT hContact = getbuddyH(who); if (!hContact) return; time_t cur_time; time(&cur_time); time_t last_chk = getDword(hContact, "PictLastCheck", 0); /* * time() - in seconds ( 60*60 = 1 hour) */ if (getDword(hContact, "PictCK", 0) == 0 || last_chk == 0 || (cur_time - last_chk) > 60) { setDword(hContact, "PictLastCheck", (DWORD)cur_time); LOG(("Requesting Avatar for: %s", who)); yahoo_request_buddy_avatar(m_id, who); } else LOG(("Avatar Not Available for: %s Last Check: %ld Current: %ld (Flood Check in Effect)", who, last_chk, cur_time)); } void CYahooProto::GetAvatarFileName(MCONTACT hContact, wchar_t* pszDest, int cbLen, int type) { int tPathLen = mir_sntprintf(pszDest, cbLen, L"%s\\%S", VARST(L"%miranda_avatarcache%"), m_szModuleName); if (_waccess(pszDest, 0)) CreateDirectoryTreeT(pszDest); if (hContact != NULL) { int ck_sum = getDword(hContact, "PictCK", 0); tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, L"\\%lX", ck_sum); } else tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, L"\\%S avatar", m_szModuleName); wcsncpy_s((pszDest + tPathLen), (cbLen - tPathLen), (type == 1 ? L".swf" : L".png"), _TRUNCATE); } INT_PTR __cdecl CYahooProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) { PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam; DBVARIANT dbv; int avtType; if (!getString(pai->hContact, YAHOO_LOGINID, &dbv)) { debugLogA("[YAHOO_GETAVATARINFO] For: %s", dbv.pszVal); db_free(&dbv); } else { debugLogA("[YAHOO_GETAVATARINFO]"); } if (!getByte("ShowAvatars", 1) || !m_bLoggedIn) { debugLogA("[YAHOO_GETAVATARINFO] %s", m_bLoggedIn ? "We are not using/showing avatars!" : "We are not logged in. Can't load avatars now!"); return GAIR_NOAVATAR; } avtType = getByte(pai->hContact, "AvatarType", 0); debugLogA("[YAHOO_GETAVATARINFO] Avatar Type: %d", avtType); if (avtType != 2) { if (avtType != 0) debugLogA("[YAHOO_GETAVATARINFO] Not handling this type yet!"); return GAIR_NOAVATAR; } if (getDword(pai->hContact, "PictCK", 0) == 0) return GAIR_NOAVATAR; GetAvatarFileName(pai->hContact, pai->filename, _countof(pai->filename), getByte(pai->hContact, "AvatarType", 0)); pai->format = PA_FORMAT_PNG; debugLogA("[YAHOO_GETAVATARINFO] filename: %s", pai->filename); if (_waccess(pai->filename, 0) == 0) return GAIR_SUCCESS; if ((wParam & GAIF_FORCE) != 0 && pai->hContact != NULL) { /* need to request it again? */ if (getDword(pai->hContact, "PictLoading", 0) != 0 && (time(NULL) - getDword(pai->hContact, "PictLastCheck", 0) < 500)) { debugLogA("[YAHOO_GETAVATARINFO] Waiting for avatar to load!"); return GAIR_WAITFOR; } else if (m_bLoggedIn) { ptrA szId(getStringA(pai->hContact, YAHOO_LOGINID)); if (szId != NULL) { debugLogA("[YAHOO_GETAVATARINFO] Requesting avatar!"); request_avatar(szId); return GAIR_WAITFOR; } else debugLogA("[YAHOO_GETAVATARINFO] Can't retrieve user id?!"); } } debugLogA("[YAHOO_GETAVATARINFO] NO AVATAR???"); return GAIR_NOAVATAR; } /* * --=[ AVS / LoadAvatars API/Services ]=-- */ INT_PTR __cdecl CYahooProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam) { int res = 0; switch (wParam) { case AF_MAXSIZE: LOG(("[YahooGetAvatarCaps] AF_MAXSIZE")); ((POINT*)lParam)->x = 96; ((POINT*)lParam)->y = 96; break; case AF_PROPORTION: LOG(("[YahooGetAvatarCaps] AF_PROPORTION")); res = PIP_NONE; break; case AF_FORMATSUPPORTED: LOG(("[YahooGetAvatarCaps] AF_FORMATSUPPORTED")); res = lParam == PA_FORMAT_PNG; break; case AF_ENABLED: LOG(("[YahooGetAvatarCaps] AF_ENABLED")); res = (getByte("ShowAvatars", 1)) ? 1 : 0; break; case AF_DONTNEEDDELAYS: res = 1; /* don't need to delay avatar loading */ break; case AF_MAXFILESIZE: res = 0; /* no max filesize for now */ break; case AF_DELAYAFTERFAIL: res = 15 * 60 * 1000; /* 15 mins */ break; default: LOG(("[YahooGetAvatarCaps] Unknown: %d", wParam)); } return res; } /* Service: /GetMyAvatar wParam=(char *)Buffer to file name lParam=(int)Buffer size return=0 on success, else on error */ INT_PTR __cdecl CYahooProto::GetMyAvatar(WPARAM wParam, LPARAM lParam) { wchar_t *buffer = (wchar_t*)wParam; int size = (int)lParam; debugLogA("[YahooGetMyAvatar]"); if (buffer == NULL || size <= 0) return -1; if (!getByte("ShowAvatars", 1)) return -2; DBVARIANT dbv; int ret = -3; if (getDword("AvatarHash", 0)) { if (!getTString("AvatarFile", &dbv)) { if (_waccess(dbv.ptszVal, 0) == 0) { mir_tstrncpy(buffer, dbv.ptszVal, size - 1); buffer[size - 1] = '\0'; ret = 0; } db_free(&dbv); } } return ret; } /* #define PS_SETMYAVATAR "/SetMyAvatar" wParam=0 lParam=(const char *)Avatar file name return=0 for sucess */ INT_PTR __cdecl CYahooProto::SetMyAvatar(WPARAM, LPARAM lParam) { wchar_t* tszFile = (wchar_t*)lParam; wchar_t tszMyFile[MAX_PATH + 1]; GetAvatarFileName(NULL, tszMyFile, MAX_PATH, 2); if (tszFile == NULL) { debugLogA("[Deleting Avatar Info]"); /* remove ALL our Avatar Info Keys */ delSetting("AvatarFile"); delSetting("AvatarHash"); delSetting("AvatarURL"); delSetting("AvatarTS"); /* Send a Yahoo packet saying we don't got an avatar anymore */ yahoo_send_picture_status(m_id, 0); setByte("ShareAvatar", 0); DeleteFile(tszMyFile); } else { HANDLE hFile = CreateFile(tszFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); if (hFile == INVALID_HANDLE_VALUE) return 1; DWORD dwPngSize = GetFileSize(hFile, NULL); BYTE *pResult = (BYTE*)malloc(dwPngSize); if (pResult == NULL) { CloseHandle(hFile); return 2; } DWORD dw; ReadFile(hFile, pResult, dwPngSize, &dw, NULL); CloseHandle(hFile); hFile = CreateFile(tszMyFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) return 1; WriteFile(hFile, pResult, dwPngSize, &dw, NULL); SetEndOfFile(hFile); CloseHandle(hFile); unsigned int hash = YAHOO_avt_hash((const char*)pResult, dwPngSize); free(pResult); if (hash) { LOG(("[YAHOO_SetAvatar] File: '%s' CK: %d", tszMyFile, hash)); /* now check and make sure we don't reupload same thing over again */ if (hash != getDword("AvatarHash", 0)) { setTString("AvatarFile", tszMyFile); setDword("TMPAvatarHash", hash); /* Set Sharing to ON if it's OFF */ if (getByte("ShareAvatar", 0) != 2) { setByte("ShareAvatar", 2); yahoo_send_picture_status(m_id, 2); } SendAvatar(tszMyFile); } else LOG(("[YAHOO_SetAvatar] Same checksum and avatar on YahooFT. Not Reuploading.")); } } return 0; }