コード例 #1
0
void CIcqProto::icq_LogUsingErrorCode(int level, DWORD dwError, const char *szMsg)
{
	char szBuf[1024];
	char str[1024];
	char str2[64];
	char szErrorMsg[512];
	char *pszErrorMsg = NULL;
	int bNeedFree = FALSE;

	switch (dwError) {
	case ERROR_TIMEOUT:
	case WSAETIMEDOUT:
		pszErrorMsg = LPGEN("The server did not respond to the connection attempt within a reasonable time, it may be temporarily down. Try again later.");
		break;

	case ERROR_GEN_FAILURE:
		pszErrorMsg = LPGEN("The connection with the server was abortively closed during the connection attempt. You may have lost your local network connection.");
		break;

	case WSAEHOSTUNREACH:
	case WSAENETUNREACH:
		pszErrorMsg = LPGEN("Miranda was unable to resolve the name of a server to its numeric address. This is most likely caused by a catastrophic loss of your network connection (for example, your modem has disconnected), but if you are behind a proxy, you may need to use the 'Resolve hostnames through proxy' option in M->Options->Network.");
		break;

	case WSAEHOSTDOWN:
	case WSAENETDOWN:
	case WSAECONNREFUSED:
		pszErrorMsg = LPGEN("Miranda was unable to make a connection with a server. It is likely that the server is down, in which case you should wait for a while and try again later.");
		break;

	case ERROR_ACCESS_DENIED:
		pszErrorMsg = LPGEN("Your proxy rejected the user name and password that you provided. Please check them in M->Options->Network.");
		break;

	case WSAHOST_NOT_FOUND:
	case WSANO_DATA:
		pszErrorMsg = LPGEN("The server to which you are trying to connect does not exist. Check your spelling in M->Options->Network->ICQ.");
		break;

	default:
		TCHAR err[512];
		if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, err, _countof(err), NULL)) {
			pszErrorMsg = make_utf8_string(err);
			bNeedFree = TRUE;
		}
		break;
	}

	mir_snprintf(szBuf, _countof(szBuf), "%s%s%s (%s %d)",
					 szMsg ? ICQTranslateUtfStatic(szMsg, str, 1024) : "",
					 szMsg ? "\r\n\r\n" : "",
					 ICQTranslateUtfStatic(pszErrorMsg, szErrorMsg, 512),
					 ICQTranslateUtfStatic(LPGEN("error"), str2, 64),
					 dwError);

	if (bNeedFree)
		SAFE_FREE(&pszErrorMsg);

	icq_LogMessage(level, szBuf);
}
コード例 #2
0
void CIcqProto::icq_LogFatalParam(const char *szMsg, WORD wError)
{
	char str[MAX_PATH];
	char buf[MAX_PATH];

	mir_snprintf(buf, ICQTranslateUtfStatic(szMsg, str, _countof(str)), wError);
	icq_LogMessage(LOG_FATAL, buf);
}
コード例 #3
0
void CIcqProto::handleLoginReply(BYTE *buf, WORD datalen, serverthread_info *info)
{
    oscar_tlv_chain *chain = NULL;

    icq_sendCloseConnection(); // imitate icq5 behaviour

    if (!(chain = readIntoTLVChain(&buf, datalen, 0)))
    {
        NetLog_Server("Error: Missing chain on close channel");
        NetLib_CloseConnection(&hServerConn, TRUE);
        return; // Invalid data
    }

    // TLV 8 errors (signon errors?)
    WORD wError = chain->getWord(0x08, 1);
    if (wError)
    {
        handleSignonError(wError);

        // we return only if the server did not gave us cookie (possible to connect with soft error)
        if (!chain->getLength(0x06, 1))
        {
            disposeChain(&chain);
            SetCurrentStatus(ID_STATUS_OFFLINE);
            icq_serverDisconnect(FALSE);
            return; // Failure
        }
    }

    // We are in the login phase and no errors were reported.
    // Extract communication server info.
    info->newServer = chain->getString(0x05, 1);
    info->newServerSSL = chain->getNumber(0x8E, 1);
    info->cookieData = (BYTE*)chain->getString(0x06, 1);
    info->cookieDataLen = chain->getLength(0x06, 1);

    // We dont need this anymore
    disposeChain(&chain);

    if (!info->newServer || !info->cookieData)
    {
        icq_LogMessage(LOG_FATAL, LPGEN("You could not sign on because the server returned invalid data. Try again."));

        SAFE_FREE(&info->newServer);
        SAFE_FREE((void**)&info->cookieData);
        info->cookieDataLen = 0;

        SetCurrentStatus(ID_STATUS_OFFLINE);
        NetLib_CloseConnection(&hServerConn, TRUE);
        return; // Failure
    }

    NetLog_Server("Authenticated.");
    info->newServerReady = 1;

    return;
}
コード例 #4
0
ファイル: icq_avatar.cpp プロジェクト: ybznek/miranda-ng
void CIcqProto::StartAvatarThread(HANDLE hConn, char *cookie, size_t cookieLen) // called from event
{
	if (!hConn) {
		mir_cslock l(m_avatarsMutex); // place avatars lock

		if (m_avatarsConnection && m_avatarsConnection->isPending()) {
			debugLogA("Avatar, Multiple start thread attempt, ignored.");
			SAFE_FREE((void**)&cookie);
			return;
		}
		debugLogA("Avatars: Connection failed");

		m_avatarsConnectionPending = FALSE;

		// check if any upload request are waiting in the queue
		int bYet = 0;

		for (int i = 0; i < m_arAvatars.getCount();) {
			avatars_request *ar = m_arAvatars[i];
			if (ar->type == ART_UPLOAD) { // we found it, return error
				if (!bYet) {
					icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server temporarily unavailable."));
					bYet = 1;
				}

				// remove upload request from queue
				m_arAvatars.remove(i);
				delete ar;
			}
			else i++;
		}

		SAFE_FREE((void**)&cookie);
		return;
	}

	mir_cslock l(m_avatarsMutex);

	if (m_avatarsConnection && m_avatarsConnection->isPending()) {
		debugLogA("Avatar, Multiple start thread attempt, ignored.");

		NetLib_CloseConnection(&hConn, false);

		SAFE_FREE((void**)&cookie);
		return;
	}
	
	if (m_avatarsConnection)
		m_avatarsConnection->closeConnection();
	m_avatarsConnection = new avatars_server_connection(this, hConn, cookie, cookieLen); // the old connection should not be used anymore

	// connection object created, remove the connection request pending flag
	m_avatarsConnectionPending = false;
}
コード例 #5
0
ファイル: fam_17signon.cpp プロジェクト: Seldom/miranda-ng
void CIcqProto::handleAuthKeyResponse(BYTE *buf, size_t wPacketLen, serverthread_info *info)
{
	char szKey[64] = {0};
	mir_md5_state_t state;
	BYTE digest[16];

	debugLogA("Received %s", "ICQ_SIGNON_AUTH_KEY");

	if (wPacketLen < 2) {
		debugLogA("Malformed %s", "ICQ_SIGNON_AUTH_KEY");
		icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid server response."));
		SetCurrentStatus(ID_STATUS_OFFLINE);
		return;
	}

	size_t wKeyLen;
	unpackWord(&buf, &wKeyLen);
	wPacketLen -= 2;

	if (!wKeyLen || wKeyLen > wPacketLen || wKeyLen > sizeof(szKey)) {
		debugLogA("Invalid length in %s: %u", "ICQ_SIGNON_AUTH_KEY", wKeyLen);
		icq_LogMessage(LOG_FATAL, LPGEN("Secure login failed.\nInvalid key length."));
		SetCurrentStatus(ID_STATUS_OFFLINE);
		return;
	}

	unpackString(&buf, szKey, wKeyLen);

	mir_md5_init(&state);
	mir_md5_append(&state, info->szAuthKey, (int)info->wAuthKeyLen);
	mir_md5_finish(&state, digest);

	mir_md5_init(&state);
	mir_md5_append(&state, (LPBYTE)szKey, (int)wKeyLen);
	mir_md5_append(&state, digest, 16);
	mir_md5_append(&state, (LPBYTE)CLIENT_MD5_STRING, sizeof(CLIENT_MD5_STRING)-1);
	mir_md5_finish(&state, digest);

	debugLogA("Sending ICQ_SIGNON_LOGIN_REQUEST to login server");
	sendClientAuth((char*)digest, 0x10, TRUE);
}
コード例 #6
0
ファイル: chan_04close.cpp プロジェクト: 0xmono/miranda-ng
void CIcqProto::handleMigration(serverthread_info *info)
{
	// Check the data that was saved when the migration was announced
	debugLogA("Migrating to %s", info->newServer);
	if (!info->newServer || !info->cookieData) {
		icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because the current server shut down."));

		SAFE_FREE(&info->newServer);
		SAFE_FREE((void**)&info->cookieData);
		info->isNewServerReady = info->isMigrating = false;
	}
}
コード例 #7
0
void CIcqProto::icq_sendFileResume(filetransfer *ft, int action, const char *szFilename)
{
	if (ft->hConnection == NULL)
		return;

	directconnect *dc = FindFileTransferDC(ft);
	if (!dc) return; // something is broken...

	int openFlags;

	switch (action)
	{
	case FILERESUME_RESUME:
		openFlags = _O_BINARY | _O_WRONLY;
		break;

	case FILERESUME_OVERWRITE:
		openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY;
		ft->dwFileBytesDone = 0;
		break;

	case FILERESUME_SKIP:
		openFlags = _O_BINARY | _O_WRONLY;
		ft->dwFileBytesDone = ft->dwThisFileSize;
		break;

	case FILERESUME_RENAME:
		openFlags = _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY;
		SAFE_FREE(&ft->szThisFile);
		ft->szThisFile = null_strdup(szFilename);
		ft->dwFileBytesDone = 0;
		break;
	}

	ft->fileId = OpenFileUtf(ft->szThisFile, openFlags, _S_IREAD | _S_IWRITE);
	if (ft->fileId == -1)
	{
		icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder."));
		NetLib_CloseConnection(&ft->hConnection, FALSE);
		return;
	}

	if (action == FILERESUME_RESUME)
		ft->dwFileBytesDone = _lseek(ft->fileId, 0, SEEK_END);
	else
		_lseek(ft->fileId, ft->dwFileBytesDone, SEEK_SET);

	ft->dwBytesDone += ft->dwFileBytesDone;

	file_sendResume(this, dc);

	BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
}
コード例 #8
0
ファイル: chan_04close.cpp プロジェクト: Ganster41/miranda-ng
void CIcqProto::handleRuntimeError(WORD wError)
{
	switch (wError) {
	case 0x01:
		ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
		icq_LogMessage(LOG_FATAL, LPGEN("You have been disconnected from the ICQ network because you logged on from another location using the same ICQ number."));
		break;

	default:
		icq_LogFatalParam(LPGEN("Unknown runtime error: 0x%02x"), wError);
		break;
	}
}
コード例 #9
0
void CIcqProto::handleSignonError(WORD wError)
{
    switch (wError) {

    case 0x01: // Unregistered uin
    case 0x04: // Incorrect uin or password
    case 0x05: // Mismatch uin or password
    case 0x06: // Internal Client error (bad input to authorizer)
    case 0x07: // Invalid account
        BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
        ZeroMemory(m_szPassword, sizeof(m_szPassword));
        icq_LogFatalParam(LPGEN("Connection failed.\nYour ICQ number or password was rejected (%d)."), wError);
        break;

    case 0x02: // Service temporarily unavailable
    case 0x0D: // Bad database status
    case 0x10: // Service temporarily offline
    case 0x12: // Database send error
    case 0x14: // Reservation map error
    case 0x15: // Reservation link error
    case 0x1A: // Reservation timeout
        BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
        icq_LogFatalParam(LPGEN("Connection failed.\nThe server is temporarily unavailable (%d)."), wError);
        break;

    case 0x16: // The users num connected from this IP has reached the maximum
    case 0x17: // The users num connected from this IP has reached the maximum (reserved)
        icq_LogFatalParam(LPGEN("Connection failed.\nServer has too many connections from your IP (%d)."), wError);
        break;

    case 0x18: // Reservation rate limit exceeded
    case 0x1D: // Rate limit exceeded
        BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
        icq_LogFatalParam(LPGEN("Connection failed.\nYou have connected too quickly,\nplease wait and retry 10 to 20 minutes later (%d)."), wError);
        break;

    case 0x1B: // You are using an older version of ICQ. Upgrade required
        BroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL);
        icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nThe server did not accept this client version."));
        break;

    case 0x1C: // You are using an older version of ICQ. Upgrade recommended
        icq_LogMessage(LOG_WARNING, LPGEN("The server sent warning, this version is getting old.\nTry to look for a new one."));
        break;

    case 0x1E: // Can't register on the ICQ network
        icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nYou were rejected by the server for an unknown reason.\nThis can happen if the UIN is already connected."));
        break;

    case 0x0C: // Invalid database fields, MD5 login not supported
        icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nSecure (MD5) login is not supported on this account."));
        break;

    case 0:    // No error
        break;

    case 0x08: // Deleted account
    case 0x09: // Expired account
    case 0x0A: // No access to database
    case 0x0B: // No access to resolver
    case 0x0E: // Bad resolver status
    case 0x0F: // Internal error
    case 0x11: // Suspended account
    case 0x13: // Database link error
    case 0x19: // User too heavily warned
    case 0x1F: // Token server timeout
    case 0x20: // Invalid SecureID number
    case 0x21: // MC error
    case 0x22: // Age restriction
    case 0x23: // RequireRevalidation
    case 0x24: // Link rule rejected
    case 0x25: // Missing information or bad SNAC format
    case 0x26: // Link broken
    case 0x27: // Invalid client IP
    case 0x28: // Partner rejected
    case 0x29: // SecureID missing
    case 0x2A: // Blocked account | Bump user

    default:
        icq_LogFatalParam(LPGEN("Connection failed.\nUnknown error during sign on: 0x%02x"), wError);
        break;
    }
}
コード例 #10
0
void CIcqProto::StartAvatarThread(HANDLE hConn, char *cookie, WORD cookieLen) // called from event
{
	if (!hConn)
	{
		icq_lock l(m_avatarsMutex); // place avatars lock

		if (m_avatarsConnection && m_avatarsConnection->isPending())
		{
			debugLogA("Avatar, Multiple start thread attempt, ignored.");
			SAFE_FREE((void**)&cookie);
			return;
		}
		debugLogA("Avatars: Connection failed");

		m_avatarsConnectionPending = FALSE;

		{ // check if any upload request are waiting in the queue
			avatars_request *ar = m_avatarsQueue;
			int bYet = 0;

			while (ar)
			{
				if (ar->type == ART_UPLOAD)
				{ // we found it, return error
					if (!bYet)
					{
						icq_LogMessage(LOG_WARNING, LPGEN("Error uploading avatar to server, server temporarily unavailable."));
						bYet = 1;
					}
					// remove upload request from queue
					ar = ReleaseAvatarRequestInQueue(ar);
					continue;
				}
				ar = ar->pNext;
			}
		}
		SAFE_FREE((void**)&cookie);

		return;
	}

	icq_lock l(m_avatarsMutex);

	if (m_avatarsConnection && m_avatarsConnection->isPending())
	{
		debugLogA("Avatar, Multiple start thread attempt, ignored.");

		NetLib_CloseConnection(&hConn, FALSE);

		SAFE_FREE((void**)&cookie);

		return;
	}
	else if (m_avatarsConnection)
		m_avatarsConnection->closeConnection();

	m_avatarsConnection = new avatars_server_connection(this, hConn, cookie, cookieLen); // the old connection should not be used anymore

	// connection object created, remove the connection request pending flag
	m_avatarsConnectionPending = FALSE;
}
コード例 #11
0
ファイル: fam_01service.cpp プロジェクト: Seldom/miranda-ng
void CIcqProto::handleServUINSettings(int nPort, serverthread_info *info)
{
	setUserInfo();

	/* SNAC 3,4: Tell server who's on our list (deprecated) */
	/* SNAC 3,15: Try to add unauthorised contacts to temporary list */
	sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST, BUL_ALLCONTACTS);

	if (m_iDesiredStatus == ID_STATUS_INVISIBLE) {
		/* Tell server who's on our visible list (deprecated) */
		if (!m_bSsiEnabled)
			sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE);
		else
			updateServVisibilityCode(3);
	}

	if (m_iDesiredStatus != ID_STATUS_INVISIBLE) {
		/* Tell server who's on our invisible list (deprecated) */
		if (!m_bSsiEnabled)
			sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE);
		else
			updateServVisibilityCode(4);
	}

	// SNAC 1,1E: Set status
	icq_packet packet;
	{
		DWORD dwDirectCookie = rand() ^ (rand() << 16);

		// Get status
		WORD wStatus = MirandaStatusToIcq(m_iDesiredStatus);

		// Get status note & mood
		char *szStatusNote = PrepareStatusNote(m_iDesiredStatus);
		BYTE bXStatus = getContactXStatus(NULL);
		char szMoodData[32];

		// prepare mood id
		if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus - 1] != -1)
			mir_snprintf(szMoodData, "icqmood%d", moodXStatus[bXStatus - 1]);
		else
			szMoodData[0] = '\0';

		//! Tricky code, this ensures that the status note will be saved to the directory
		SetStatusNote(szStatusNote, m_bGatewayMode ? 5000 : 2500, TRUE);

		size_t wStatusNoteLen = mir_strlen(szStatusNote);
		size_t wStatusMoodLen = mir_strlen(szMoodData);
		size_t wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4;

		serverPacketInit(&packet, 71 + (wSessionDataLen ? wSessionDataLen + 4 : 0));
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS);
		packDWord(&packet, 0x00060004);             // TLV 6: Status mode and security flags
		packWord(&packet, GetMyStatusFlags());      // Status flags
		packWord(&packet, wStatus);                 // Status
		packTLVWord(&packet, 0x0008, 0x0A06);       // TLV 8: Independent Status Messages
		packDWord(&packet, 0x000c0025);             // TLV C: Direct connection info
		packDWord(&packet, getDword("RealIP", 0));
		packDWord(&packet, nPort);
		packByte(&packet, DC_TYPE);                 // TCP/FLAG firewall settings
		packWord(&packet, ICQ_VERSION);
		packDWord(&packet, dwDirectCookie);         // DC Cookie
		packDWord(&packet, WEBFRONTPORT);           // Web front port
		packDWord(&packet, CLIENTFEATURES);         // Client features
		packDWord(&packet, 0x7fffffff);             // Abused timestamp
		packDWord(&packet, ICQ_PLUG_VERSION);       // Abused timestamp
		if (ServiceExists("SecureIM/IsContactSecured"))
			packDWord(&packet, 0x5AFEC0DE);           // SecureIM Abuse
		else
			packDWord(&packet, 0x00000000);           // Timestamp
		packWord(&packet, 0x0000);                  // Unknown
		packTLVWord(&packet, 0x001F, 0x0000);

		if (wSessionDataLen) { // Pack session data
			packWord(&packet, 0x1D);                  // TLV 1D
			packWord(&packet, WORD(wSessionDataLen));       // TLV length
			packWord(&packet, 0x02);                  // Item Type
			if (wStatusNoteLen) {
				packWord(&packet, 0x400 | WORD(wStatusNoteLen + 4)); // Flags + Item Length
				packWord(&packet, WORD(wStatusNoteLen));      // Text Length
				packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen);
				packWord(&packet, 0);                   // Encoding not specified (utf-8 is default)
			}
			else
				packWord(&packet, 0);                   // Flags + Item Length
			packWord(&packet, 0x0E);                  // Item Type
			packWord(&packet, WORD(wStatusMoodLen));        // Flags + Item Length
			if (wStatusMoodLen)
				packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood

			// Save current status note & mood
			db_set_utf(NULL, m_szModuleName, DBSETTING_STATUS_NOTE, szStatusNote);
			setString(DBSETTING_STATUS_MOOD, szMoodData);
		}
		// Release memory
		SAFE_FREE(&szStatusNote);

		sendServPacket(&packet);
	}

	/* SNAC 1,11 */
	serverPacketInit(&packet, 14);
	packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE);
	packDWord(&packet, 0x00000000);

	sendServPacket(&packet);
	m_bIdleAllow = 0;

	// Change status
	SetCurrentStatus(m_iDesiredStatus);

	// Finish Login sequence
	serverPacketInit(&packet, 98);
	packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY);
	packDWord(&packet, 0x00220001); // imitate ICQ 6 behaviour
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00010004);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00130004);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00020001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00030001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00150001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00040001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00060001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00090001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x000A0001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x000B0001);
	packDWord(&packet, 0x0110164f);

	sendServPacket(&packet);

	debugLogA(" *** Yeehah, login sequence complete");

	// login sequence is complete enter logged-in mode
	info->bLoggedIn = true;
	m_bConnectionLost = false;

	// enable auto info-update routine
	icq_EnableUserLookup(true);

	if (!info->isMigrating) {
		// Get Offline Messages Reqeust
		cookie_offline_messages *ack = (cookie_offline_messages*)SAFE_MALLOC(sizeof(cookie_offline_messages));
		if (ack) {
			DWORD dwCookie = AllocateCookie(CKT_OFFLINEMESSAGE, ICQ_MSG_CLI_REQ_OFFLINE, 0, ack);

			serverPacketInit(&packet, 10);
			packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQ_OFFLINE, 0, dwCookie);

			sendServPacket(&packet);
		}
		else icq_LogMessage(LOG_WARNING, LPGEN("Failed to request offline messages. They may be received next time you log in."));

		// Update our information from the server
		sendOwnerInfoRequest();

		// Request info updates on all contacts
		icq_RescanInfoUpdate();

		// Start sending Keep-Alive packets
		StartKeepAlive(info);

		if (m_bAvatarsEnabled) { // Send SNAC 1,4 - request avatar family 0x10 connection
			icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread);

			m_avatarsConnectionPending = TRUE;
			debugLogA("Requesting Avatar family entry point.");
		}

		// Set last xstatus
		updateServerCustomStatus(TRUE);
	}
	info->isMigrating = false;

	if (m_bAimEnabled) {
		char **szAwayMsg = NULL;
		mir_cslock l(m_modeMsgsMutex);

		szAwayMsg = MirandaStatusToAwayMsg(m_iStatus);
		if (szAwayMsg)
			icq_sendSetAimAwayMsgServ(*szAwayMsg);
	}
}
コード例 #12
0
ファイル: fam_01service.cpp プロジェクト: Seldom/miranda-ng
void CIcqProto::handleServiceFam(BYTE *pBuffer, size_t wBufferLength, snac_header *pSnacHeader, serverthread_info *info)
{
	icq_packet packet;

	switch (pSnacHeader->wSubtype) {

	case ICQ_SERVER_READY:
		debugLogA("Server is ready and is requesting my Family versions");
		debugLogA("Sending my Families");

		// This packet is a response to SRV_FAMILIES SNAC(1,3).
		// This tells the server which SNAC families and their corresponding
		// versions which the client understands. This also seems to identify
		// the client as an ICQ vice AIM client to the server.
		// Miranda mimics the behaviour of ICQ 6
		serverPacketInit(&packet, 54);
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES);
		packDWord(&packet, 0x00220001);
		packDWord(&packet, 0x00010004);
		packDWord(&packet, 0x00130004);
		packDWord(&packet, 0x00020001);
		packDWord(&packet, 0x00030001);
		packDWord(&packet, 0x00150001);
		packDWord(&packet, 0x00040001);
		packDWord(&packet, 0x00060001);
		packDWord(&packet, 0x00090001);
		packDWord(&packet, 0x000a0001);
		packDWord(&packet, 0x000b0001);
		sendServPacket(&packet);
		break;

	case ICQ_SERVER_FAMILIES2:
		/* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands.
		* We send a rate request packet */
		debugLogA("Server told me his Family versions");
		debugLogA("Requesting Rate Information");

		serverPacketInit(&packet, 10);
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO);
		sendServPacket(&packet);
		break;

	case ICQ_SERVER_RATE_INFO:
		debugLogA("Server sent Rate Info");

		/* init rates management */
		m_rates = new rates(this, pBuffer, wBufferLength);

		/* ack rate levels */
		debugLogA("Sending Rate Info Ack");

		m_rates->initAckPacket(&packet);
		sendServPacket(&packet);

		/* CLI_REQINFO - This command requests from the server certain information about the client that is stored on the server. */
		debugLogA("Sending CLI_REQINFO");

		serverPacketInit(&packet, 10);
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQINFO);
		sendServPacket(&packet);

		if (m_bSsiEnabled) {
			cookie_servlist_action* ack;
			DWORD dwCookie;

			DWORD dwLastUpdate = getDword("SrvLastUpdate", 0);
			WORD wRecordCount = getWord("SrvRecordCount", 0);

			// CLI_REQLISTS - we want to use SSI
			debugLogA("Requesting roster rights");

			serverPacketInit(&packet, 16);
			packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQLISTS);
			packTLVWord(&packet, 0x0B, 0x000F); // mimic ICQ 6
			sendServPacket(&packet);

			if (!wRecordCount) { // CLI_REQROSTER
				// we do not have any data - request full list
				debugLogA("Requesting full roster");

				serverPacketInit(&packet, 10);
				ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action));
				if (ack) { // we try to use standalone cookie if available
					ack->dwAction = SSA_CHECK_ROSTER; // loading list
					dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_REQUEST, 0, ack);
				}
				else // if not use that old fake
					dwCookie = ICQ_LISTS_CLI_REQUEST << 0x10;

				packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQUEST, 0, dwCookie);
				sendServPacket(&packet);
			}
			else { // CLI_CHECKROSTER
				debugLogA("Requesting roster check");

				serverPacketInit(&packet, 16);
				ack = (cookie_servlist_action*)SAFE_MALLOC(sizeof(cookie_servlist_action));
				if (ack)  { // TODO: rewrite - use get list service for empty list
					// we try to use standalone cookie if available
					ack->dwAction = SSA_CHECK_ROSTER; // loading list
					dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_CHECK, 0, ack);
				}
				else // if not use that old fake
					dwCookie = ICQ_LISTS_CLI_CHECK << 0x10;

				packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_CHECK, 0, dwCookie);
				// check if it was not changed elsewhere (force reload, set that setting to zero)
				if (IsServerGroupsDefined()) {
					packDWord(&packet, dwLastUpdate);  // last saved time
					packWord(&packet, wRecordCount);   // number of records saved
				}
				else { // we need to get groups info into DB, force receive list
					packDWord(&packet, 0);  // last saved time
					packWord(&packet, 0);   // number of records saved
				}
				sendServPacket(&packet);
			}
		}

		// CLI_REQLOCATION
		debugLogA("Requesting Location rights");

		serverPacketInit(&packet, 10);
		packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_CLI_REQ_RIGHTS);
		sendServPacket(&packet);

		// CLI_REQBUDDY
		debugLogA("Requesting Client-side contactlist rights");

		serverPacketInit(&packet, 16);
		packFNACHeader(&packet, ICQ_BUDDY_FAMILY, ICQ_USER_CLI_REQBUDDY);
		// Query flags: 1 = Enable Avatars
		//              2 = Enable offline status message notification
		//              4 = Enable Avatars for offline contacts
		//              8 = Use reject for not authorized contacts
		packTLVWord(&packet, 0x05, 0x0007);
		sendServPacket(&packet);

		// CLI_REQICBM
		debugLogA("Sending CLI_REQICBM");

		serverPacketInit(&packet, 10);
		packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQICBM);
		sendServPacket(&packet);

		// CLI_REQBOS
		debugLogA("Sending CLI_REQBOS");

		serverPacketInit(&packet, 10);
		packFNACHeader(&packet, ICQ_BOS_FAMILY, ICQ_PRIVACY_REQ_RIGHTS);
		sendServPacket(&packet);
		break;

	case ICQ_SERVER_PAUSE:
		debugLogA("Server is going down in a few seconds... (Flags: %u)", pSnacHeader->wFlags);
		// This is the list of groups that we want to have on the next server
		serverPacketInit(&packet, 30);
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_PAUSE_ACK);
		packWord(&packet, ICQ_SERVICE_FAMILY);
		packWord(&packet, ICQ_LISTS_FAMILY);
		packWord(&packet, ICQ_LOCATION_FAMILY);
		packWord(&packet, ICQ_BUDDY_FAMILY);
		packWord(&packet, ICQ_EXTENSIONS_FAMILY);
		packWord(&packet, ICQ_MSG_FAMILY);
		packWord(&packet, 0x06);
		packWord(&packet, ICQ_BOS_FAMILY);
		packWord(&packet, ICQ_LOOKUP_FAMILY);
		packWord(&packet, ICQ_STATS_FAMILY);
		sendServPacket(&packet);

		debugLogA("Sent server pause ack");
		break;

	case ICQ_SERVER_MIGRATIONREQ:
		debugLogA("Server migration requested (Flags: %u)", pSnacHeader->wFlags);

		pBuffer += 2; // Unknown, seen: 0
		wBufferLength -= 2;
		{
			oscar_tlv_chain *chain = readIntoTLVChain(&pBuffer, wBufferLength, 0);

			if (info->cookieDataLen > 0)
				SAFE_FREE((void**)&info->cookieData);

			info->newServer = chain->getString(0x05, 1);
			info->newServerSSL = chain->getNumber(0x8E, 1);
			info->cookieData = (BYTE*)chain->getString(0x06, 1);
			info->cookieDataLen = chain->getLength(0x06, 1);

			disposeChain(&chain);

			if (!info->newServer || !info->cookieData) {
				icq_LogMessage(LOG_FATAL, LPGEN("A server migration has failed because the server returned invalid data. You must reconnect manually."));
				SAFE_FREE(&info->newServer);
				SAFE_FREE((void**)&info->cookieData);
				info->cookieDataLen = 0;
				info->isNewServerReady = false;
				return;
			}

			debugLogA("Migration has started. New server will be %s", info->newServer);

			m_iDesiredStatus = m_iStatus;
			SetCurrentStatus(ID_STATUS_CONNECTING); // revert to connecting state

			info->isNewServerReady = info->isMigrating = true;
		}
		break;

	case ICQ_SERVER_NAME_INFO: // This is the reply to CLI_REQINFO
		debugLogA("Received self info");
		{
			BYTE bUinLen;
			unpackByte(&pBuffer, &bUinLen);
			pBuffer += bUinLen;
			pBuffer += 4;      /* warning level & user class */
			wBufferLength -= 5 + bUinLen;

			// This is during the login sequence
			if (pSnacHeader->dwRef == ICQ_CLIENT_REQINFO << 0x10) {
				// TLV(x01) User type?
				// TLV(x0C) Empty CLI2CLI Direct connection info
				// TLV(x0A) External IP
				// TLV(x0F) Number of seconds that user has been online
				// TLV(x03) The online since time.
				// TLV(x0A) External IP again
				// TLV(x22) Unknown
				// TLV(x1E) Unknown: empty.
				// TLV(x05) Member of ICQ since.
				// TLV(x14) Unknown
				oscar_tlv_chain *chain = readIntoTLVChain(&pBuffer, wBufferLength, 0);

				// Save external IP
				DWORD dwValue = chain->getDWord(0x0A, 1);
				setDword("IP", dwValue);

				// Save member since timestamp
				dwValue = chain->getDWord(0x05, 1);
				if (dwValue) setDword("MemberTS", dwValue);

				dwValue = chain->getDWord(0x03, 1);
				setDword("LogonTS", dwValue ? dwValue : time(NULL));

				disposeChain(&chain);

				// If we are in SSI mode, this is sent after the list is acked instead
				// to make sure that we don't set status before seing the visibility code
				if (!m_bSsiEnabled || info->isMigrating)
					handleServUINSettings(wListenPort, info);
			}
		}
		break;

	case ICQ_SERVER_RATE_CHANGE:
		if (wBufferLength >= 2) {
			WORD wStatus, wClass;
			DWORD dwLevel;
			// We now have global rate management, although controlled are only some
			// areas. This should not arrive in most cases. If it does, update our
			// local rate levels & issue broadcast.
			unpackWord(&pBuffer, &wStatus);
			unpackWord(&pBuffer, &wClass);
			pBuffer += 20;
			unpackDWord(&pBuffer, &dwLevel);
			{
				mir_cslock l(m_ratesMutex);
				m_rates->updateLevel(wClass, dwLevel);
			}

			if (wStatus == 2 || wStatus == 3) {
				// this is only the simplest solution, needs rate management to every section
				ProtoBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
				if (wStatus == 2)
					debugLogA("Rates #%u: Alert", wClass);
				else
					debugLogA("Rates #%u: Limit", wClass);
			}
			else if (wStatus == 4) {
				ProtoBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
				debugLogA("Rates #%u: Clear", wClass);
			}
		}

		break;

	case ICQ_SERVER_REDIRECT_SERVICE: // reply to family request, got new connection point
	{
		oscar_tlv_chain *pChain = NULL;
		cookie_family_request *pCookieData;

		if (!(pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0))) {
			debugLogA("Received Broken Redirect Service SNAC(1,5).");
			break;
		}

		// pick request data
		WORD wFamily = pChain->getWord(0x0D, 1);
		if ((!FindCookie(pSnacHeader->dwRef, NULL, (void**)&pCookieData)) || (pCookieData->wFamily != wFamily)) {
			disposeChain(&pChain);
			debugLogA("Received unexpected SNAC(1,5), skipping.");
			break;
		}

		FreeCookie(pSnacHeader->dwRef);

		// new family entry point received
		char *pServer = pChain->getString(0x05, 1);
		BYTE bServerSSL = pChain->getNumber(0x8E, 1);
		char *pCookie = pChain->getString(0x06, 1);
		WORD wCookieLen = pChain->getLength(0x06, 1);

		if (!pServer || !pCookie) {
			debugLogA("Server returned invalid data, family unavailable.");

			SAFE_FREE(&pServer);
			SAFE_FREE(&pCookie);
			SAFE_FREE((void**)&pCookieData);
			disposeChain(&pChain);
			break;
		}

		// Get new family server ip and port
		WORD wPort = info->wServerPort; // get default port
		parseServerAddress(pServer, &wPort);

		// establish connection
		NETLIBOPENCONNECTION nloc = { 0 };
		if (m_bGatewayMode)
			nloc.flags |= NLOCF_HTTPGATEWAY;
		nloc.szHost = pServer;
		nloc.wPort = wPort;

		HANDLE hConnection = NetLib_OpenConnection(m_hNetlibUser, wFamily == ICQ_AVATAR_FAMILY ? "Avatar " : NULL, &nloc);

		if (hConnection == NULL)
			debugLogA("Unable to connect to ICQ new family server.");
		// we want the handler to be called even if the connecting failed
		else if (bServerSSL) { /* Start SSL session if requested */
			debugLogA("(%p) Starting SSL negotiation", CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0));

			if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hConnection, 0)) {
				debugLogA("Unable to connect to ICQ new family server, SSL could not be negotiated");
				NetLib_CloseConnection(&hConnection, FALSE);
			}
		}

		(this->*pCookieData->familyHandler)(hConnection, pCookie, wCookieLen);

		// Free allocated memory
		// NOTE: "cookie" will get freed when we have connected to the avatar server.
		disposeChain(&pChain);
		SAFE_FREE(&pServer);
		SAFE_FREE((void**)&pCookieData);
		break;
	}

	case ICQ_SERVER_EXTSTATUS: // our session data
		debugLogA("Received owner session data.");

		while (wBufferLength > 4) { // loop thru all items
			WORD itemType = pBuffer[0] * 0x10 | pBuffer[1];
			BYTE itemFlags = pBuffer[2];
			size_t itemLen = pBuffer[3];

			if (itemType == AVATAR_HASH_PHOTO) { /// TODO: handle photo item
				// skip photo item
				debugLogA("Photo item recognized");
			}
			else if ((itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH) && (itemLen >= 0x10)) {
				debugLogA("Avatar item recognized");

				if (m_bAvatarsEnabled && !info->bMyAvatarInited) { // signal the server after login
					// this refreshes avatar state - it used to work automatically, but now it does not
					if (getByte("ForceOurAvatar", 0)) { // keep our avatar
						TCHAR *file = GetOwnAvatarFileName();
						SetMyAvatar(0, (LPARAM)file);
						SAFE_FREE(&file);
					}
					else { // only change avatar hash to the same one
						BYTE hash[0x14];
						memcpy(hash, pBuffer, 0x14);
						hash[2] = 1; // update image status
						updateServAvatarHash(hash, 0x14);
					}
					info->bMyAvatarInited = true;
					break;
				}
				// process owner avatar hash changed notification
				handleAvatarOwnerHash(itemFlags, pBuffer, itemLen + 4);
			}
			else if (itemType == 0x02) {
				debugLogA("Status message item recognized");
			}
			else if (itemType == 0x0E) {
				debugLogA("Status mood item recognized");
			}

			// move to next item
			if (wBufferLength >= itemLen + 4) {
				wBufferLength -= itemLen + 4;
				pBuffer += itemLen + 4;
			}
			else {
				pBuffer += wBufferLength;
				wBufferLength = 0;
			}
		}
		break;

	case ICQ_ERROR: // Something went wrong, probably the request for avatar family failed
	{
		WORD wError;
		if (wBufferLength >= 2)
			unpackWord(&pBuffer, &wError);
		else
			wError = 0;

		LogFamilyError(ICQ_SERVICE_FAMILY, wError);
	}
		break;

		// Stuff we don't care about
	case ICQ_SERVER_MOTD:
		debugLogA("Server message of the day");
		break;

	default:
		debugLogA("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef);
		break;
	}
}
コード例 #13
0
void CIcqProto::handleFileTransferPacket(directconnect* dc, PBYTE buf, WORD wLen)
{
	if (wLen < 1)
		return;

	NetLog_Direct("Handling file packet");

	switch (buf[0])
	{
	case PEER_FILE_INIT:   /* first packet of a file transfer */
		if (dc->initialised)
			return;
		if (wLen < 19)
			return;
		buf += 5;  /* id, and unknown 0 */
		dc->type = DIRECTCONN_FILE;
		{
			DWORD dwFileCount;
			DWORD dwTotalSize;
			DWORD dwTransferSpeed;
			WORD wNickLength;
			int bAdded;

			unpackLEDWord(&buf, &dwFileCount);
			unpackLEDWord(&buf, &dwTotalSize);
			unpackLEDWord(&buf, &dwTransferSpeed);
			unpackLEWord(&buf, &wNickLength);

			dc->ft = FindExpectedFileRecv(dc->dwRemoteUin, dwTotalSize);
			if (dc->ft == NULL)
			{
				NetLog_Direct("Unexpected file receive");
				CloseDirectConnection(dc);
				return;
			}
			dc->ft->dwFileCount = dwFileCount;
			dc->ft->dwTransferSpeed = dwTransferSpeed;
			dc->ft->hContact = HContactFromUIN(dc->ft->dwUin, &bAdded);
			dc->ft->dwBytesDone = 0;
			dc->ft->iCurrentFile = -1;
			dc->ft->fileId = -1;        
			dc->ft->hConnection = dc->hConnection;
			dc->ft->dwLastNotify = GetTickCount();

			dc->initialised = 1;

			file_sendTransferSpeed(this, dc);
			file_sendNick(this, dc);
		}
		BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, dc->ft, 0);
		break;

	case PEER_FILE_INIT_ACK:
		if (wLen < 8)
			return;
		buf++;
		unpackLEDWord(&buf, &dc->ft->dwTransferSpeed);
		/* followed by nick */
		file_sendNextFile(this, dc);
		break;

	case PEER_FILE_NEXTFILE:
		if (wLen < 20)
			return;
		buf++;  /* id */
		{
	  char *szAnsi;
			WORD wThisFilenameLen, wSubdirLen;
			BYTE isDirectory;

			unpackByte(&buf, &isDirectory);
			unpackLEWord(&buf, &wThisFilenameLen);
			if (wLen < 19 + wThisFilenameLen)
				return;
			SAFE_FREE(&dc->ft->szThisFile);
	  szAnsi = (char *)_malloca(wThisFilenameLen + 1);
			memcpy(szAnsi, buf, wThisFilenameLen);
			szAnsi[wThisFilenameLen] = '\0';
	  dc->ft->szThisFile = ansi_to_utf8(szAnsi);
			buf += wThisFilenameLen;

			unpackLEWord(&buf, &wSubdirLen);
			if (wLen < 18 + wThisFilenameLen + wSubdirLen)
				return;
			SAFE_FREE(&dc->ft->szThisSubdir);
	  szAnsi = (char *)_malloca(wSubdirLen + 1);
			memcpy(szAnsi, buf, wSubdirLen);
			szAnsi[wSubdirLen] = '\0';
			dc->ft->szThisSubdir = ansi_to_utf8(szAnsi);
			buf += wSubdirLen;

			unpackLEDWord(&buf, &dc->ft->dwThisFileSize);
			unpackLEDWord(&buf,  &dc->ft->dwThisFileDate);
			unpackLEDWord(&buf,  &dc->ft->dwTransferSpeed);

			/* no cheating with paths */
			if (!IsValidRelativePath(dc->ft->szThisFile) || !IsValidRelativePath(dc->ft->szThisSubdir))
			{
				NetLog_Direct("Invalid path information");
				break;
			}

			char *szFullPath = (char*)SAFE_MALLOC(strlennull(dc->ft->szSavePath)+strlennull(dc->ft->szThisSubdir)+strlennull(dc->ft->szThisFile)+3);
			strcpy(szFullPath, dc->ft->szSavePath);
			NormalizeBackslash(szFullPath);
			strcat(szFullPath, dc->ft->szThisSubdir);
			NormalizeBackslash(szFullPath);
//			_chdir(szFullPath); // set current dir - not very useful
			strcat(szFullPath, dc->ft->szThisFile);
			// we joined the full path to dest file
			SAFE_FREE(&dc->ft->szThisFile);
			dc->ft->szThisFile = szFullPath;

			dc->ft->dwFileBytesDone = 0;
			dc->ft->iCurrentFile++;

			if (isDirectory)
			{
				MakeDirUtf(dc->ft->szThisFile);
				dc->ft->fileId = -1;
			}
			else
			{
				/* file resume */
				PROTOFILETRANSFERSTATUS pfts = {0};

				file_buildProtoFileTransferStatus(dc->ft, &pfts);
				if (BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, dc->ft, (LPARAM)&pfts))
					break;   /* UI supports resume: it will call PS_FILERESUME */

				dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
				if (dc->ft->fileId == -1)
				{
					icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder."));
					CloseDirectConnection(dc);
					dc->ft->hConnection = NULL;
					break;
				}
			}
		}
		file_sendResume(this, dc);
		BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0);
		break;

	case PEER_FILE_RESUME:
		if (dc->ft->fileId == -1 && !dc->ft->currentIsDir)
			return;
		if (wLen < 13)
			return;
		if (wLen < 17)
			NetLog_Direct("Warning: Received short PEER_FILE_RESUME");
		buf++;
		{
			DWORD dwRestartFrom;

			unpackLEDWord(&buf, &dwRestartFrom);
			if (dwRestartFrom > dc->ft->dwThisFileSize)
				return;
			buf += 4;  /* unknown. 0 */
			unpackLEDWord(&buf, &dc->ft->dwTransferSpeed);
			buf += 4;  /* unknown. 1 */
			if (!dc->ft->currentIsDir)
				_lseek(dc->ft->fileId, dwRestartFrom, 0);
			dc->wantIdleTime = 1;
			dc->ft->dwBytesDone += dwRestartFrom;
			dc->ft->dwFileBytesDone += dwRestartFrom;
		}
		break;

	case PEER_FILE_SPEED:
		if (wLen < 5)
			return;
		buf++;
		unpackLEDWord(&buf, &dc->ft->dwTransferSpeed);
		dc->ft->dwLastNotify = GetTickCount();
		break;

	case PEER_FILE_DATA:
		if (!dc->ft->currentIsDir)
		{
			if (dc->ft->fileId == -1)
				break;
			buf++; wLen--;
			_write(dc->ft->fileId, buf, wLen);
		}
		else
			wLen = 0;
		dc->ft->dwBytesDone += wLen;
		dc->ft->dwFileBytesDone += wLen;
		if (GetTickCount() > dc->ft->dwLastNotify + 500 || wLen < 2048) 
		{
			PROTOFILETRANSFERSTATUS pfts;

			file_buildProtoFileTransferStatus(dc->ft, &pfts);
			BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts);
			dc->ft->dwLastNotify = GetTickCount();
		}
		if (wLen < 2048)
		{
			/* EOF */
			if (!dc->ft->currentIsDir)
				_close(dc->ft->fileId);
			dc->ft->fileId = -1;
			if ((DWORD)dc->ft->iCurrentFile == dc->ft->dwFileCount - 1)
			{
				dc->type = DIRECTCONN_CLOSING;     /* this guarantees that we won't accept any more data but that the sender is still free to closesocket() neatly */
				BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0);
			}
		}
		break;

	default:
		NetLog_Direct("Unknown file transfer packet ignored.");
		break;
	}
}
コード例 #14
0
ファイル: icq_server.cpp プロジェクト: raoergsls/miranda
void __cdecl CIcqProto::ServerThread(serverthread_start_info *infoParam)
{
	serverthread_info info = {0};

	info.isLoginServer = 1;
	info.wAuthKeyLen = infoParam->wPassLen;
	null_strcpy((char*)info.szAuthKey, infoParam->szPass, info.wAuthKeyLen);
	// store server port
	info.wServerPort = infoParam->nloc.wPort;

	srand(time(NULL));

	ResetSettingsOnConnect();

	// Connect to the login server
	NetLog_Server("Authenticating to server");
	{
		NETLIBOPENCONNECTION nloc = infoParam->nloc;
		nloc.timeout = 6;
		if (m_bGatewayMode)
			nloc.flags |= NLOCF_HTTPGATEWAY;

		hServerConn = NetLib_OpenConnection(m_hServerNetlibUser, NULL, &nloc);

		SAFE_FREE((void**)&nloc.szHost);
		SAFE_FREE((void**)&infoParam);

		if (hServerConn && m_bSecureConnection)
		{
			if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)hServerConn, 0))
			{
				icq_LogMessage(LOG_ERROR, LPGEN("Unable to connect to ICQ login server, SSL could not be negotiated"));
				SetCurrentStatus(ID_STATUS_OFFLINE);
				NetLib_CloseConnection(&hServerConn, TRUE);
				return;
			}
		}

	}

	// Login error
	if (hServerConn == NULL)
	{
		DWORD dwError = GetLastError();

		SetCurrentStatus(ID_STATUS_OFFLINE);

		icq_LogUsingErrorCode(LOG_ERROR, dwError, LPGEN("Unable to connect to ICQ login server"));
		return;
	}

	// Initialize direct connection ports
	{
		DWORD dwInternalIP;
		BYTE bConstInternalIP = getSettingByte(NULL, "ConstRealIP", 0);

		info.hDirectBoundPort = NetLib_BindPort(icq_newConnectionReceived, this, &wListenPort, &dwInternalIP);
		if (!info.hDirectBoundPort)
		{
			icq_LogUsingErrorCode(LOG_WARNING, GetLastError(), LPGEN("Miranda was unable to allocate a port to listen for direct peer-to-peer connections between clients. You will be able to use most of the ICQ network without problems but you may be unable to send or receive files.\n\nIf you have a firewall this may be blocking Miranda, in which case you should configure your firewall to leave some ports open and tell Miranda which ports to use in M->Options->ICQ->Network."));
			wListenPort = 0;
			if (!bConstInternalIP) deleteSetting(NULL, "RealIP");
		}
		else if (!bConstInternalIP)
			setSettingDword(NULL, "RealIP", dwInternalIP);
	}

	// Initialize rate limiting queues
	{ 
		icq_lock l(m_ratesMutex);

		m_ratesQueue_Request = new rates_queue(this, "request", RML_IDLE_30, RML_IDLE_50, 1);
		m_ratesQueue_Response = new rates_queue(this, "response", RML_IDLE_10, RML_IDLE_30, -1);
	}

	// This is the "infinite" loop that receives the packets from the ICQ server
	{
		int recvResult;
		NETLIBPACKETRECVER packetRecv = {0};

		info.hPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 0x2400);
		packetRecv.cbSize = sizeof(packetRecv);
		packetRecv.dwTimeout = INFINITE;
		while (serverThreadHandle)
		{
			if (info.bReinitRecver)
			{ // we reconnected, reinit struct
				info.bReinitRecver = 0;
				ZeroMemory(&packetRecv, sizeof(packetRecv));
				packetRecv.cbSize = sizeof(packetRecv);
				packetRecv.dwTimeout = INFINITE;
			}

			recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)info.hPacketRecver, (LPARAM)&packetRecv);

			if (recvResult == 0)
			{
				NetLog_Server("Clean closure of server socket");
				break;
			}

			if (recvResult == SOCKET_ERROR)
			{
				NetLog_Server("Abortive closure of server socket, error: %d", GetLastError());
				break;
			}

			if (m_iDesiredStatus == ID_STATUS_OFFLINE)
			{ // Disconnect requested, send disconnect packet
				icq_sendCloseConnection();

				// disconnected upon request
				m_bConnectionLost = FALSE;
				SetCurrentStatus(ID_STATUS_OFFLINE);

				NetLog_Server("Logged off.");
				break;
			}

			// Deal with the packet
			packetRecv.bytesUsed = handleServerPackets(packetRecv.buffer, packetRecv.bytesAvailable, &info);
		}
		serverThreadHandle = NULL;

		// Time to shutdown
		NetLib_CloseConnection(&hServerConn, TRUE);

		// Close the packet receiver (connection may still be open)
		NetLib_SafeCloseHandle(&info.hPacketRecver);

		// Close DC port
		NetLib_SafeCloseHandle(&info.hDirectBoundPort);
	}

	// disable auto info-update thread
	icq_EnableUserLookup(FALSE);

	if (m_iStatus != ID_STATUS_OFFLINE && m_iDesiredStatus != ID_STATUS_OFFLINE)
	{
		if (!info.bLoggedIn)
			icq_LogMessage(LOG_FATAL, LPGEN("Connection failed.\nLogin sequence failed for unknown reason.\nTry again later."));

		// set flag indicating we were kicked out
		m_bConnectionLost = TRUE;

		SetCurrentStatus(ID_STATUS_OFFLINE);
	}

	// signal keep-alive thread to stop
	StopKeepAlive(&info);

	// Close all open DC connections
	CloseContactDirectConns(NULL);

	// Close avatar connection if any
	StopAvatarThread();

	// Offline all contacts
	HANDLE hContact = FindFirstContact();
	while (hContact)
	{
		DWORD dwUIN;
		uid_str szUID;

		if (!getContactUid(hContact, &dwUIN, &szUID))
		{
			if (getContactStatus(hContact) != ID_STATUS_OFFLINE)
			{
				char tmp = 0;

				setSettingWord(hContact, "Status", ID_STATUS_OFFLINE);

				handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0);
			}
		}

		hContact = FindNextContact(hContact);
	}

	setSettingDword(NULL, "LogonTS", 0); // clear logon time

	servlistPendingFlushOperations(); // clear pending operations list

	{ // release rates queues
		icq_lock l(m_ratesMutex);

		SAFE_DELETE((void_struct**)&m_ratesQueue_Request);
		SAFE_DELETE((void_struct**)&m_ratesQueue_Response);
		SAFE_DELETE((void_struct**)&m_rates);
	}

	FlushServerIDs();         // clear server IDs list

	NetLog_Server("%s thread ended.", "Server");
}