/* GameSpy PT SDK Dan "Mr. Pants" Schoenblum dan@gamespy.com Copyright 2000 GameSpy Industries, Inc */ #include #include "pt.h" #include "../ghttp/ghttp.h" #include "../common/gsStringUtil.h" #include "../common/gsAvailable.h" /************ ** DEFINES ** ************/ #define PTA_DEFAULT_VERCHECK_URL "http://motd." GSI_DOMAIN_NAME "/motd/vercheck.asp" #define PTA_DEFAULT_MOTD_URL "http://motd." GSI_DOMAIN_NAME "/motd/motd.asp" #define PTA_DEFAULT_FILEPLANET_URL "http://www.fileplanet.com/dlfileraw.asp" #define MAX_MIRRORS 32 #define PTA_MAX_STRING_SIZE 2048 char gPTAVercheckURL[PTA_MAX_STRING_SIZE]; char gPTAMOTDURL[PTA_MAX_STRING_SIZE]; char gPTAFilePlanetURL[PTA_MAX_STRING_SIZE]; /********** ** TYPES ** **********/ typedef struct ptaPatchData { ptPatchCallback callback; void * param; } ptaPatchData; typedef struct ptaFilePlanetInfoData { int fileID; ptFilePlanetInfoCallback callback; void * param; } ptaFilePlanetInfoData; /************ ** GLOBALS ** ************/ //static char URL[PTA_MAX_STRING_SIZE]; /************** ** FUNCTIONS ** **************/ static const char * ptaGetKeyValue ( const char * buffer, const char * key ) { static char value[PTA_MAX_STRING_SIZE]; const char * str; int len; str = strstr(buffer, key); if(!str) return NULL; str += strlen(key); len = (int)strcspn(str, "\\"); len = min(len, (int)sizeof(value) - 1); memcpy(value, str, (unsigned int)len); value[len] = '\0'; return value; } static char Line[PTA_MAX_STRING_SIZE]; static int ptaFillLine ( const char * buffer ) { char * str = Line; int i; // Skip white space. //////////////////// for(i = 0 ; isspace(*buffer) ; i++) buffer++; // Check for EOF. ///////////////// if(*buffer == '\0') return EOF; // Copy off the line. ///////////////////// for( ; *buffer && ((*buffer != 0x0A) && (*buffer != 0x0D)) ; i++) { if(i == sizeof(Line) - 1) { // This line is too big for our buffer. /////////////////////////////////////// assert(0); return EOF; } *str++ = *buffer++; } *str = '\0'; return i; } static void ptaCallPatchCallback ( ptaPatchData * data, PTBool available, PTBool mandatory, const char * versionName, int fileID, const char * downloadURL ) { if(data->callback) { #ifndef GSI_UNICODE data->callback(available, mandatory, versionName, fileID, downloadURL, data->param); #else unsigned short versionName_W[255]; unsigned short downloadURL_W[PTA_MAX_STRING_SIZE*2]; UTF8ToUCS2String(versionName, versionName_W); AsciiToUCS2String(downloadURL, downloadURL_W); data->callback(available, mandatory, versionName_W, fileID, downloadURL_W, data->param); #endif } gsifree(data); } // already returns ghttptrue static GHTTPBool ptaPatchFailed ( ptaPatchData * data ) { ptaCallPatchCallback(data, PTFalse, PTFalse, "", 0, ""); return GHTTPTrue; } static void ptaCallFilePlanetInfoCallback ( ptaFilePlanetInfoData * data, PTBool found, const char * description, const char * size, int numMirrors, char ** mirrorNames, char ** mirrorURLs ) { int i; if(data->callback) { if (!found) data->callback(data->fileID, PTFalse, NULL, NULL, 0, NULL, NULL, data->param); else { #ifndef GSI_UNICODE data->callback(data->fileID, found, description, size, numMirrors, (const char**)mirrorNames, (const char**)mirrorURLs, data->param); #else unsigned short description_W[255]; unsigned short size_W[1024]; unsigned short** mirrorNames_W; unsigned short** mirrorURLs_W; int i; UTF8ToUCS2String(description, description_W); AsciiToUCS2String(size, size_W); mirrorNames_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)mirrorNames, numMirrors); mirrorURLs_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)mirrorURLs, numMirrors); data->callback(data->fileID, found, description_W, size_W, numMirrors, (const unsigned short**)mirrorNames_W, (const unsigned short**)mirrorURLs_W, data->param); for (i=0; i < numMirrors; i++) { gsifree(mirrorNames[i]); gsifree(mirrorURLs[i]); } gsifree(mirrorNames); gsifree(mirrorURLs); #endif } } for(i = 0 ; i < numMirrors ; i++) { gsifree(mirrorNames[i]); gsifree(mirrorURLs[i]); } gsifree(data); } // already returns ghttptrue static GHTTPBool ptaFilePlanetInfoFailed ( ptaFilePlanetInfoData * data ) { ptaCallFilePlanetInfoCallback(data, PTFalse, NULL, NULL, 0, NULL, NULL); return GHTTPTrue; } static GHTTPBool ptaPatchCompletedCallback ( GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param ) { ptaPatchData * data = (ptaPatchData *)param; const char * value; PTBool mandatory; int fileID; char versionName[PTA_MAX_STRING_SIZE]; char downloadURL[PTA_MAX_STRING_SIZE]; GSI_UNUSED(bufferLen); GSI_UNUSED(request); // Check for success. ///////////////////// if(result != GHTTPSuccess) return ptaPatchFailed(data); // Check for a patch. ///////////////////// value = ptaGetKeyValue(buffer, "\\newver\\"); if(!value || !atoi(value)) return ptaPatchFailed(data); // Check the mandatory flag. //////////////////////////// value = ptaGetKeyValue(buffer, "\\lockout\\"); mandatory = (value && atoi(value)); // Get the file id. /////////////////// value = ptaGetKeyValue(buffer, "\\fpfileid\\"); if(value) fileID = atoi(value); else fileID = 0; // Get the name. //////////////// value = ptaGetKeyValue(buffer, "\\newvername\\"); if(value) { strncpy(versionName, value, sizeof(versionName)); versionName[sizeof(versionName) - 1] = '\0'; } else versionName[0] = '\0'; // Get the URL. /////////////// value = ptaGetKeyValue(buffer, "\\dlurl\\"); if(value) { strncpy(downloadURL, value, sizeof(downloadURL)); downloadURL[sizeof(downloadURL) - 1] = '\0'; } else downloadURL[0] = '\0'; // Call the callback. ///////////////////// ptaCallPatchCallback(data, PTTrue, mandatory, versionName, fileID, downloadURL); return GHTTPTrue; } PTBool ptCheckForPatchA ( int productID, const char * versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, void * param ) { int charsWritten; char aURL[PTA_MAX_STRING_SIZE]; ptaPatchData * data; // check if the backend is available if(__GSIACResult != GSIACAvailable) return PTFalse; // Check the arguments. /////////////////////// assert(versionUniqueID); if(!versionUniqueID) return PTFalse; assert(callback); if(!callback) return PTFalse; // override hostname? if (gPTAVercheckURL[0] == '\0') sprintf(gPTAVercheckURL, PTA_DEFAULT_VERCHECK_URL); // Store some data. /////////////////// data = (ptaPatchData *)gsimalloc(sizeof(ptaPatchData)); if(!data) return PTFalse; memset(data, 0, sizeof(ptaPatchData)); data->callback = callback; data->param = param; // Build the URL. ///////////////// charsWritten = snprintf(aURL, PTA_MAX_STRING_SIZE, "%s?productid=%d&versionuniqueid=%s&distid=%d&gamename=%s", gPTAVercheckURL, productID, versionUniqueID, distributionID, __GSIACGamename); assert(charsWritten >= 0); if (charsWritten < 0) return PTFalse; // Send the request. //////////////////// if((ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaPatchCompletedCallback, data) == (unsigned char)(-1)) && !blocking) return PTFalse; return PTTrue; } #ifdef GSI_UNICODE PTBool ptCheckForPatchW ( int productID, const unsigned short* versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, void * param ) { char versionUniqueID_A[255]; UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); return ptCheckForPatchA(productID, versionUniqueID_A, distributionID, callback, blocking, param); } #endif PTBool ptTrackUsageA ( int userID, int productID, const char * versionUniqueID, int distributionID, PTBool blocking ) { int charsWritten; char aURL[PTA_MAX_STRING_SIZE]; // check if the backend is available if(__GSIACResult != GSIACAvailable) return PTFalse; // Check the arguments. /////////////////////// assert(versionUniqueID); if(!versionUniqueID) return PTFalse; // override hostname? if (gPTAMOTDURL[0] == '\0') sprintf(gPTAMOTDURL, PTA_DEFAULT_MOTD_URL); // Build the URL. ///////////////// charsWritten = snprintf(aURL, PTA_MAX_STRING_SIZE, "%s?userid=%d&productid=%d&versionuniqueid=%s&distid=%d&uniqueid=%s&gamename=%s", gPTAMOTDURL, userID, productID, versionUniqueID, distributionID, GOAGetUniqueID(), __GSIACGamename); assert(charsWritten >= 0); if (charsWritten < 0) return PTFalse; // Send the info. ///////////////// if(ghttpGetFileA(aURL, (GHTTPBool)blocking, NULL, NULL) == -1) return PTFalse; return PTTrue; } #ifdef GSI_UNICODE PTBool ptTrackUsageW ( int userID, int productID, const unsigned short* versionUniqueID, int distributionID, PTBool blocking ) { char versionUniqueID_A[255]; UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); return ptTrackUsageA(userID, productID, versionUniqueID_A, distributionID, blocking); } #endif PTBool ptCreateCheckPatchTrackUsageReqA ( int userID, int productID, const char * versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, int *request, void * param ) { int charsWritten; char aURL[PTA_MAX_STRING_SIZE]; ptaPatchData * data; // check if the backend is available if(__GSIACResult != GSIACAvailable) return PTFalse; // Check the arguments. /////////////////////// assert(versionUniqueID); if(!versionUniqueID) return PTFalse; assert(callback); if(!callback) return PTFalse; // Store some data. /////////////////// data = (ptaPatchData *)gsimalloc(sizeof(ptaPatchData)); if(!data) return PTFalse; memset(data, 0, sizeof(ptaPatchData)); data->callback = callback; data->param = param; // override hostname? if (gPTAVercheckURL[0] == '\0') sprintf(gPTAVercheckURL, PTA_DEFAULT_VERCHECK_URL); // Build the URL. ///////////////// charsWritten = snprintf(aURL, PTA_MAX_STRING_SIZE, "%s?userid=%d&productid=%d&versionuniqueid=%s&distid=%d&uniqueid=%s&gamename=%s", gPTAVercheckURL, userID, productID, versionUniqueID, distributionID, GOAGetUniqueID(), __GSIACGamename); assert(charsWritten >= 0); if (charsWritten < 0) return PTFalse; // Send the request. //////////////////// *request = ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaPatchCompletedCallback, data); if (*request == -1) return PTFalse; return PTTrue; } #ifdef GSI_UNICODE PTBool ptCreateCheckPatchTrackUsageReqW ( int userID, int productID, const unsigned short * versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, int *request, void * param ) { char versionUniqueID_A[255]; UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); return ptCreateCheckPatchTrackUsageReqA(userID, productID, versionUniqueID_A, distributionID, callback, blocking, request, param); } #endif PTBool ptCheckForPatchAndTrackUsageA ( int userID, int productID, const char * versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, void * param ) { GHTTPRequest aRequest; // create the request and send it. /////////////////////////////////// return ptCreateCheckPatchTrackUsageReqA(userID, productID, versionUniqueID, distributionID, callback, blocking, &aRequest, param); } #ifdef GSI_UNICODE PTBool ptCheckForPatchAndTrackUsageW ( int userID, int productID, const unsigned short * versionUniqueID, int distributionID, ptPatchCallback callback, PTBool blocking, void * param ) { char versionUniqueID_A[255]; UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); return ptCheckForPatchAndTrackUsageA(userID, productID, versionUniqueID_A, distributionID, callback, blocking, param); } #endif static GHTTPBool ptaFilePlanetCompletedCallback ( GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param ) { ptaFilePlanetInfoData * data = (ptaFilePlanetInfoData *)param; int len; char description[256]; char size[64]; char * mirrorNames[MAX_MIRRORS]; char * mirrorURLs[MAX_MIRRORS]; int i; char * str; // check if the backend is available if(__GSIACResult != GSIACAvailable) return GHTTPFalse; GSI_UNUSED(request); GSI_UNUSED(bufferLen); // Check for success. ///////////////////// if(result != GHTTPSuccess) return ptaFilePlanetInfoFailed(data); // Get the description. /////////////////////// len = ptaFillLine(buffer); if(len == EOF) return ptaFilePlanetInfoFailed(data); buffer += len; strncpy(description, Line, sizeof(description)); description[sizeof(description) - 1] = '\0'; // Get the size. //////////////// len = ptaFillLine(buffer); if(len == EOF) return ptaFilePlanetInfoFailed(data); buffer += len; strncpy(size, Line, sizeof(size)); size[sizeof(size) - 1] = '\0'; // Get the mirrors. /////////////////// for(i = 0 ; (i < MAX_MIRRORS) && ((len = ptaFillLine(buffer)) != EOF) ; ) { // Adjust the buffer. ///////////////////// buffer += len; // Find the tab. //////////////// str = strchr(Line, '\t'); if(!str) continue; // Copy off the name. ///////////////////// len = (str - Line); mirrorNames[i] = (char *)gsimalloc((unsigned int)len + 1); if(!mirrorNames[i]) break; memcpy(mirrorNames[i], Line, (unsigned int)len); mirrorNames[i][len] = '\0'; // Copy off the URL. //////////////////// str++; len = (int)strlen(str); mirrorURLs[i] = (char *)gsimalloc((unsigned int)len + 1); if(!mirrorURLs[i]) { gsifree(mirrorNames[i]); break; } strcpy(mirrorURLs[i], str); // One more mirror. /////////////////// i++; } // Call the callback. ///////////////////// ptaCallFilePlanetInfoCallback(data, PTTrue, description, size, i, mirrorNames, mirrorURLs); return GHTTPTrue; } // 9/7/2004 (xgd) ptLookupFilePlanetInfo() deprecated; per case 2724. // PTBool ptLookupFilePlanetInfo ( int fileID, ptFilePlanetInfoCallback callback, PTBool blocking, void * param ) { char aURL[PTA_MAX_STRING_SIZE]; ptaFilePlanetInfoData * data; // Check the arguments. /////////////////////// assert(callback); if(!callback) return PTFalse; // override hostname? if (gPTAFilePlanetURL[0] == '\0') sprintf(gPTAFilePlanetURL, PTA_DEFAULT_FILEPLANET_URL); // Store some data. /////////////////// data = (ptaFilePlanetInfoData *)gsimalloc(sizeof(ptaFilePlanetInfoData)); if(!data) return PTFalse; memset(data, 0, sizeof(ptaFilePlanetInfoData)); data->callback = callback; data->param = param; data->fileID = fileID; // Build the URL. ///////////////// // 11/24/2004 - Added By Saad Nader // Now using string size as limit for printing // also null terminate string automatically /////////////////////////////////////////////// snprintf(aURL, PTA_MAX_STRING_SIZE, "%s?file=%d&gamename=%s", gPTAFilePlanetURL, fileID, __GSIACGamename); // Send the request. //////////////////// if((ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaFilePlanetCompletedCallback, data) == -1) && !blocking) return PTFalse; return PTTrue; }