YASAMM - re-inventing the wheel

oldfart

Member
Hi guys,

YASAMM - Yet Another Steam Account Manager, Manager ;)

I am probably reinventing the wheel here, but shortly I would like a few people to trial a new Steam Account Manager. It's currently aimed at people who own more than 1 x legitimate Steam Account. :eek:

I am hoping that this one will have a few things in it's favour.

It was originally conceived so I could spread my spare Steam Accounts amongst my children and their friends, without handing out my passwords etc. - shades of Steam's User Agreement :rolleyes::

Basically this is how it works:-

My son and I are both running my 2.5MB YASAMM executable on our respective PC's at different points on the Internet (or LAN). He wants to use a game on one of my spare steam accounts and I don't wish to tell him the Password.

Solution (1 of 3)
1. Agree on a "PassPhrase"
2. Select "Contact a friend using an IP address" Button on the YASAMM.
3. Enter his IP and the Listener port of his "internal server"
4. Click go
5. Communicate (in text)
6. <then a miracle occurs>
7. A game from 1 x of my Steam Accounts is launched on my son's PC

Solution (2 of 3)
1. Retrieve my son's IP, port and PassPhrase from my local Dbase etc

Solution (3 of 3)
1. Login to our central P2P & web server to get my son's current IP etc

peer01.jpg


I am just finishing the GUI for the P2P and then some Beta testers would be appreciated.

You guys have heaps more experience than me at "cracking", so some pointers regarding security would be appreciated.

cheers
AnOldBloke
 
6. <then a miracle occurs>
My favorite part haha. Does look quite interesting however, similar to how our cafe system worked back in the day.
 
Hi WorldWarIII,

Yes, I needed a laugh after some of the grief Windoze (ASyncSockets) have visited on me. :rolleyes:

The mechanics all work - but it's the user interface and operational design that is not exactly my strong points.

Any suggestions are welcome .. I'll give you a brief idea.

1. Each "Peer" has it's own TCP/IP Listen server waiting for connections - by listening on a dedicated port.
2. A client when connected will pop up a "floating dialog" on both PC's
3. Text flow happens quite happily.
4. Somehow a game must be decided on (drop down box on the lender's side ?)
4a. The borrower request some game (may know by personal experience - or the lender somehow "advertising" it - via the web site etc).
5. The borrower and lender authenticate each other (digitally or personally)
6. A PassPhrase is negotiated and delivered - preferably by voice, phone, email etc - definitely back-channel ...
7. The Steam Account Username/Password is encrypted using the PassPhrase and sent from the lender's YASAMM to the borrower's YASAMM.
8. The Borrower's YASAMM then launches the Steam Account on the Borrower's PC - via - the C++ Wrapper.
9. YASAMM - watches the game until it is implicitly or explicitly terminated.
10. The C++ Wrapper is then "unloaded"
11. The borrower can then launch any of their own local games (this may be a way to download legit GCF's from Steam - just a thought).

etc etc etc - A good way of completing the UI would be helpful ..

cheers
 
What's the point of having it select a game? Simply having the account sent is sufficient. Otherwise, you are getting out of hand if the game crashes, want to play something else, etc etc.
 
What's the point of having it select a game? Simply having the account sent is sufficient. Otherwise, you are getting out of hand if the game crashes, want to play something else, etc etc.

Hi WorldWarIII,

Up until Erix pointed me in the direction of the Steam.dll API - I was stuck with using the very insecure "command line" login for a GUI start (although Steam seems to have recently fixed that hole - by cleaning up the command line/environment variables after it starts).

This "command line" version gives a borrower full access to the account because it kicks off the GUI. The Steam DLL API doesn't seem to allow that option (I may have missed something in there). So, do you know how to start the account in GUI mode, just by using the Steam DLL API ?

When our clan members borrow a library copy of our (legit) Steam games - I actually use the "command line" to start the GUI for them, similarly I use the "command line" if they are just accessing their own accounts from their local Dbase on their PC (or a friend's for that matter).

But IMO, the Steam DLL API "Launch Game" is perfect for launching a specific game off (across the Net). :D

When Erix pointed me towards the API - it was one of the biggest boosts that I have had for a while and I am posting this info and some snippets to show my appreciation for the tremendous aid that it has been.

By my estimates - I may have a pre-Beta available within a day or 2 as I have just finished the "resizing" of the text chat windows and now all I have to do is figure out an elegant way to select a game.

cheers
AnOldBloke
P.S. Anyone want a CWinThread based Client/Server source code snippet).


Here are some images to show I'm not too full of BS ;)
vnetcafe124.jpg


The 2 peers talking to each other (on my Dev PC in this case).
vnetcafe125.jpg
 
Hmmm looks good then all in all. Keep up the dev, and let us know how it goes!
 
Hmmm looks good then all in all. Keep up the dev, and let us know how it goes!

Hi there,

I would like some advice on how secure the methods I am using are - as previously stated - some of you people here, have much more experience hacking, cracking, reverse-engineering (mine is mainly 20 x years ago :confused:) than I do.

All my steam games/accounts are legit and I don't mind "lending" those that I'm not using - but I wouldn't like to have them hacked and lost - if you get my drift.

IMO Steam's User Agreement is a "crock-of-shite" and unfair to boot - that's why most new games I buy for myself or my kids, I put in new Steam accounts. I also strongly advocate that course of action to others! IMO that little extra effort is worth the benefits - hence this YASAMM ;)

BTW: Are there people at FS who can verify that this code is "virus free" - non hacking - keylogging - trojan ( :rolleyes: ) etc. Or do you need to examine the Source ?

Note:
1. This code will auto-check for updates (you can chose to download and launch an internal updater)
2. Start a Listen Server (TCP/IP)
3. Allow multiple TCP/IP Peers to communicate concurrently
4. Launch Application on the host PC (Steam, Steam.dll, various games etc)
5. Watch and terminate process/applications
6. Talk, using HTTP to a web server
7. Talk via SSL using HTTP to yet another web server
8. Detect (if enabled) your local LAN information, firewall, DHCP server, domain etc)
9. Read and write to the registry

And that's only the executable ..

The Web server (my code also) runs on an Apache Server, using PHP, MySQL, XHTML, CSS and includes the facility for clan members to borrow old accounts from other members - this project was aimed at my clan community - but I am interested in sharing it.

I am happy to release snippets of the code and for a senior member of FS, possibly the entire project - but who knows - it may be a dismal failure - time will tell ...

cheers
AnOldBloke
 
I would suggest checking if the blob file is saving the information on the clients computer from the data sent by the host. If that is clean, you are okay.
 
I'm trying to think of a way you can incorporate "rain" (steamCookers API for remote downloading/mounting of GCFs on Valves content servers).

Would it be any help for this..

1. Connect to account database, say you wanted to play game Counter Strike: Source
2. Server sends client user/pass of the account with the game subscription
3. Client receives login information
4. Client logs in and loads ContentDescriptionRecord (rain api) and finds all the dependencys for Counter Strike: Source and adds them to a queue to be downloaded
5. Client downloads files Ex: Source sounds.gcf, Source engine.gcf
6. When the download finishes it will start the emulator (steamstartapp API call I believe?)

As long as you are planning to work with a valid account I can help you with basically anything so just let me know of your ideas ;).

My latest work with Steam stuff:



This application is fully capable of downloading/updating files directly from Steam's content servers. What I wanted to do was implement a reliable way to have clients download content they do not own from a pre-configured remote server. I'm stuck on how I should transfer the files however. I wanted to do p2p with super peers for maximum speeds. The only way I can see that working 100% is to have a linux cpp console program. This I don't think would be too difficult except I only know vb.net and I don't know how well the interoperability would be between the two languages.
 
Thanks WorldWarIII - I will remember that!


G'day Erix920,

The brain is a bit "fuzzy" and the tongue a bit "furry" - now that it's New Year's Morning (after :rolleyes: ) - oops afternoon.

I was hoping to finish encrypting the "Chat" channel today ... but in my state it may take a bit longer.

I'm not really up to date on a number of the things you are referring to in your post as I have only ever worked around the periphery of Steam and am not too sure of it's inner workings.

My thoughts are that if there is 1 x valid Steam account for a specific game within the FS community and people are willing to share it then ..
Each person could use that account to directly download the Steam files - but no doubt - Steam would wake up to that very quickly and probably ban the account :mad:

Just a thought - I have a number of games available on my gaming PC but they don't all belong to the same Steam account. So, a question is - if I login with a DODS only account, will it update other games that exist on the PC or will it only update games on the logged-in account ?

Which begs the thought - and is maybe what you are suggesting - i.e.
1. I have a legitimate Steam Account with say L4D2 on it
2. An update becomes available - I download it and run it.
Later ..
3. I connect to a YASAMM running on central FS server somewhere and "kick off" L4D2 using my legit account.
4. The central FS server then gets updated directly from Steam
5. The central FS server then allows other FS members to download and access the updated content

Finally, in regards to your offer of assistance with "legit" Steam accounts - I am still not able to get an accurate list of all the subscribed games my (various) accounts have - I'm only accessing the Steam.dll and from what I've read elsewhere I may need to access additional Steam Dlls - is this correct ?

cheers
AnOldBloke
 
Wow I can obviously see what i would have to do if i want to be a coder...(and maybe a hacker:cool:) at my age, my head hurts after reading all of this. I know I'm late but whatever. So you're trying to share a account without giving your password? that could be a major accomplishment. Have luck on your journey of making this a reality. :)
 
I'm not really up to date on a number of the things you are referring to in your post as I have only ever worked around the periphery of Steam and am not too sure of it's inner workings.

My thoughts are that if there is 1 x valid Steam account for a specific game within the FS community and people are willing to share it then ..
Each person could use that account to directly download the Steam files - but no doubt - Steam would wake up to that very quickly and probably ban the account :mad:

Just a thought - I have a number of games available on my gaming PC but they don't all belong to the same Steam account. So, a question is - if I login with a DODS only account, will it update other games that exist on the PC or will it only update games on the logged-in account ?

Which begs the thought - and is maybe what you are suggesting - i.e.
1. I have a legitimate Steam Account with say L4D2 on it
2. An update becomes available - I download it and run it.
Later ..
3. I connect to a YASAMM running on central FS server somewhere and "kick off" L4D2 using my legit account.
4. The central FS server then gets updated directly from Steam
5. The central FS server then allows other FS members to download and access the updated content

Finally, in regards to your offer of assistance with "legit" Steam accounts - I am still not able to get an accurate list of all the subscribed games my (various) accounts have - I'm only accessing the Steam.dll and from what I've read elsewhere I may need to access additional Steam Dlls - is this correct ?

cheers
AnOldBloke

Exactly what I was saying. With rain, we can have a app that checks the content description record file every x amount of time. If it sees an update, it will log in with an account that has that subscription and download the updated files.

This is the code for the rain API I was talking about. I hope you can see something eye catching seeing how it's the first of it's kind ;).:

Code:
#include <stdio.h>
#include <malloc.h>
#include <string.h> 
#include "rain.h"

void printContentOf(GCF gcf, char * root)
{
	char path[500];
	char ** files=RAIN_listFiles(gcf,root);
	char ** file=files;
	
	while (*file)
	{
		sprintf(path,"%s/%s",root,*file);
		if (RAIN_isDirectory(gcf,path))
		{
			printf(" - [%s]\n",path);
		}
		else
		{
			unsigned int size=RAIN_effectiveSize(gcf,path);
			unsigned int expectedSize=RAIN_size(gcf,path);
			float completion=100.0f;
			if (expectedSize) completion=(float)100.0f*(float)size/(float)expectedSize;
			printf(" - %s : %u bytes (%3.2f%%)\n",path,size,completion);
		}
		file++;
	}
	RAIN_free(files);
}

void printChecksums(GCF gcf, char * filePath)
{
	Checksums checksums=RAIN_getChecksums(gcf,filePath);
	
	printf("%s has %u checksums :\n",filePath,checksums.count);
	
	for (unsigned int ind=0;ind<checksums.count;ind++)
	{
		printf("[%08X]",checksums.checksums[ind]);
	}
	printf("\n");
	RAIN_free(checksums);
}
void extractFile(GCF gcf, char * filePath, char * extractedPath)
{
	printf("Extracting %s :\n",filePath);
	unsigned int size=RAIN_size(gcf,filePath);
	
	GCF_ENTRY file=RAIN_openToRead(gcf,filePath);

	if (!file)
	{
		printf("Failed to open file\n");
		return;
	}
	
	FILE * outFile=fopen(extractedPath,"wb");

	unsigned char buffer[1000];
	unsigned int extracted=0;

	while (extracted<size)
	{
		unsigned int len=RAIN_read(file,buffer,1000);
		
		if (!len)
		{
			printf("\nNo more data available or data corrupted\n");
		}
		
		fwrite(buffer,1,len,outFile);

		extracted+=len;
		printf(".");
	}

	RAIN_close(file);
	fclose(outFile);

	printf("\nFile extracted into %s\n",extractedPath);
}

void importFile(GCF gcf, char * extractedPath, char * filePath)
{
	printf("Importing %s :\n",extractedPath);
	
	RAIN_delete(gcf,filePath);
	GCF_ENTRY file=RAIN_openToWrite(gcf,filePath);

	if (!file)
	{
		printf("Failed to open file\n");
		return;
	}
	
	FILE * inFile=fopen(extractedPath,"rb");

	unsigned char buffer[1000];
	unsigned int len=0;

	while (len=fread(buffer,1,1000,inFile))
	{		
		RAIN_write(file,buffer,len);
		printf(".");
	}

	RAIN_close(file);
	fclose(inFile);

	printf("\nFile imported into %s : %u bytes\n",filePath,RAIN_size(gcf,filePath));
}

void copyFile(GCF fromGcf, GCF toGcf, char * filePath)
{
	unsigned int size=RAIN_size(fromGcf,filePath);
	
	printf("Downloading %s (%u bytes) :\n",filePath,size);

	
	GCF_ENTRY fromFile=RAIN_openToRead(fromGcf,filePath);

	if (!fromFile)
	{
		printf("Failed to open origin file\n");
		return;
	}
	
	GCF_ENTRY toFile=RAIN_openToWrite(toGcf,filePath);

	if (!toFile)
	{
		printf("Failed to open target file\n");
		return;
	}

	unsigned char buffer[1000];
	unsigned int copied=0;

	while (copied<size)
	{
		unsigned int len=RAIN_read(fromFile,buffer,1000);

		if (!len)
		{
			printf("\nNo more data available or data corrupted\n");
			break;
		}
		
		RAIN_write(toFile,buffer,len);

		copied+=len;
		printf(".");
	}

	RAIN_close(fromFile);
	RAIN_close(toFile);

	printf("\nFile downloaded\n");
}

int main(int argc, char ** argv)
{
	RAIN_enableLogs("rain.log");

	printf("Downloading CDR\n");

	CDR cdr=RAIN_downloadCDR("gds1.steampowered.com:27030");
    
	if (!cdr)
	{
		printf("Failed to download cdr\n");
		return 1;
	}
	
	printf("Saving CDR\n");
	RAIN_save(cdr,"ContentDescriptionRecord.bin");
	RAIN_free(cdr);

	printf("Loading CDR\n");
	cdr=RAIN_load("ContentDescriptionRecord.bin");

	APPInfo info=RAIN_getAppInfo(cdr,7);
	
	printf("Winui info :\n");
	printf(" - appId           : %u\n",info.appId);
	printf(" - format          : %s\n",info.isNcf ? "NCF" : "GCF");
	printf(" - name            : %s\n",info.name);
	printf(" - common dir      : %s\n",info.installDirName);
	printf(" - current version : %u\n",info.currentVersion);

	RAIN_free(cdr);

	printf("Mounting Latest Winui from content server...\n");

	GCF remoteGcf=RAIN_mountGcfOnContentServer("gds1.steampowered.com:27030",5,"username","password",7,info.currentVersion);
	
	printf("Creating local winui ...\n");

	GCF localGcf=RAIN_newEmptyGcf("winui.gcf",remoteGcf);

	copyFile(remoteGcf,localGcf,"/Support/script.js");
	copyFile(remoteGcf,localGcf,"/Support/support.dll");

	printChecksums(remoteGcf,"/Support/script.js");
	printChecksums(localGcf,"/Support/support.dll");

	RAIN_free(remoteGcf);
	RAIN_free(localGcf);
	
 	GCF gcf=RAIN_mountGcf("winui.gcf");
	
	if (!gcf)
	{
		printf("Failed to mount gcf\n");
		return 1;
	}
	
	printf("Mounted GCF %u version %u\n",RAIN_getAppId(gcf),RAIN_getAppVersion(gcf));

	printContentOf(gcf,"/Support");

	extractFile(gcf,"/Support/script.js","extracted.txt");

	importFile(gcf,"extracted.txt","/Support/script.js");

	RAIN_unmountGcf(gcf);

	return 0;
}

This is how I enumerate subscriptions in vb.net (snippet from my cracker):

Code:
Public Shared Sub queryAccountInfo() ' 4
        Try
            Dim SErr As New TSteamError()
            games = ""
            Dim iBuffSize As UInteger = 512
            Dim iSteamReturn As Integer = 0

            Dim AppStats As New TSteamAppStats()

            iSteamReturn = SteamGetAppStats(AppStats, SErr)

            Dim SubscriptionStats As New TSteamSubscriptionStats()

            iSteamReturn = SteamGetSubscriptionStats(SubscriptionStats, SErr)

            If SubscriptionStats.uNumSubscriptions > 0 Then
                Dim RawSubscriptionIDs As UInteger()
                RawSubscriptionIDs = New UInteger(SubscriptionStats.uNumSubscriptions - 1) {}
                iSteamReturn = SteamGetSubscriptionIds(RawSubscriptionIDs, SubscriptionStats.uNumSubscriptions, SErr)

                Dim tAppIDs = New UInteger(AppStats.uNumApps) {} 'set the array to the maximum amount of Steam(Apps)

                ' Here we are creating a pointer to the tAppIDs array and allocating the correct amount of memory for manual marshaling
                Dim arraytype As Object = tAppIDs.GetValue(0)
                Dim arraysize As Integer = Marshal.SizeOf(arraytype)
                Dim buffer As Integer = arraysize * tAppIDs.Length
                Dim intPtr As IntPtr = Marshal.AllocHGlobal(buffer)

                Dim isSubSubscribed As UInteger = 0
                Dim isSubReady As UInteger = 0

                For Each RawSubscriptionID As UInteger In RawSubscriptionIDs
                    iSteamReturn = SteamIsSubscribed(RawSubscriptionID, isSubSubscribed, isSubReady, SErr)

                    If isSubSubscribed = 1 Then

                        Dim SubNFO As New TSteamSubscription()
                        SubNFO.Name = New String(" "c, 255)
                        SubNFO.MaxNameChars = 255
                        SubNFO.AppIDs = intPtr
                        SubNFO.MaxAppIDs = AppStats.uNumApps

                        iSteamReturn = SteamEnumerateSubscription(RawSubscriptionID, SubNFO, SErr)

                        If Not RawSubscriptionID = 0 Then
                            If Not SubNFO.Name = "" Then
                                If Not games = "" Then
                                    games = games & "," & SubNFO.Name
                                Else
                                    games = SubNFO.Name
                                End If
                            End If
                        End If

                        Dim ofs As Integer = 0
                        Dim uLoop As Integer
                        For uLoop = 0 To SubNFO.NumApps - 1 'populate our app array from marshaled memory
                            tAppIDs(uLoop) = Marshal.ReadInt32(intPtr, ofs)
                            ofs = ofs + arraysize
                        Next

                        For uLoop = 0 To SubNFO.NumApps - 1 'Clear the relevant array indexes for the next subscription
                            tAppIDs(uLoop) = 0
                        Next

                    End If
                Next
                Marshal.FreeHGlobal(intPtr) 'free the marshaled memory
            End If
        Catch ex As Exception
            MsgBox("Error at 4: " & ex.Message)
        End Try

    End Sub

If you want to experiment with archive updating then I will provide you the API. However, you'll need to have some primitive knowledge about how GCFs work. If you have any specific questions ask 'em here :).
 
Erix920 said:
This application is fully capable of downloading/updating files directly from Steam's content servers. What I wanted to do was implement a reliable way to have clients download content they do not own from a pre-configured remote server. I'm stuck on how I should transfer the files however. I wanted to do p2p with super peers for maximum speeds. The only way I can see that working 100% is to have a linux cpp console program. This I don't think would be too difficult except I only know vb.net and I don't know how well the interoperability would be between the two languages.
Hi Erix920,

I'm in the middle of "Diffie-Hellman" and "man-in-the-middle" attacks and I need a break ... so,

I have had a thought that may be easier to implement - using Apache/PHP on the server (thus whether it's a Windoze on *nix is of little consequence).

1. Using Apache - saves having to write a durable, reliable, multi user server from "scratch" - it can be configured to listen on any number of ports and tuned to handle multiple clients .. (we must have some Apache guru's somewhere amongst this mob :rolleyes: )

2. Using PHP, we can write some applications that run on the Apache server and handles HTTP like requests from remote clients (I have used this method quite successfully in the past). Depending on the setup, each application may handle the updates for a specific game/GCF etc

3. You (Erix920 :D) can write a VB application with built in Web Browser capability without the GUI (I have hand crafted one for Win32 C++) but I know MS has a bucket-load of of API's that will do most of this work!

4. Your VB application (running on any user's PCs) could then act as a client and connect to the Apache server and download the required content. (You could say .. access http://fs_server1/steamcontent/css/update.php - with an agreed protocol etc if the local user wanted to check for updates to CSS)

I can flesh in a few more details and suggest some protocols as well as assist with the PHP - if this is of interest please let me know. I'll see which APIs I consider would be a help to your VB App - check the C++ snippet below - there is bound to be a VB equivalent around on the net!

cheers
AnOldBloke

Code:
/////////////////////////////////////////////////////// 
/*  
*  inetcpp.cpp  *  
*  Written by Wei Hua  
*  of Microsoft Developer Support  *  
*  Functions implemented in inetall.cpp  *  
*  MyAllocMem()         - memory allocation helper function  
*  MyFreeMem()          - free memory allocated by MyAllocMem  
*  CMyItemArray::CMyItemArray()  
*                       - CMyItemArray constructor  
*  CMyItemArray::~CMyItemArray()  
*                       - CMyItemArray destructor  
*  CMyItemArray::Add()  - Add an item to the array  
*  CMyItemArray::RemoveAll()  
*                       - Remove all items in the array  
*  CMyItemArray::GetAt()- Get an item given an index  
*  CMyItemArray::GetSize()  
*                       - Get the size of the array  
*  WinMain()           - WinMain, display our main dialog box  
*  Dlg_Proc()           - Message Proc for the main dialog box  
*  Dlg_OnInitDialog()   - WM_INITDIALOG handler for the main dialog box  
*  Dlg_OnCommand()      - WM_COMMAND handler for the main dialog box  
*  Dlg_OnDestroy()      - WM_DESTROY handler for the main dialog box  
*  BOOL UpdateUI()      - Exchange data between UI and member variables  
*  FillFtpOrFileObjArray()  
*                       - Enumerate a FTP or FILE URL, and populate a CMyItemArray  
*  FillTreeControl()    - Draw tree structure of a FTP or FILE URL in Treeview Ctrl  
*  Copyright (C) 1997 Microsoft Corporation. All rights reserved  *  
*/ ////////////////////////////////////////////////////// 
#include <windows.h>  
#include <windowsx.h>  //we use message crackers to make code easier to read  
#include <commctrl.h> 
#include <tchar.h> 
#include <string.h> 
#include <wininet.h> 
#include "inetall.h"   
LPVOID MyAllocMem(     DWORD cb) 
{     
return HeapAlloc(GetProcessHeap(),      
HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, cb); 
}   
BOOL MyFreeMem(     LPVOID pMem) 
{     return HeapFree(GetProcessHeap(), 0, pMem); 
} 
 ////////////////////////////////////////////////////// 
 //CMyItemArray Implementation functions 
 CMyItemArray::CMyItemArray() 
 {
  m_nCount = 0;
   m_pItemlist = NULL; 
   }  
CMyItemArray::~CMyItemArray() 
{ if (m_pItemlist) MyFreeMem(m_pItemlist); 
}  
int CMyItemArray::Add(ItemAttrib& item) { if (m_nCount%10 == 0) { //Allocating 10 ItemAttrib at a time LPVOID pTemp = MyAllocMem((m_nCount+10) * sizeof (ItemAttrib)); if (!pTemp) return -1;  //The called function should check return value CopyMemory (pTemp, m_pItemlist, m_nCount*sizeof(ItemAttrib)); MyFreeMem(m_pItemlist); m_pItemlist = (PItemAttrib)pTemp; } lstrcpy(m_pItemlist[m_nCount].szObjectPath, item.szObjectPath); m_pItemlist[m_nCount].nObjectType = item.nObjectType; return m_nCount++; //return index of the newly added item. Increment count. }  void CMyItemArray::RemoveAll() { if (m_pItemlist) MyFreeMem(m_pItemlist); m_pItemlist = NULL; m_nCount = 0; }  ItemAttrib CMyItemArray::GetAt(int nIndex) { if (nIndex>=0 && nIndex < m_nCount) return m_pItemlist[nIndex]; else { ItemAttrib nullItem; (nullItem.szObjectPath)[0]='\0'; nullItem.nObjectType = -1; return nullItem; } }  int CMyItemArray::GetSize() { return m_nCount; } //End of CMyItemArray Implementation //////////////////////////////////////////////////////  ////////////////////////////////////////////////////// //Declare Dialog callback function. BOOL CALLBACK Dlg_Proc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);  //WinMain just displays a dialogbox int APIENTRY WinMain (HINSTANCE hInstance,     HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) {  g_hInst = hInstance; InitCommonControls(); if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_INETALL_DIALOG),  NULL, (DLGPROC)Dlg_Proc) == -1)  MessageBox(NULL, "Failure in creating main dialog window", "Error", MB_OK); return(0); }  BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,     LPARAM lParam)  { BOOL bRet =  FALSE;  g_Inet.m_dwSizeHtml = 1024; g_Inet.m_phtml = (LPTSTR)MyAllocMem(g_Inet.m_dwSizeHtml); if (!g_Inet.m_phtml) { MessageBox(hwnd, "Memory Allocation Failure", "Error", MB_OK); return bRet; }  bRet = (g_hDlg = hwnd) && (g_Inet.hCheckBoxCern = GetDlgItem(g_hDlg, IDC_CERN)) && (g_Inet.hwndUrl = GetDlgItem(g_hDlg, IDC_URL)) && (g_Inet.hwndPassword = GetDlgItem(g_hDlg, IDC_PASSWORD)) && (g_Inet.hwndUsername = GetDlgItem(g_hDlg, IDC_USERNAME)) && (g_Inet.hTreeViewCtrl = GetDlgItem(g_hDlg, IDC_TREE1)) && (g_Inet.hwndHTML = GetDlgItem(hwnd, IDC_HTML));  if (!bRet) return bRet;  //Set inital service to HTTP, and select the option button. g_Inet.m_dwServiceType = SERVICE_TYPE_HTTP; ShowWindow(g_Inet.hCheckBoxCern, SW_HIDE); //CERN check box only shown when doing ftp g_Inet.m_phtml[0]=g_Inet.m_url[0] = g_Inet.m_password[0] = g_Inet.m_username[0] = '\0';  g_Inet.m_cern = TRUE;  //Send g_Inet to update UI UpdateUI(FALSE);  g_Inet.m_curItem = NULL; //No current selected item in tree control  //Set up image list and tree control g_Inet.hImgList = ImageList_Create(16, 15, 0, 3, 2); HBITMAP hBmTemp; for (int iCnt=IDB_BMERR; iCnt<=IDB_BMFILE; iCnt++) { hBmTemp = LoadBitmap(g_hInst, MAKEINTRESOURCE(iCnt)); ImageList_Add(g_Inet.hImgList, hBmTemp, NULL); } TreeView_SetImageList(g_Inet.hTreeViewCtrl, g_Inet.hImgList, TVSIL_NORMAL); TV_INSERTSTRUCT tvstruct; tvstruct.hParent = NULL; tvstruct.hInsertAfter = TVI_FIRST; tvstruct.item.iImage = 0; tvstruct.item.iSelectedImage = 0; tvstruct.item.pszText = _T("Root"); tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; g_Inet.m_curItem= (HTREEITEM)SendMessage(g_Inet.hTreeViewCtrl, TVM_INSERTITEM,0, (LPARAM)(LPTV_INSERTSTRUCT)&tvstruct); g_Inet.m_bRedrawTree = TRUE; return(TRUE); }   void Dlg_OnDestroy (HWND hwnd) { if (g_Inet.hImgList) ImageList_Destroy(g_Inet.hImgList); if (g_Inet.m_phtml) MyFreeMem(g_Inet.m_phtml); }  void Dlg_OnCommand (HWND hwnd, int id,     HWND hwndCtl, UINT codeNotify)  {    switch (id) {       case IDCANCEL:          EndDialog(hwnd, id);          break;    case IDC_HTTP: //http option button is clicked.   case IDC_FTP:  //ftp option button is clicked.   case IDC_FILE:  //file option button is clicked. g_Inet.m_url[0] = g_Inet.m_password[0] = g_Inet.m_username[0]  = g_Inet.m_phtml[0]= '\0'; g_Inet.m_dwServiceType = (id == IDC_HTTP)? SERVICE_TYPE_HTTP: (id ==  IDC_FTP)?SERVICE_TYPE_FTP : SERVICE_TYPE_FILE; //Show CERN check box for FTP URL only if (id == IDC_FTP) ShowWindow(g_Inet.hCheckBoxCern, SW_SHOW); else ShowWindow(g_Inet.hCheckBoxCern, SW_HIDE); UpdateUI(FALSE); //Send g_Inet to update UI g_Inet.m_itemArray.RemoveAll();  FillTreeControl(); break;     case IDC_CERN:  //CERN checked box is clicked. g_Inet.m_cern = IsDlgButtonChecked(g_hDlg, IDC_CERN)==BST_CHECKED; break;    case IDC_GETDATA: //GetData button is clicked HCURSORhCursor; hCursor = SetCursor(LoadCursor (NULL, IDC_WAIT)); ShowCursor(TRUE);  //Get the UI setting to g_Inet UpdateUI(TRUE); g_Inet.m_phtml[0]= '\0'; UpdateUI(FALSE); //cleaning up the html window  //strip out white space in url int i=0, j=0; while (g_Inet.m_url[i]) { while (g_Inet.m_url[i] == ' ') i++; g_Inet.m_url[j++] = g_Inet.m_url[i++]; } g_Inet.m_url[j]='\0'; if (!lstrlen(g_Inet.m_url)) { MessageBox(g_hDlg, "You haven't enter a URL yet.", "Error", MB_OK); break; }  CharLower(g_Inet.m_url); //change to all lower case if (_tcsstr(g_Inet.m_url, _T("http://")) || _tcsstr(g_Inet.m_url, _T("ftp://")) || _tcsstr(g_Inet.m_url, _T("file://"))) { MessageBox(hwnd, "Don't type method name in the url text box!", g_Inet.m_url, MB_OK); goto CursorBackandBailOut; }  if (g_Inet.m_dwServiceType == SERVICE_TYPE_FILE) { //For file url, change all / to \ in the url i=0; while (g_Inet.m_url[i])  { if (g_Inet.m_url[i] == '/') g_Inet.m_url[i] = '\\'; i++; } lstrcpy(szFullUrl, "file://"); lstrcat(szFullUrl, g_Inet.m_url); } else { //For ftp or http, change all \ to / in the url i=0; while (g_Inet.m_url[i])  { if (g_Inet.m_url[i] == '\\') g_Inet.m_url[i] = '/'; i++; } //If the server requires username and password, we will construct a url like this: //http://username:password@server:port/path. //Since we only use InternetOpenUrl, there is no other way to pass in username and //password.Doesn't apply to FILE url. lstrcpy(szFullUrl, g_Inet.m_dwServiceType == SERVICE_TYPE_FTP? "ftp://":"http://"); if (lstrlen(g_Inet.m_username) && lstrlen(g_Inet.m_password)) { lstrcat(szFullUrl,g_Inet.m_username);  lstrcat(szFullUrl, ":"); lstrcat(szFullUrl,(LPCTSTR)g_Inet.m_password);  lstrcat(szFullUrl, "@"); } lstrcat(szFullUrl,(LPCTSTR)g_Inet.m_url);  }   //if m_bRedrawTree is FALSE, which means user has clicked a treecontrol item, //we won't redraw the whole tree. We will simply add sub-item to the currnet  //selected item. Also if the service HTTP, we don't change tree control at all. if ((g_Inet.m_bRedrawTree && g_Inet.m_dwServiceType != SERVICE_TYPE_HTTP) || g_Inet.m_dwServiceType == SERVICE_TYPE_HTTP) { TreeView_DeleteAllItems( g_Inet.hTreeViewCtrl); TV_INSERTSTRUCT tvstruct; tvstruct.hParent = NULL; tvstruct.hInsertAfter = TVI_FIRST; tvstruct.item.iImage = 0; tvstruct.item.iSelectedImage = 0; tvstruct.item.pszText = g_Inet.m_url; tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; g_Inet.m_curItem = (HTREEITEM)SendMessage(g_Inet.hTreeViewCtrl, TVM_INSERTITEM,0, (LPARAM)(LPTV_INSERTSTRUCT)&tvstruct); } g_Inet.m_bRedrawTree = TRUE;   HINTERNET hInternetSession; hInternetSession = InternetOpen(_T("InetAll"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternetSession) { MessageBox(hwnd, "InternetOpen Fails", "Error", MB_OK); goto CursorBackandBailOut; } switch (g_Inet.m_dwServiceType) { case SERVICE_TYPE_HTTP: HINTERNET hInternetFile; //We just download html and text. Modify if needs to download binary file. hInternetFile = InternetOpenUrl(hInternetSession, szFullUrl, NULL, 0, INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0); if (!hInternetFile) { MessageBox(hwnd, "InternetOpenUrl failed! Check URL or connection", szFullUrl, MB_OK); goto CursorBackandBailOut; } DWORD dwRead; TCHAR szTemp[1024]; int nTimes; nTimes=1; while (InternetReadFile(hInternetFile, (LPVOID)szTemp, 1023, &dwRead)) { if (!dwRead) break; szTemp[dwRead]='\0'; //Enlarge buffer only on a need base if (++nTimes * 1024>(int)g_Inet.m_dwSizeHtml) { LPVOID pTemp = MyAllocMem(g_Inet.m_dwSizeHtml + 1024); if (!pTemp) { MessageBox(hwnd, "Mem alloc fails", "Error", MB_OK); InternetCloseHandle(hInternetFile); g_Inet.m_phtml[0] = '\0'; goto CursorBackandBailOut; } CopyMemory (pTemp, g_Inet.m_phtml, g_Inet.m_dwSizeHtml); g_Inet.m_dwSizeHtml += 1024;  MyFreeMem(g_Inet.m_phtml); g_Inet.m_phtml = (LPTSTR)pTemp; } lstrcat(g_Inet.m_phtml, szTemp); } SetWindowText(g_Inet.hwndHTML, g_Inet.m_phtml); InternetCloseHandle(hInternetFile); break;  case SERVICE_TYPE_FILE: case SERVICE_TYPE_FTP: //FillFtpOrFileObjArray enumerates and FTP or FILE url, and populates //g_Inet.m_itemArray. if (!FillFtpOrFileObjArray(hInternetSession, szFullUrl)) break; //FillTreeControl draws the treeview control using g_Inet.m_itemArray  FillTreeControl(); break; }  CursorBackandBailOut: InternetCloseHandle(hInternetSession); UpdateUI(FALSE); ShowCursor(FALSE); SetCursor(hCursor); break; //break for switch id }   }   BOOL CALLBACK Dlg_Proc (HWND hDlg, UINT uMsg,     WPARAM wParam, LPARAM lParam) {        BOOL fProcessed = TRUE;    switch (uMsg) {       HANDLE_MSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);       HANDLE_MSG(hDlg, WM_DESTROY, Dlg_OnDestroy);       HANDLE_MSG(hDlg, WM_COMMAND, Dlg_OnCommand);    //No message crackers defined in windowsx.h for WM_NOTIFY, so we just handled   //it directly.   //We only process WM_NOTIFY when TreeView items are double clicked.   case WM_NOTIFY: int idCtrl; idCtrl  = (int) wParam; LPNMHDR pnmh; pnmh =  (LPNMHDR) lParam;    if (idCtrl == IDC_TREE1 && pnmh->code == NM_DBLCLK) { g_Inet.m_curItem = TreeView_GetSelection(g_Inet.hTreeViewCtrl);  //if it's already root, we don't need to enumerate again. if (! TreeView_GetParent(g_Inet.hTreeViewCtrl, g_Inet.m_curItem)) return fProcessed; TV_ITEM tvItem; tvItem.mask =TVIF_TEXT;  tvItem.hItem = g_Inet.m_curItem; tvItem.pszText = g_Inet.m_url; TreeView_GetItem(g_Inet.hTreeViewCtrl, &tvItem);  //change UI to have new m_url UpdateUI(FALSE);  //if the URL ends with a / or \, it's a directory, we call Dlg_OnCommand directly to //construct new m_itemArray. FillFtpOrFileObjArray //and FillTreeControl will be called by Dlg_OnCommand. TCHAR cRight; cRight = g_Inet.m_url[lstrlen(g_Inet.m_url)-1]; if (cRight =='/' ||cRight =='\\') { g_Inet.m_bRedrawTree = FALSE; Dlg_OnCommand (g_hDlg, IDC_GETDATA, GetDlgItem(g_hDlg, IDC_GETDATA),0); } else { //if it's a file, we are downloading it. if (g_Inet.m_dwServiceType == SERVICE_TYPE_FTP) { HINTERNET hInternetFile, hInternetSession; hInternetSession = InternetOpen(_T("InetAll"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternetSession) { MessageBox(g_hDlg, "InternetOpen Fails", "Error", MB_OK); return fProcessed; }  UpdateUI(TRUE); lstrcpy(szFullUrl, g_Inet.m_dwServiceType == SERVICE_TYPE_FTP? "ftp://":"http://"); if (lstrlen(g_Inet.m_username) && lstrlen(g_Inet.m_password)) { lstrcat(szFullUrl,g_Inet.m_username);  lstrcat(szFullUrl, ":"); lstrcat(szFullUrl,(LPCTSTR)g_Inet.m_password);  lstrcat(szFullUrl, "@"); } lstrcat(szFullUrl,(LPCTSTR)g_Inet.m_url);  DeleteFile("c:\\deleteme"); HANDLE f; DWORD dwRead; //download the file to c:\deleteme f= CreateFile("c:\\deleteme", GENERIC_WRITE,  0, NULL,  CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);   if (f==  INVALID_HANDLE_VALUE)  { MessageBox (hDlg, "Can't open c:\\deleteme to write! Enough free space on C:???", szFullUrl, MB_OK); return fProcessed; }  hInternetFile = InternetOpenUrl(hInternetSession,(LPCTSTR)szFullUrl, NULL, 0,  INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0); if (!hInternetFile) { CloseHandle(f); return fProcessed; } TCHAR szTemp[1024]; while (InternetReadFile(hInternetFile, (LPVOID)szTemp, 1024, &dwRead)) { if (!dwRead) break; DWORD dwWritten; WriteFile(f, (LPVOID)szTemp, dwRead, &dwWritten, NULL); } CloseHandle(f); InternetCloseHandle(hInternetFile); InternetCloseHandle(hInternetSession); MessageBox(g_hDlg, "The url is downloaded in c:\\deleteme!", szFullUrl, MB_OK);  }//////////// else { ///file type url DeleteFile("c:\\deleteme"); if (CopyFile( g_Inet.m_url,// pointer to name of an existing file  "c:\\deleteme",// pointer to filename to copy to  FALSE // flag for operation if file exists  ))  MessageBox(g_hDlg, "The url is downloaded in c:\\deleteme!", g_Inet.m_url, MB_OK); else  { MessageBox(g_hDlg, "CopyFile failed!", g_Inet.m_url, MB_OK); } } } //Double click will actually collapse a tree. To expand it in double click event //we will simply post a TVM_EXPAND message to the treeview control. PostMessage(g_Inet.hTreeViewCtrl, TVM_EXPAND, (WPARAM) (UINT) TVE_EXPAND, (LPARAM) g_Inet.m_curItem);  } break;        default:          fProcessed = FALSE;          break;    }     return(fProcessed); }   //Update UI or Collect input from UI //bDirection FALSE g_Inet to UI //bDirection TRUE UI to g_Inet  BOOL UpdateUI(BOOL bDirection) { BOOL bRet = FALSE; if (bDirection) //Get UI Input to g_Inet { if (BST_CHECKED ==IsDlgButtonChecked(g_hDlg, IDC_CERN)) g_Inet.m_cern = TRUE; else g_Inet.m_cern =  FALSE;  if (BST_CHECKED ==IsDlgButtonChecked(g_hDlg, IDC_HTTP))  g_Inet.m_dwServiceType == SERVICE_TYPE_HTTP; if (BST_CHECKED ==IsDlgButtonChecked(g_hDlg, IDC_FTP))  g_Inet.m_dwServiceType == SERVICE_TYPE_FTP; if (BST_CHECKED ==IsDlgButtonChecked(g_hDlg, IDC_FILE))  g_Inet.m_dwServiceType == SERVICE_TYPE_FILE;  bRet = GetDlgItemText(g_hDlg, IDC_URL, g_Inet.m_url, MAX_STRING_SIZE)   && GetDlgItemText(g_hDlg, IDC_USERNAME, g_Inet.m_username, MAX_STRING_SIZE)   && GetDlgItemText(g_hDlg, IDC_PASSWORD, g_Inet.m_password, MAX_STRING_SIZE); } else //Update UI from g_Inet {  int nService;  if (g_Inet.m_dwServiceType == SERVICE_TYPE_HTTP) nService = IDC_HTTP; else if (g_Inet.m_dwServiceType == SERVICE_TYPE_FTP) nService = IDC_FTP; else nService = IDC_FILE; bRet = CheckRadioButton(g_hDlg, IDC_HTTP, IDC_FILE, nService) && SetWindowText(g_Inet.hwndUrl, g_Inet.m_url)     && SetWindowText(g_Inet.hwndPassword, g_Inet.m_password) && SetWindowText(g_Inet.hwndUsername, g_Inet.m_username);; bRet  = bRet && SetWindowText(g_Inet.hwndHTML, g_Inet.m_phtml);  SendMessage(g_Inet.hCheckBoxCern, BM_SETCHECK, g_Inet.m_cern, 0); } return bRet; }  //Enumerate strURL, and populate g_Inet.m_itemArray BOOL FillFtpOrFileObjArray(HINTERNET hInternetSession, LPTSTR strURL) { BOOL bRet = FALSE; if (!hInternetSession) return bRet;  if (g_Inet.m_dwServiceType == SERVICE_TYPE_HTTP) { MessageBox(g_hDlg, "only ftp and file url needs enumeration!", "Error", MB_OK); return bRet; }  ItemAttrib tempObj; g_Inet.m_itemArray.RemoveAll();  if (g_Inet.m_dwServiceType == SERVICE_TYPE_FTP) //////// start_if_ftp { //CERN or NO CERN we will download HTML anyway. HINTERNET hInternetFile; hInternetFile = InternetOpenUrl(hInternetSession, szFullUrl, NULL, 0, INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0); DWORD dwRead; TCHAR szTemp[1024]; int nTimes; nTimes=1; while (InternetReadFile(hInternetFile, (LPVOID)szTemp, 1023, &dwRead)) { if (!dwRead) break; szTemp[dwRead]='\0'; if (++nTimes * 1024>(int)g_Inet.m_dwSizeHtml) { LPVOID pTemp = MyAllocMem(g_Inet.m_dwSizeHtml + 1024); if (!pTemp) { MessageBox(g_hDlg, "Mem alloc fails", "Error", MB_OK); InternetCloseHandle(hInternetFile); g_Inet.m_phtml[0] = '\0'; break; } CopyMemory (pTemp, g_Inet.m_phtml, g_Inet.m_dwSizeHtml); g_Inet.m_dwSizeHtml += 1024;  MyFreeMem(g_Inet.m_phtml); g_Inet.m_phtml = (LPTSTR)pTemp; } lstrcat(g_Inet.m_phtml, szTemp); } SetWindowText(g_Inet.hwndHTML, g_Inet.m_phtml); InternetCloseHandle(hInternetFile);  //If direct access to FTP server, we will use  //InternetOpenUrl(INTERNET_FLAG_RAW_DATA) and InternetFindNextFile //to enumerate the sub directories and files if (!g_Inet.m_cern)  //start_if_no_cern { WIN32_FIND_DATA wfd;  HINTERNET hInternetFind = InternetOpenUrl(hInternetSession,(LPCTSTR)strURL, NULL, 0,  INTERNET_FLAG_RAW_DATA| INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0); if (!InternetFindNextFile (hInternetFind, &wfd))  { bRet = FALSE; //Actually this may or may not be a failure. MessageBox(g_hDlg, "No files or sub-directories under this url directory", strURL, MB_OK); return bRet; } do { LPCTSTR strFileName; if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { strFileName = (LPCTSTR) &wfd.cFileName; if (strFileName[0] == '.') continue; lstrcpy(tempObj.szObjectPath, g_Inet.m_url); if (strURL[lstrlen(strURL)-1] != '/') lstrcat(tempObj.szObjectPath, "/"); lstrcat (tempObj.szObjectPath, strFileName); if (tempObj.szObjectPath[lstrlen(tempObj.szObjectPath)-1] != '/' ) lstrcat(tempObj.szObjectPath, "/"); tempObj.nObjectType = 1; g_Inet.m_itemArray.Add(tempObj); } else { strFileName = (LPCTSTR) &wfd.cFileName; lstrcpy(tempObj.szObjectPath , g_Inet.m_url); if (strURL[lstrlen(strURL)-1] != '/') lstrcat(tempObj.szObjectPath, "/"); lstrcat(tempObj.szObjectPath, strFileName); tempObj.nObjectType = 0; g_Inet.m_itemArray.Add(tempObj); } } while (InternetFindNextFile (hInternetFind, &wfd)); InternetCloseHandle (hInternetFind); }  //end_if_no_cern else { //start_if_cern  LPTSTR strTemp; TCHAR strTempUrl[MAX_STRING_SIZE]; strTemp = g_Inet.m_phtml; //we have the html file listings in the strTemp, we just need to parse it  //a sample html is provided at the bottom of this file. Note that the parsing //code may not work with proxies other than MS Proxy server. while (TRUE) { int nPos; TCHAR strLeft[] = "<A HREF="; TCHAR strRight[] = ">";  nPos = _tcsstr(strTemp, strLeft) - strTemp; if (nPos < 0) break; strTemp = strTemp + nPos +lstrlen(strLeft)+1; nPos = _tcsstr(strTemp, strRight) - strTemp; for (int i=0; i<nPos-1; i++) strTempUrl[i]=strTemp[i]; strTempUrl[nPos-1] = '\0'; strTemp =  strTemp +i +lstrlen(strRight); if (strTempUrl[0] == '.') continue;  if (g_Inet.m_url[lstrlen(g_Inet.m_url)-1] != '/') { g_Inet.m_url[lstrlen(g_Inet.m_url)] ='/'; g_Inet.m_url[lstrlen(g_Inet.m_url)+1] ='\0'; }  TCHAR strServerName[256]; i=0; while (TRUE) { strServerName[i]= g_Inet.m_url[i]; if (g_Inet.m_url[i] == '/') { strServerName[i] = '\0'; break; } i++; } lstrcpy(tempObj.szObjectPath, strServerName); lstrcat(tempObj.szObjectPath, strTempUrl); if (strTempUrl[lstrlen(strTempUrl)-1] == '/' ) tempObj.nObjectType = 1; else tempObj.nObjectType = 0; g_Inet.m_itemArray.Add(tempObj); } if (!g_Inet.m_itemArray.GetSize()){ MessageBox(g_hDlg, "No files or sub-directories under the url", g_Inet.m_url, MB_OK); return bRet; } }//end_if_cern }////end_if_ftp else  {  //start_if_file TCHAR strFileSpec[MAX_STRING_SIZE];   lstrcpy(strFileSpec, g_Inet.m_url);  //trying to determine if it's a single machine name to enumerate, or //it's already a unc name. LPTSTR szTempRight;  //in case user type in \\machine name in url text box, szTempRight = strFileSpec+2; int i=0; BOOL bServerNameOnly; bServerNameOnly= TRUE; for (i=0; i<lstrlen(szTempRight)-1; i++) { if (szTempRight[i] == '\\') { bServerNameOnly = FALSE; break; } }  if (bServerNameOnly) {  //user enters a single machine name, we will enumerate the shares. lstrcpy(g_Inet.m_url, "\\\\"); int i=0; while (strFileSpec[i] == '\\') i++; lstrcat(g_Inet.m_url, (LPTSTR)(strFileSpec + i)); if (g_Inet.m_url[lstrlen(g_Inet.m_url)-1] == '\\') g_Inet.m_url[lstrlen(g_Inet.m_url)-1] = '\0'; //now the g_Inet.m_url is "\\server name NETRESOURCE nr; nr.dwScope = RESOURCE_GLOBALNET; nr.dwType = RESOURCETYPE_ANY; nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; nr.dwUsage = RESOURCEUSAGE_CONTAINER; nr.lpLocalName = NULL; nr.lpRemoteName = g_Inet.m_url; nr.lpComment = NULL; nr.lpProvider = NULL; LPVOID pMem =  HeapAlloc(GetProcessHeap(),      HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, 16384); if (!pMem) { MessageBox(g_hDlg, "Not enough memory to allocate for WNetEnumResource",g_Inet.m_url, MB_OK ); return bRet; } HANDLE hWNetEnum=NULL; DWORD dwStatus = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,  RESOURCEUSAGE_CONNECTABLE, &nr, &hWNetEnum); if (dwStatus != NO_ERROR) { DWORD dwErr = GetLastError(); MessageBox(g_hDlg, "WNetOpenEnum failed", g_Inet.m_url, MB_OK ); HeapFree(GetProcessHeap(), 0, pMem); return bRet; } do { DWORD dwEntries; DWORD dwBuffSize; dwEntries =1; dwBuffSize= 16384; dwStatus = WNetEnumResource(hWNetEnum, &dwEntries, pMem, &dwBuffSize); if (dwStatus == NO_ERROR) { lstrcpy(tempObj.szObjectPath, ((LPNETRESOURCE)pMem)->lpRemoteName); lstrcat(tempObj.szObjectPath, "\\"); tempObj.nObjectType = 1; g_Inet.m_itemArray.Add(tempObj); } } while (dwStatus == NO_ERROR); if (dwStatus != ERROR_NO_MORE_ITEMS) { MessageBox(g_hDlg, "WNetEnumResource failed",g_Inet.m_url, MB_OK); MyFreeMem(pMem); WNetCloseEnum(hWNetEnum); return bRet; } MyFreeMem(pMem); WNetCloseEnum(hWNetEnum); //we are done with enumerating shares on a file server. return bRet = TRUE; }  lstrcpy(strFileSpec, "\\\\"); i=0; while (g_Inet.m_url[i]=='\\') //skip starting \ in m_url { i++; } lstrcat(strFileSpec, g_Inet.m_url+i); //Now strFileSpec is a UNC such as \\server\share\filedirectory\...  WIN32_FIND_DATA fd;  HANDLE hFind = NULL; if ((hFind = FindFirstFile ((LPCTSTR) strFileSpec, &fd)) == INVALID_HANDLE_VALUE) { if (strFileSpec[lstrlen(strFileSpec)-1] != '\\') lstrcat(strFileSpec, "\\"); lstrcpy(g_Inet.m_url, strFileSpec); lstrcat(strFileSpec, "*.*"); if ((hFind = FindFirstFile ((LPCTSTR) strFileSpec, &fd)) == INVALID_HANDLE_VALUE)  { MessageBox(g_hDlg, "No files or sub-directories under the url", g_Inet.m_url, MB_OK); return bRet; } } do { if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {  (LPCTSTR) &fd.cFileName; if ( ((LPCTSTR) &fd.cFileName)[0] == '.') continue; lstrcpy(tempObj.szObjectPath, g_Inet.m_url); lstrcat(tempObj.szObjectPath, (LPCTSTR) &fd.cFileName); lstrcat(tempObj.szObjectPath, "\\"); tempObj.nObjectType = 1; g_Inet.m_itemArray.Add(tempObj); } else { lstrcpy(tempObj.szObjectPath, g_Inet.m_url); lstrcat(tempObj.szObjectPath, (LPCTSTR) &fd.cFileName); tempObj.nObjectType = 0; g_Inet.m_itemArray.Add(tempObj);  } } while (FindNextFile (hFind, &fd)); FindClose (hFind); } //end_if_file bRet = TRUE; //happy here.  return bRet; }  //Draw tree structure of a FTP or FILE URL in  //treeview Ctrl using g_Inet.m_itemArray void FillTreeControl() { TV_INSERTSTRUCT tvstruct; int nItem; nItem = g_Inet.m_itemArray.GetSize(); HTREEITEM hChildItem=NULL, hNextChildItem=NULL; if (!nItem){ TreeView_DeleteAllItems( g_Inet.hTreeViewCtrl); tvstruct.hParent = NULL; tvstruct.hInsertAfter = TVI_FIRST; tvstruct.item.iImage = 0; tvstruct.item.iSelectedImage = 0; tvstruct.item.pszText = _T("Root"); tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; SendMessage(g_Inet.hTreeViewCtrl, TVM_INSERTITEM,0, (LPARAM)(LPTV_INSERTSTRUCT)&tvstruct); return; }  int nBMID;  //Remove all old items under the selected item hChildItem = TreeView_GetChild(g_Inet.hTreeViewCtrl, g_Inet.m_curItem);   while (hChildItem) { hNextChildItem = TreeView_GetNextSibling(g_Inet.hTreeViewCtrl, hChildItem);  TreeView_DeleteItem(g_Inet.hTreeViewCtrl, hChildItem); hChildItem = hNextChildItem; } //add new items for (int i=0; i<nItem; i++) { nBMID = ((g_Inet.m_itemArray.GetAt(i)).nObjectType==0)?2:1; tvstruct.hParent = g_Inet.m_curItem; tvstruct.hInsertAfter = TVI_LAST; tvstruct.item.iImage = nBMID; tvstruct.item.iSelectedImage = nBMID; tvstruct.item.pszText = (g_Inet.m_itemArray.GetAt(i)).szObjectPath; tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; SendMessage(g_Inet.hTreeViewCtrl, TVM_INSERTITEM,0, (LPARAM)(LPTV_INSERTSTRUCT)&tvstruct); } //Make sure the tree under the selected item is expanded. if (g_Inet.m_curItem)  { TreeView_EnsureVisible(g_Inet.hTreeViewCtrl, g_Inet.m_curItem); TreeView_Expand(g_Inet.hTreeViewCtrl, g_Inet.m_curItem, TVE_EXPAND); } }  //A typical HTML wrapper for file listing a in ftp url from MS Proxy Server //which is CERN-compatible proxy. /* <HTML> <HEAD> <TITLE>FTP root at ftp.microsoft.com</TITLE> </HEAD> <BODY> <H1>FTP root at ftp.microsoft.com</H1> <HR> <H4><PRE> This is FTP.MICROSOFT.COM.  Please see the  dirmap.txt file for more information. 

</PRE></H4> <HR> <PRE> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/access/">access</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/dosword/">dosword</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/excel/">excel</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/games/">games</A> 10/08/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/GEN_INFO/">GEN_INFO</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/homeapps/">homeapps</A> 03/12/97 10:23PM          &lt;DIR&gt; <A HREF="/deskapps/kids/">kids</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/miscapps/">miscapps</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/mmapps/">mmapps</A> 08/28/96 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/MONEY/">MONEY</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/office/">office</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/powerpt/">powerpt</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/project/">project</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/publishr/">publishr</A> 08/30/94 12:00AM          1,791 <A HREF="/deskapps/readme.txt">readme.txt</A> 08/24/94 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/word/">word</A> 08/28/96 12:00AM          &lt;DIR&gt; <A HREF="/deskapps/WORKS/">WORKS</A> </PRE> <HR> </BODY> </HTML> */  /////////////////////// End Of File //////////////////////// 



#include "stdafx.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
	HINTERNET hOpen, hConnect, hReq;
	hOpen = InternetOpen("SimpleGet", INTERNET_OPEN_TYPE_PRECONFIG, NULL, 0, 0);
	if(!hOpen)
	{
		cout << "hopen " << GetLastError() << endl;
		return 0;
	}
	// try the following in InternetConnect to see the problem. 
	hConnect = InternetConnect(hOpen, "www.microsoft.com/learning/", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
	if(!hConnect)
	{
		cout << "hconnect " << GetLastError() << endl;
		return 0;
	}
	hReq = HttpOpenRequest(hConnect, "GET", "", "HTTP/1.1", NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0);
	if(!hReq)
	{
		cout << "hreq " << GetLastError() << endl;
		return 0;
	}
	if(HttpSendRequest(hReq, NULL, 0, NULL, 0))
	{
		DWORD dwSize = 0;
		char Data[1024] = "\0";
		DWORD dwCode, dwCodeSize;
		dwCodeSize = sizeof(DWORD);
		if(!HttpQueryInfo(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwCodeSize, NULL))
		{
			cout << "queryinfo " << GetLastError() << endl;
			return 0;
		}
		else
		{
			cout << "Status Code: " << dwCode << endl;
		}
		do
		{
			InternetReadFile(hReq, (LPVOID)Data, 1023, &dwSize);
			if(0!=dwSize)
			{
				Data[dwSize]='\0';
				cout << Data;
			}
			ZeroMemory(Data, 1024);
		}while (dwSize !=0);
	}
	else
	{
		cout << "SendRequest error " << GetLastError() << endl;
	}
	return 0;
}
 
Apache/PHP fag reporting in.

LOL :eek:

Does the above suggestion sound reasonable to you ? You are probably more aware of Erix920's requirements than I am :(

I am using a similar method currently to Check and Update the YASAMM executable (using HTTP). Plus I use HTTPS to get "Library Booking" information, game updates etc for when members borrow accounts.

Apache/PHP and MySQL work together so easily - much easer than trying to write a C++ server with MySQL + Connectors etc

cheers
AnOldBloke

Here is a "partial snippet" of the Apache based PHP I use to Update the YASAMM - using Port 80

Code:
<?php
//	************************************************************************
//	**
//	**	../an_update.php
//	**
//	**	Module by <snip>
//	**	http://www.YASAMM.com
//	**
//	************************************************************************
//
//		CVS - Tracking
//
//	MODULE     : $RCSfile: an_update.php,v $
//
//	CREATED    : $Author: CVSUser3 $
//
//	REVISION   : $Revision: 1.1 $, $Date: 2009/12/03 00:45:20 $
//	EDITEDBY   : $Author: CVSUser3 $
//
//
//	-------------------------------------------------------------
//
//	Version: $Log: update.php,v $
...
//	Version: Revision 1.1  2009/10/30 05:34:37  CVSUse3r
//	Version: Remove Upload.
//	Version: Add Remote Control.
//
//	------------------------------------------------------------

	include( "debug.php" );
	ProcessDebug( '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~', __FILE__, __LINE__ );
	//HTML_Debug();
	
	define( 'MY_RESOURCE',	'ABCDEFG_EXE' );
	
	$version_latest	= '1.0.3.4';
	$file_name		= "YASAMM.exe";
	$resource_id	= md5( MY_RESOURCE );
	
	include( "mydbfn_updates.php" );

define( '_DEBUG_ENABLED',				0 );
define( '_DEBUG_ENABLED_2',				2 );

//define( 'CURRENT_VERSION',				'1.0.1.5' );
define( 'UL_MAX_CHUNK',				4096 );		// UL max block size
define	( 'UL_CMD_UPDATECLIENT',		1 );		// Update Client

//
//	Plain text
//
	//	Responses are echoes of Commands
	define( '_REQUEST',					'Request' );		// 'command=' =>
	define( '_RESPONSE',				'Response' );		// <= 'Response='
	
	//	Request and Response - Version Info
	define( '_GET_LATEST_VERSION_INFO',		'VersionInfo' );
	define( '_RESOURCE_ID',					'ResourceId' );			
		define( '_STATUS',					'status' );			// => &status=..
		define( '_VERSION',					'version' );		// => &version=..
		define( '_UL_CHUNK_SIZE',			'chunk_size' );		// => &block_size
		define( '_UL_FILE_SIZE',			'file_size' );		// file_size
		define( '_UL_FILE_NAME',			'file_name' );		// file_name
		define( '_UL_FILE_MD5',				'file_md5' );		// file_md5
		
	//	Request and Response - Version Info
	define( '_GET_DATA_BLOCK',				'DataBlock' );
&version=..
		define( '_UL_BLOCK_NUMBER',			'block_number' );	// => &block_number=..,..,..
		define( '_UL_BLOCK_SIZE',			'block_size' );		// => &block_size
		define( '_UL_FILE_DATA',			'file_data' );		// file_data
	
	
	//	-----------------------------------------
	//	G L O B A L   D A T A
	//	-----------------------------------------

	//	-----------------------------------------
	
	ProcessDebug( 'Incoming connection', __FILE__, __LINE__ );
	
	//	Check User Agent, HTTPS and REQUEST_ METHOD
	$user_agent		= ( isset( $_SERVER['HTTP_USER_AGENT'] )) ? $_SERVER['HTTP_USER_AGENT']: false;
	$https			= ( isset( $_SERVER['HTTPS'] )) ? $_SERVER['HTTPS'] : false;
	$request_method	= ( isset( $_SERVER['REQUEST_METHOD'] )) ? $_SERVER['REQUEST_METHOD'] : false;
	$remote_address	= ( isset( $_SERVER['REMOTE_ADDR'] )) ? $_SERVER['REMOTE_ADDR'] : false;
	$remote_port	= ( isset( $_SERVER['REMOTE_PORT'] )) ? $_SERVER['REMOTE_PORT'] : false;
	
	//	----------------
	//	Check user agent
	//	----------------
	if	(($user_agent != "ThisIsObfuscated") OR ($request_method != 'POST')) {
		ProcessDebug( 'user agent: '.$user_agent, __FILE__, __LINE__ );
		ProcessDebug( 'Ip Address: '.$remote_address.':'.$remote_port, __FILE__, __LINE__ );
		ProcessDebug( '     https: '. (!$https ? 'Not https' : $https), __FILE__, __LINE__ );
		ProcessDebug( 'Req Method: '. (!$request_method ? 'unknown' : $request_method), __FILE__, __LINE__ );

		SendError403( "User_Agent, Request_Method or https" );	// and die
	}

	
	//	--------------------------------
	//	Read the rest of the server info
	//	--------------------------------
	$request_time	= ( isset( $_SERVER['REQUEST_TIME'] )) ? $_SERVER['REQUEST_TIME'] : false;
	$query_string	= ( isset( $_SERVER['QUERY_STRING'] )) ? $_SERVER['QUERY_STRING'] : false;
	$accept			= ( isset( $_SERVER['HTTP_ACCEPT'] )) ? $_SERVER['HTTP_ACCEPT'] : false;
	$accept_charset	= ( isset( $_SERVER['HTTP_ACCEPT_CHARSET'] )) ? $_SERVER['HTTP_ACCEPT_CHARSET'] : false;
	$accept_encoding= ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : false;
	$accept_language= ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] )) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : false;
	$referer		= ( isset( $_SERVER['HTTP_REFERER'] )) ? $_SERVER['HTTP_REFERER'] : false;
	$keep_alive		= ( isset( $_SERVER['HTTP_KEEP_ALIVE'] )) ? $_SERVER['HTTP_KEEP_ALIVE'] : false;
	$connection		= ( isset( $_SERVER['HTTP_CONNECTION'] )) ? $_SERVER['HTTP_CONNECTION'] : false;
	
	//
	//	Start of session
	//
//	session_start();
	
	//	-----------------
	//	Set default state
	//	-----------------
	
	//	--------------
	//	Check Request
	//	--------------	
	$request	= ( isset($_POST[_REQUEST] ) ? $_POST[_REQUEST] : false );
	ProcessDebug( " => Looking for ping ($request)", __FILE__, __LINE__ );
	if	( $request == 'ping' ) {
		ProcessDebug( " => Send 200 OK", __FILE__, __LINE__ );
		header("HTTP/1.1 200 OK");
		die();
	}
	
		ProcessDebug( "--> -----------------------------", __FILE__, __LINE__ );
		ProcessDebug( "-->    dump all POST variables   ", __FILE__, __LINE__ );
		ProcessDebug( "--> -----------------------------", __FILE__, __LINE__ );
		if	( _DEBUG_ENABLED_2 ) {		
			foreach	($_POST as $key => $value ) {
				ProcessDebug( "  $key => $value", __FILE__, __LINE__ );
			}
		}
	
	switch	( $request )
	{
		case	_GET_LATEST_VERSION_INFO:
			get_version_info();
			break;
		case	_GET_DATA_BLOCK:
			get_data_block();
			break;
		default:
			ProcessGetVersionInfo();
			SendError401();
	}
 
Great idea and concept code, but for static files like the updates you don't want to use Apache to server them as it's a hog. Nginx is a lot better and faster at that.
 
How are you thinking the GCFs will be downloaded from Steam and updated from Steam when you are talking about just php and apache?

I asked Echo's opinion as the idea didn't make sense to me and he said it could be used for authentication? That could be a good idea, for instance verifying a hardware id of a client. Then there could be an administrative section of the site where relevant information about the account can be added such as the owner's name, hwid etc.

But I'm not sure your idea for downloading and updating of files. The application must be able to download and update the files by using the rain API. This I don't think can be done with php so that leaves cpp and vb. We would have to use two different protocols in this case. One for auth (http) and one for file transfers between client and server (tcp).

By having all clients downloads from your server and NOT receive the account information, you can ensure the accounts will not be disabled or stolen. Of course the pitfall of this approach is that the clients won't be able to play online. Having people share accounts for online games is dumb anyway because the ticket constantly expires and will only allow for one person to be connected at a time.
 
Hi Erix920,

As I see it we have 2 x parts to the equation:-

First Part
1. FS has a server that has all the GCFs, updates etc on it - correct ?
2. If this is so, I was suggesting Apache/PHP combination on that server (Echo419 suggested that the server could be ngix - which I know zilch about) to "serve up" the files/data as required.

Second Part
3. You have "clients" (who I assume usually run Windoze boxes) who need to download the GCFs, updates etc from the above mentioned FS server - is this correct ?
4. I was suggesting that you write a VB application that accesses the FS server via TCP/IP using many of the available API's that Windoze supplies. I also assume that VB can call the "Rain" API.

I was suggesting that to do the above would be reasonably easy and quick to implement on the Server and I assume for you using VB.

BTW: "FS" => a Free Steam associated server.


cheers
 
The second part is fine it's the first part that is still fuzzy.

Where are you planning the GCFs are coming from? Maybe more explanation is needed.

There must be an application somewhere on the server whether it's FS's server or somewhere else, there just needs to be one. This server will provide a channel in which clients can download FULL GCFs, the client should be able to send an .archive file to the server (in case the client needs an update), the server should be able to transfer the .update files back to the client in the same way it transfers full GCFs.

I mean I guess you could have it so when the client passes the auth and request a file download (FULL GCF not and update) it will be able to download via a url. But in the case that an update is needed, we will have to use the APIs from cftoolbox. This means that there must be another application running on the server, since php can't use dlls, to do all the hard work.

Hopefully that is more clear.
 
Hi Erix920,

I have a few questions that I need to ask in regards to this - as we seem to be missing each other's point!

Does FS have a central server where all the GCF's etc are available for download or is that what you trying to organise - this central FS server ?

Does the "Rain" software need to run on the server that maintains the GCF data ?

Edit: On Windoze boxes - I believe that PHP can access DLLs - although I haven't actually done this myself.

cheers
OldFart

P.S. My Secure comms is almost complete :rolleyes:
 
No, FS does not have a central server, this is what we need to create for GCF updating / downloading. This would be the central repo for all files that the clients will download. And yes, the application that uses the rain API must be on the same server as the GCFs as it must have direct access to the files (retrieving information about them, completeness, version, appid etc).
 
No, FS does not have a central server, this is what we need to create for GCF updating / downloading. This would be the central repo for all files that the clients will download. And yes, the application that uses the rain API must be on the same server as the GCFs as it must have direct access to the files (retrieving information about them, completeness, version, appid etc).

Hi Erix920,

Do you have access to the "Rain" source or can you tell me what platforms it is able to be run on please.

Additionally, do you have a say in the choice of OS for any future FS GCF server?

If you choose windows (Win2K3) as the server OS, then you could use IIS :rolleyes: with that - I am sure you can code the "page server" parts directly using VB.NET or C#.NET and access the Rain API as well (if it's a Windoze DLL). Its about 3 x years since I did any .NET coding so my memory is a bit shakey!

cheers
OldFart
 
Yes the dll is for windows, I only have the source code that I posted in this thread along with the header and lib file. FS's server is linux which is why I was looking for a Linux solution. Asp.net could work as easily as just pulling up a download page (after being authed) and be able to download files from a list. The files would of course come from the accounts that have been loaded. This is what I wanted to do a little while ago since it be very easy to create an update. All you would need to do is upload your .archive file, the server will process it and then send the client the .update file.

This above method using asp.net seems much easier than creating a client server model for tcp file transfers. We could always have the windows master server upload to Linux FTP servers however.
 
Hi Erix920,

I'm taking a break from YASAMM atm - because I finally got the Encrypted Peer-Peer comms working (I plagiarized the Encryption parts from an interesting project at CodeProject and spent days modifying it to fit my requirements).

Some of the original "inventors" of Crypto protocols and algorithms could sure think "outside of the box" (Applied Cryptography, 2nd Edition by Bruce Schneier - my night-time reading for the last 10 x days) one can't help but admire them. :D

Now back to this project - a couple of points ..

1. Should we start a new thread where you can copy the relevant posts to, so it's all in just 1 x spot please ?
2. Can we ask for any *NIX C/C++ gurus to "front and centre" for their opinions and possible help.
3. Can we start getting your ideas on what is required "down on paper", to use as a skeleton that we can flesh out
4. How can I come quickly up-to-date on how Steam organises it's content and updates (please excuse my lack of knowledge :eek:).

I may read back through your posts and try and reassess the info you have so far supplied. From there I may be able to post what I think you are after and you can correct my mistakes.

My time zone is GMT +10 so we are probably on the other side of the world from each other.

Our clan runs a couple of TS2 servers - maybe we could chat on there ?

cheers
OldFart
 
Yes, I will start a new thread and slowly begin to add as much knowledge as I know about the Steam protocol and it's methods for things such as downloading and updating gcfs and ncfs. And yes, we are on opposite sides of the world I am gmt -5 so were going to have to post as much as possible in these post. I'll start on the new thread later in the day.
 
We may be able to find an alternative to directly hosting files on our servers.
 
Hi all,

I'm not as fast as Erix920 but I'm slowly getting there ...

cheers
OldFart


ToDo List before Beta Release

Code:
-----------------------------------
Sun 24/01/2010	- 03:30PM AUS EDST

[ ]	Minimum to release Beta
	[X]	Reject unknown remote login
		[X]	Send remote fail message
	[X]	Transaction to indicate successful login
		[X]	Enable Tx Button
		[X]	Enable Loan Botton
	[ ]	Validate all Rx packets
	[ ]	Ban Ip/User
	[ ]	Maintain Ip Dbase
	[ ]	Maintain "Friends" Dbase
	[ ]	Dynamic "add friend"
	[ ]	Launch Steam Account
		[X]	Define encrypted message type
		[ ]	Validate Steam.dll
		[X]	Lender Game selection (appid)
			[X]	Game selection sort by Game id then account
			[X]	Create selection Dialog
			[X]	Implement Selection
			[X]	Allow override of PassPhrase
		[ ]	Transfer Launch Username/password
			[X]	Local to send Launch command
			[X]	Remote to accept Launch
			[X]	Add crypto to PeerConnection
			[X]	Lender encrypt username/password/app_id using PassPhrase
			[X]	Borrower decrypt using PassPhrase
			[ ]	Borrower Launch game
			[ ]	Launch fails - local Local notification
			[ ]	Launch fails - local Remote notification
				[ ]	Connection open
				[ ]	Connection Closed
		[ ]	Track Game in progress
 
Hi all,

Here are some more dialogs etc for those who may be interested

Start of the Configuration Property Sheet
vnetcafe133.jpg


New/improved "friends" mutual identification Dialog
vnetcafe130.jpg


A resizeable chat Window - with some diagnostics
All chat is encrypted using the Public and Private keys. The launch game information is encrypted with a "supposedly" mutual key.
vnetcafe131.jpg


Game Selection Window after pressing the "Lend Game" button
vnetcafe132.jpg


All tested - I ain't MicroSloth ;)

But I would appreciate anyone with "Graphics talent" assisting in dialog layouts etc.


cheers
OldFart
As a Windoze programmer I'm good at embedded :D
 
I'm Good with Photoshop... what would you want?

BTW, Your program is looking Good!
A Question, are you planning on adding a skin to it? I don't like skin's on programs, or maybe it's because some of the progz I have that have skins run like shit because of them. But That's Just My Opinion.

Great Work!!
 
Hi DG,

Thanks for your supportive comments!

I'm an Analyst/programmer - I'm not sure I even know what a "skin" is - all I know is when it comes to making things look good .. well .. I'm an Analyst/Programmer! ;)

OK- back on topic

1. I make the dialogs (and there seems too many :roll: ) that are probably ugly and the wording probably sucks as well - but the functionality is there.
2. I steal graphics from the Internet for my ToolBar and I have to use "ToolTips" so people know their meaning!
3. I use the standard Interface that came with VS 6 (not even Xp or Vista) which is flat by today's standards
4. l always test my code thoroughly and usually document it as well ..

I need advice from a person/people who know how to make things easy to understand - I am good at making things happen - I'm more of an artificer than an innovator!

This YASAMM, is 1 x idea that appealed to me but - thankfully - at my age I know my limitations and am happy to ask for assistance in areas that I'm deficient in!

So, shortly when I do the Beta (i.e. everything that I'm looking at is working as expected) I will welcome ideas and support that make the project easy to use and nice to look at! So don't go away - I should have most of this working shortly and I'd like your input!

The whole product probably needs a reassessment as most of my time has been spent discovering methods to achieve the aims/goals that I'm seeking!

I'll PM you my home email - thanks!

cheers
OldFart
 
Hi guys,

I'm not trying to steal Erix920's thunder ;)

But I finally managed to launch L4D2 on my dev machine from my test web server yesterday.

It was via Steam's gui and command line. To kick it off through the DLL will be the next step - because I will need then to be able to monitor the game state etc (so I can nicely unload the DLL)!

The gui way lets me test that all communications/handshaking/encryption/decryption/notifications etc. I wanted to make sure they are working before starting on the DLL Launch method.

Slow progress but getting there.

Is any of this making sense ?

Questions on why I am doing something will help me "sort out in my head" why I'm doing something in a certain way.

Q1. Like why ban IPs?
Q2. Why enable/disable the Listen server?
Q3. Why encrypt the Steam Account Username/Password on an already encrypted link?

Also, has anyone seen any examples of Peer-Peer when both sides are using a Firewall. How do they do it? Do the need an intermediate server?

I thought I read somewhere about doing this? Any ideas?

Also, who is best to hold the source for this project - so you know it doesn't contain viruses or phishing code etc.

cheers
OldFart

P.S: My ToDo list

Code:
[ ]	Minimum to release Beta
	[X]	Reject unknown remote login
		[X]	Send remote fail message
	[X]	Transaction to indicate successful login
		[X]	Enable Tx Button
		[X]	Enable Loan Botton
	[ ]	Validate all Rx packets
	[ ]	Ban Ip/User
		[ ]	Are you sure ?
		[ ]	Update friend dbase
		[ ]	Update banned IP dbase
	[ ]	Maintain Ip Dbase
	[ ]	Maintain "Friends" Dbase
	[ ]	Dynamic "add friend"
		[X]	Move button position
		[ ]	Hide button
		[ ]	Enable button on "new" login
		[ ]	On activation
			[ ]	Save and update friend dbase
	[ ]	Launch Steam Account
		[X]	Define encrypted message type
		[ ]	Validate Steam.dll
		[X]	Lender Game selection (appid)
			[X]	Game selection sort by Game id then account
			[X]	Create selection Dialog
			[X]	Implement Selection
			[X]	Allow override of PassPhrase
		[X]	Transfer Launch Username/password
			[X]	Local to send Launch command
			[X]	Remote to accept Launch
			[X]	Add crypto to PeerConnection
			[X]	Lender encrypt username/password/app_id using PassPhrase
			[X]	Borrower decrypt using PassPhrase
		[ ] Launch Game
			[ ]	Borrower launch game via DLL API
			[X]	Borrower Launch game (via gui)
				[X]	Notify root
					[X]	Validate State OK to run
					[X]	Stop Steam - if running
					[X]	Notify Chat
				[ ]	Notify Remote
					[ ]	Define Remote Launch status message
			[ ]	Launch fails - Local notification
			[ ]	Launch fails - local Remote notification
				[ ]	Connection open
					[ ]	Notify remote
				[ ]	Connection Closed
					[X]	Do Nix
		[ ]	Track Game in progress
 
good job man, I am currently working to use udp and tcp protocol for my app. Steamcooker informed me that TCP is much more resource intensive than udp so I will use it for session creation etc.

Looks good though, let me know when you solve the giving the username and password of the account to the client issue ;).
 
Thanks for that Erix920,

Now which parts on your appln are considering using UDP for?

I'm sure you know that UDP is good for some things and TCP is better for others.

I have some experience in that area if you wish to bounce some ideas around! :D



BTW: I just got home from the in-laws place (they live up in the "bush") - my father-in-law was just inducted into his region's Cricketing Hall of Fame!

It was a bloody "Good Night" - but a 3.5 Hour drive each way (+ a stay overnight) - that's why I wasn't on yesterday. ;)
cheers
OldFart
 
Hi guys,

FWIW: I will probably release a Beta of YASAMM tomorrow evening (Aussie time :rolleyes:).

I have finished and tested the "friends" aka contacts and the "banned IPs".

I don't have true P2P yet - still trying to find how they do it :eek:.

The current version will allow connection between known peers and if the ports are correctly forwarded if using a NAT.

It will work well for LANs.

I just have to implement and test the Steam.Dll launch version (the command line version is working). I'll also update the doco when I finish the coding and testing.

cheers
OldFart
 
Hi guys,

I've been testing launching legitimate Steam accounts/games today using the Steam Dll Api and I tried to launch 2 x games using the API

Code:
    hSteam  = pfnSteamLaunchApp((int)dwGameId, 0, "-console", tSteamError );
    tSteamProgress.Valid    = 1;
    while ( pfnSteamProcessCall( hSteam, tSteamProgress, tSteamError ) == 0)
    {
        ...
    }
Left4Dead2 and DOD:S

Both of them refused to run beyond the promo blurb

L4D2 produced this:-
vnetcafe140.jpg


And DOD:S produced something substantially the same - but in Steam's in-game dialog.

Similar code was working up until about 6 x weeks ago when I last tested it.

Has anyone else had similar problems ?

cheers
[FS]OldFart
 
You must initalize the dll before you can do this.

Code:
            Dim iSteamReturn As Integer = 0
            Dim SErr As New TSteamError()
            Dim startoptions As UInteger = 15

            'start the steam engine and initalize the dll
            iSteamReturn = SteamStartEngine(SErr)
            iSteamReturn = SteamStartup(startoptions, SErr)

To stop Steam

Code:
            iSteamReturn = SteamCleanup(SErr)
            iSteamReturn = SteamShutdownEngine(SErr)
 
Hi Erix920,

I think I'm doing that when I login - this is some of the login code

Code:
	//	Start up
	dwError	= pfnSteamStartEngine( tSteamError );

	if	( tSteamError.eSteamError == eSteamErrorNone )
	{
		dwError	= pfnSteamStartup( uStartOptions, tSteamError );
		if	( tSteamError.eSteamError == eSteamErrorNone )
		{
			//	Login
			hSteam	= pfnSteamLogin( (char *)m_pszSteamUsername, (char *)m_pszSteamPassword, 1, tSteamError );

			tSteamProgress.Valid	= 1;
			while ( pfnSteamProcessCall( hSteam, tSteamProgress, tSteamError ) == 0)
			{
				if	( !GotoSleep() )
				{

I'll go and step through it to make sure - thanks for the reply!

cheers
OldFart
 
Hey OldFart!! I was just thinking of YASAMM... How's it going? Where have you been?

Hi DigitalGeek,

I've been somewhat busy and lazy plus I had some contract work.

I'm still playing around with the "Hole Punching" P2P and spotted a small bug when a client is behind the same firewall as the P2P server. But this depends on Firewall/Modem manufacturer - Netgear is OK but Billion causes the problem - i.e. it returns the LAN gateway IP and not the external IP.

I'm just looking for some energy and inspiration atm! ;)

YASAMM aka VNETCAFE is at Rev 1.0.8.5 and I have ported it to VS 7 (.NET 2003) and I'll then port it to 2008 - unless I should just skip to 2010 Express - any suggestions ?

Our clan is back on track and our DOD:S server is #42 in the world. :D

cheers
OldFart
 
Back
Top