/* gpiSearch.c GameSpy Presence SDK Dan "Mr. Pants" Schoenblum Copyright 1999-2007 GameSpy Industries, Inc devsupport@gamespy.com *********************************************************************** Please see the GameSpy Presence SDK documentation for more information **********************************************************************/ //INCLUDES ////////// #include #include #include "gpi.h" //DEFINES ///////// // Search Manager Address. ////////////////////////// #define GPI_SEARCH_MANAGER_NAME "gpsp." GSI_DOMAIN_NAME #define GPI_SEARCH_MANAGER_PORT 29901 //GLOBALS ///////// char GPSearchManagerHostname[64] = GPI_SEARCH_MANAGER_NAME; //char GPSearchManagerHostname[64] = "localhost"; //FUNCTIONS /////////// static GPResult gpiStartProfileSearch( GPConnection * connection, GPIOperation * operation ) { GPISearchData * data = (GPISearchData*)operation->data; int rcode; struct sockaddr_in address; struct hostent * host; // Initialize the buffer. ///////////////////////// data->inputBuffer.size = 4096; data->inputBuffer.buffer = (char *)gsimalloc((unsigned int)data->inputBuffer.size + 1); if(data->inputBuffer.buffer == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); // Create the socket. ///////////////////// data->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(data->sock == INVALID_SOCKET) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket."); // Make it non-blocking. //////////////////////// rcode = SetSockBlocking(data->sock,0); if(rcode == 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking."); // Bind the socket. /////////////////// /* memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; rcode = bind(data->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); if (gsiSocketIsError(rcode)) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket."); */ // Get the server host. /////////////////////// host = gethostbyname(GPSearchManagerHostname); if(host == NULL) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "Could not resolve search mananger host name."); // Connect the socket. ////////////////////// memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = *(unsigned int *)host->h_addr_list[0]; assert(address.sin_addr.s_addr != 0); address.sin_port = htons(GPI_SEARCH_MANAGER_PORT); rcode = connect(data->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); if (gsiSocketIsError(rcode)) { int error = GOAGetLastError(data->sock); if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT) ) { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error connecting a socket."); } } // We're waiting for the connect to complete. ///////////////////////////////////////////// operation->state = GPI_CONNECTING; data->searchStartTime = current_time(); return GP_NO_ERROR; } static GPResult gpiInitSearchData( GPConnection * connection, GPISearchData ** searchData, int type ) { GPISearchData * data; // Init the data. ///////////////// data = (GPISearchData *)gsimalloc(sizeof(GPISearchData)); if(data == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); memset(data, 0, sizeof(GPISearchData)); data->type = type; data->sock = INVALID_SOCKET; data->inputBuffer.buffer = NULL; data->inputBuffer.len = 0; data->inputBuffer.pos = 0; data->inputBuffer.size = 0; data->outputBuffer.len = 0; data->outputBuffer.pos = 0; data->outputBuffer.size = 4096; data->outputBuffer.buffer = (char *)gsimalloc((unsigned int)data->outputBuffer.size + 1); if(data->outputBuffer.buffer == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); data->processing = GPIFalse; data->remove = GPIFalse; *searchData = data; return GP_NO_ERROR; } static GPResult gpiStartSearch( GPConnection * connection, GPISearchData * data, GPEnum blocking, GPCallback callback, void * param ) { GPIOperation * operation; GPIConnection * iconnection = (GPIConnection*)*connection; // One more search. /////////////////// iconnection->numSearches++; // Create a new operation. ////////////////////////// CHECK_RESULT(gpiAddOperation(connection, GPI_PROFILE_SEARCH, data, &operation, blocking, callback, param)); // Start the search. //////////////////// CHECK_RESULT(gpiStartProfileSearch(connection, operation)); // Process it if blocking. ////////////////////////// if(operation->blocking) CHECK_RESULT(gpiProcess(connection, operation->id)); return GP_NO_ERROR; } GPResult gpiProfileSearch( GPConnection * connection, const char nick[GP_NICK_LEN], const char uniquenick[GP_UNIQUENICK_LEN], const char email[GP_EMAIL_LEN], const char firstname[GP_FIRSTNAME_LEN], const char lastname[GP_LASTNAME_LEN], int icquin, int skip, GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Error check. /////////////// if((nick == NULL) || (*nick == '\0')) if((email == NULL) || (*email == '\0')) if((firstname == NULL) || (*firstname == '\0')) if((lastname == NULL) || (*lastname == '\0')) if(icquin == 0) if((uniquenick == NULL) || (*uniquenick == '\0')) Error(connection, GP_PARAMETER_ERROR, "No search criteria."); // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PROFILE)); // Fill in the data. //////////////////// if(nick == NULL) data->nick[0] = '\0'; else strzcpy(data->nick, nick, GP_NICK_LEN); if(uniquenick == NULL) data->uniquenick[0] = '\0'; else strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); if(email == NULL) data->email[0] = '\0'; else strzcpy(data->email, email, GP_EMAIL_LEN); _strlwr(data->email); if(firstname == NULL) data->firstname[0] = '\0'; else strzcpy(data->firstname, firstname, GP_FIRSTNAME_LEN); if(lastname == NULL) data->lastname[0] = '\0'; else strzcpy(data->lastname, lastname, GP_LASTNAME_LEN); data->icquin = icquin; if(skip < 0) skip = 0; data->skip = skip; // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiProfileSearchUniquenick( GPConnection * connection, const char uniquenick[GP_UNIQUENICK_LEN], const int namespaceIDs[], int numNamespaces, GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Error check. /////////////// if((uniquenick == NULL) || (*uniquenick == '\0')) Error(connection, GP_PARAMETER_ERROR, "No search criteria."); // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PROFILE_UNIQUENICK)); // Fill in the data. //////////////////// strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); if((namespaceIDs != NULL) && (numNamespaces > 0)) { data->numNamespaces = min(numNamespaces, GP_MAX_NAMESPACEIDS); memcpy(data->namespaceIDs, namespaceIDs, sizeof(namespaceIDs[0]) * data->numNamespaces); } else { data->numNamespaces = 0; } // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiIsValidEmail( GPConnection * connection, const char email[GP_EMAIL_LEN], GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Error check. /////////////// if((email == NULL) || (*email == '\0') || (strlen(email) >= GP_EMAIL_LEN)) Error(connection, GP_PARAMETER_ERROR, "Invalid e-mail."); // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_IS_VALID)); // Fill in the data. //////////////////// strzcpy(data->email, email, GP_EMAIL_LEN); _strlwr(data->email); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiGetUserNicks( GPConnection * connection, const char email[GP_EMAIL_LEN], const char password[GP_PASSWORD_LEN], GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Error check. /////////////// if((email == NULL) || (*email == '\0') || (strlen(email) >= GP_EMAIL_LEN)) Error(connection, GP_PARAMETER_ERROR, "Invalid e-mail."); if((password == NULL) || (strlen(password) >= GP_PASSWORD_LEN)) Error(connection, GP_PARAMETER_ERROR, "Invalid password."); // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_NICKS)); // Fill in the data. //////////////////// strzcpy(data->email, email, GP_EMAIL_LEN); _strlwr(data->email); strzcpy(data->password, password, GP_PASSWORD_LEN); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiFindPlayers( GPConnection * connection, int productID, GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PLAYERS)); // Fill in the data. //////////////////// data->productID = productID; // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiCheckUser( GPConnection * connection, const char nick[GP_NICK_LEN], const char email[GP_EMAIL_LEN], const char password[GP_PASSWORD_LEN], GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_CHECK)); // Fill in the data. //////////////////// strzcpy(data->email, email, GP_EMAIL_LEN); _strlwr(data->email); strzcpy(data->nick, nick, GP_NICK_LEN); if(password) strzcpy(data->password, password, GP_PASSWORD_LEN); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiNewUser( GPConnection * connection, const char nick[GP_NICK_LEN], const char uniquenick[GP_UNIQUENICK_LEN], const char email[GP_EMAIL_LEN], const char password[GP_PASSWORD_LEN], const char cdkey[GP_CDKEY_LEN], GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_NEWUSER)); // Fill in the data. //////////////////// strzcpy(data->email, email, GP_EMAIL_LEN); strzcpy(data->nick, nick, GP_NICK_LEN); strzcpy(data->password, password, GP_PASSWORD_LEN); strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); if(cdkey) strzcpy(data->cdkey, cdkey, GP_CDKEY_LEN); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiOthersBuddy( GPConnection * connection, GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_OTHERS_BUDDY)); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiOthersBuddyList( GPConnection * connection, int *profiles, int numOfProfiles, GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_OTHERS_BUDDY_LIST)); data->revBuddyProfileIds = profiles; data->numOfRevBuddyProfiles = numOfProfiles; CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } GPResult gpiSuggestUniqueNick( GPConnection * connection, const char desirednick[GP_NICK_LEN], GPEnum blocking, GPCallback callback, void * param ) { GPISearchData * data; // Init the data. ///////////////// CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_SUGGEST_UNIQUE)); // Fill in the data. //////////////////// strzcpy(data->uniquenick, desirednick, GP_UNIQUENICK_LEN); // Start the search. //////////////////// CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); return GP_NO_ERROR; } static GPResult gpiProcessSearch( GPConnection * connection, GPIOperation * operation ) { int state; GPISearchData * data; char key[512]; char value[512]; GPIBool done; int index; int oldIndex; GPIBool loop; GPIBool more; GPICallback callback; GPIConnection * iconnection = (GPIConnection*)*connection; int len; GPIBool connClosed; GPResult result; void * tempPtr; GPIBool doneParsingMatch; int rcode; int pid; GPProfileSearchMatch * match; GPUniqueMatch *uniqueNickMatch; //password encryption stuff char passwordenc[GP_PASSWORDENC_LEN]; // Get a pointer to the data. ///////////////////////////// data = (GPISearchData*)operation->data; // Loop if blocking. //////////////////// if(operation->blocking) loop = GPITrue; else loop = GPIFalse; if (!operation->blocking && (current_time() - data->searchStartTime > GPI_SEARCH_TIMEOUT)) { data->remove = GPITrue; CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_TIMED_OUT, "The search timed out"); } do { // Send anything that needs to be sent. /////////////////////////////////////// CHECK_RESULT(gpiSendFromBuffer(connection, data->sock, &data->outputBuffer, &connClosed, GPITrue, "SM")); // Is it connecting? //////////////////// if(operation->state == GPI_CONNECTING) { // Check the connect state. /////////////////////////// CHECK_RESULT(gpiCheckSocketConnect(connection, data->sock, &state)); // Check for a failed attempt. ////////////////////////////// if(state == GPI_DISCONNECTED) CallbackError(connection, GP_SERVER_ERROR, GP_SEARCH_CONNECTION_FAILED, "Could not connect to the search manager."); // Check if finished connecting. //////////////////////////////// if(state == GPI_CONNECTED) { // Send a request based on type. //////////////////////////////// if(data->type == GPI_SEARCH_PROFILE) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\search\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); if(data->nick[0] != '\0') { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); } if(data->uniquenick[0] != '\0') { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); } if(data->email[0] != '\0') { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); } if(data->firstname[0] != '\0') { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\firstname\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->firstname); } if(data->lastname[0] != '\0') { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\lastname\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->lastname); } if(data->icquin != 0) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\icquin\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->icquin); } if(data->skip > 0) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\skip\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->skip); } } else if(data->type == GPI_SEARCH_PROFILE_UNIQUENICK) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\searchunique\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaces\\"); if(data->numNamespaces > 0) { int i; for(i = 0 ; i < data->numNamespaces ; i++) { if(i > 0) gpiAppendCharToBuffer(connection, &data->outputBuffer, ','); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->namespaceIDs[i]); } } else { gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); } } else if(data->type == GPI_SEARCH_IS_VALID) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\valid\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); } else if(data->type == GPI_SEARCH_NICKS) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nicks\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); gpiEncodeString(data->password, passwordenc); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); } else if(data->type == GPI_SEARCH_PLAYERS) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\pmatch\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\productid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->productID); } else if(data->type == GPI_SEARCH_CHECK) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\check\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); gpiEncodeString(data->password, passwordenc); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); } else if(data->type == GPI_SEARCH_NEWUSER) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\newuser\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); gpiEncodeString(data->password, passwordenc); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\productID\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->productID); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); if(data->cdkey[0]) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\cdkey\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->cdkey); } gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); } else if(data->type == GPI_SEARCH_OTHERS_BUDDY) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\others\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); } else if(data->type == GPI_SEARCH_OTHERS_BUDDY_LIST) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\otherslist\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\numopids\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->numOfRevBuddyProfiles); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\opids\\"); if (data->revBuddyProfileIds) { int i; gpiAppendIntToBuffer(connection, &data->outputBuffer, data->revBuddyProfileIds[0]); for (i = 1; i < data->numOfRevBuddyProfiles; i++) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "|"); gpiAppendIntToBuffer(connection, &data->outputBuffer, data->revBuddyProfileIds[i]); } } gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); } else if(data->type == GPI_SEARCH_SUGGEST_UNIQUE) { gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquesearch\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\preferrednick\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); } else { assert(0); } gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\gamename\\"); gpiAppendStringToBuffer(connection, &data->outputBuffer, __GSIACGamename); gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\final\\"); // Update the state. //////////////////// operation->state = GPI_WAITING; } } // Is it waiting? ///////////////// else if(operation->state == GPI_WAITING) { // Read from the socket. //////////////////////// result = gpiRecvToBuffer(connection, data->sock, &data->inputBuffer, &len, &connClosed, "SM"); if(result != GP_NO_ERROR) { if(result == GP_NETWORK_ERROR) CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_CONNECTION_FAILED, "There was an error reading from the server."); return result; } if (operation->blocking && (current_time() - data->searchStartTime > GPI_SEARCH_TIMEOUT)) { data->remove = GPITrue; CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_TIMED_OUT, "The search timed out"); } // Is this the end of the response? /////////////////////////////////// if(strstr(data->inputBuffer.buffer, "\\final\\") != NULL) { // Reset the index. /////////////////// index = 0; // This operation is finishing up. ////////////////////////////////// operation->state = GPI_FINISHING; // Check for an error. ////////////////////// if(gpiCheckForError(connection, data->inputBuffer.buffer, GPITrue)) { data->remove = GPITrue; return GP_SERVER_ERROR; } // Process it based on type. //////////////////////////// if((data->type == GPI_SEARCH_PROFILE) || (data->type == GPI_SEARCH_PROFILE_UNIQUENICK)) { GPProfileSearchResponseArg arg; // Start setting up the arg. //////////////////////////// arg.result = GP_NO_ERROR; arg.numMatches = 0; arg.matches = NULL; arg.more = GP_DONE; // Parse the message. ///////////////////// done = GPIFalse; do { // Read the next key and value. /////////////////////////////// CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); // Is the list done? //////////////////// if(strcmp(key, "bsrdone") == 0) { // Check for more. ////////////////// CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "more") == 0) { // Make sure there are actually more. ///////////////////////////////////// if(strcmp(value, "0") != 0) arg.more = GP_MORE; } // Done. //////// done = GPITrue; } else if(strcmp(key, "bsr") == 0) { // Create a new match. ////////////////////// arg.numMatches++; arg.matches = (GPProfileSearchMatch *)gsirealloc(arg.matches, sizeof(GPProfileSearchMatch) * arg.numMatches); if(arg.matches == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); match = &arg.matches[arg.numMatches - 1]; memset(match, 0, sizeof(GPProfileSearchMatch)); // Get the profile id. ////////////////////// match->profile = atoi(value); // PANTS|05.16.00 // Changed to be order independent, and ignore unrecognized keys. ///////////////////////////////////////////////////////////////// // Read key/value pairs. //////////////////////// doneParsingMatch = GPIFalse; do { // Read the next key/value. /////////////////////////// oldIndex = index; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); // Set the field based on the key. ////////////////////////////////// #ifndef GSI_UNICODE if(strcmp(key, "nick") == 0) strzcpy(match->nick, value, GP_NICK_LEN); else if(strcmp(key, "uniquenick") == 0) strzcpy(match->uniquenick, value, GP_UNIQUENICK_LEN); else if(strcmp(key, "namespaceid") == 0) match->namespaceID = atoi(value); else if(strcmp(key, "firstname") == 0) strzcpy(match->firstname, value, GP_FIRSTNAME_LEN); else if(strcmp(key, "lastname") == 0) strzcpy(match->lastname, value, GP_LASTNAME_LEN); else if(strcmp(key, "email") == 0) strzcpy(match->email, value, GP_EMAIL_LEN); else if((strcmp(key, "bsr") == 0) || (strcmp(key, "bsrdone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #else if(strcmp(key, "nick") == 0) UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); else if(strcmp(key, "uniquenick") == 0) UTF8ToUCS2StringLen(value, match->uniquenick, GP_UNIQUENICK_LEN); else if(strcmp(key, "namespaceid") == 0) match->namespaceID = atoi(value); else if(strcmp(key, "firstname") == 0) UTF8ToUCS2StringLen(value, match->firstname, GP_FIRSTNAME_LEN); else if(strcmp(key, "lastname") == 0) UTF8ToUCS2StringLen(value, match->lastname, GP_LASTNAME_LEN); else if(strcmp(key, "email") == 0) UTF8ToUCS2StringLen(value, match->email, GP_EMAIL_LEN); else if((strcmp(key, "bsr") == 0) || (strcmp(key, "bsrdone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #endif } while(!doneParsingMatch); } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Save the more state. /////////////////////// more = (GPIBool)arg.more; // Get the callback. //////////////////// callback = operation->callback; // Call the callback. ///////////////////// if(callback.callback != NULL) callback.callback(connection, &arg, callback.param); // Start a new operation if they want more matches. /////////////////////////////////////////////////// if((more == GP_MORE) && (arg.more == GP_MORE)) CHECK_RESULT(gpiProfileSearch(connection, data->nick, data->uniquenick, data->email, data->firstname, data->lastname, data->icquin, arg.numMatches + data->skip, (GPEnum)operation->blocking, operation->callback.callback, operation->callback.param)); // We're done. ////////////// freeclear(arg.matches); } else if(data->type == GPI_SEARCH_IS_VALID) { callback = operation->callback; if(callback.callback != NULL) { GPIsValidEmailResponseArg * arg; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "vr") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); // Setup the arg. ///////////////// arg = (GPIsValidEmailResponseArg *)gsimalloc(sizeof(GPIsValidEmailResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = GP_NO_ERROR; #ifndef GSI_UNICODE strzcpy(arg->email, data->email, GP_EMAIL_LEN); #else UTF8ToUCS2String(data->email, arg->email); #endif if(value[0] == '0') arg->isValid = GP_INVALID; else arg->isValid = GP_VALID; // Add the callback. //////////////////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); } } else if(data->type == GPI_SEARCH_NICKS) { callback = operation->callback; if(callback.callback != NULL) { GPGetUserNicksResponseArg * arg; // Setup the arg. ///////////////// arg = (GPGetUserNicksResponseArg *)gsimalloc(sizeof(GPGetUserNicksResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = GP_NO_ERROR; #ifndef GSI_UNICODE strcpy(arg->email, data->email); #else UTF8ToUCS2String(data->email, arg->email); #endif arg->numNicks = 0; arg->nicks = NULL; arg->uniquenicks = NULL; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "nr") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); // Get the nicks. ///////////////// done = GPIFalse; do { CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "nick") == 0) { // Add it. ////////// #ifndef GSI_UNICODE tempPtr = gsirealloc(arg->nicks, sizeof(char *) * (arg->numNicks + 1)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->nicks = (char **)tempPtr; tempPtr = gsimalloc(GP_NICK_LEN); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->nicks[arg->numNicks] = (gsi_char*)tempPtr; strzcpy(arg->nicks[arg->numNicks], value, GP_NICK_LEN); arg->numNicks++; #else tempPtr = gsirealloc(arg->nicks, sizeof(unsigned short *) * (arg->numNicks + 1)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->nicks = (unsigned short **)tempPtr; tempPtr = gsimalloc(GP_NICK_LEN * sizeof(unsigned short)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->nicks[arg->numNicks] = (gsi_char*)tempPtr; UTF8ToUCS2StringLen(value, arg->nicks[arg->numNicks], GP_NICK_LEN); arg->numNicks++; #endif } else if(strcmp(key, "uniquenick") == 0) { if(arg->numNicks <= 0) continue; // Add it. ////////// #ifndef GSI_UNICODE tempPtr = gsirealloc(arg->uniquenicks, sizeof(char *) * arg->numNicks); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->uniquenicks = (char **)tempPtr; tempPtr = gsimalloc(GP_UNIQUENICK_LEN); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->uniquenicks[arg->numNicks - 1] = (gsi_char*)tempPtr; strzcpy(arg->uniquenicks[arg->numNicks - 1], value, GP_UNIQUENICK_LEN); #else tempPtr = gsirealloc(arg->uniquenicks, sizeof(unsigned short *) * arg->numNicks); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->uniquenicks = (unsigned short **)tempPtr; tempPtr = gsimalloc(GP_UNIQUENICK_LEN * sizeof(unsigned short)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->uniquenicks[arg->numNicks - 1] = (gsi_char*)tempPtr; UTF8ToUCS2StringLen(value, arg->uniquenicks[arg->numNicks - 1], GP_UNIQUENICK_LEN); #endif } else if(strcmp(key, "ndone") == 0) { // Done. //////// done = GPITrue; } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Do it. ///////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_NICKS)); } } else if(data->type == GPI_SEARCH_PLAYERS) { callback = operation->callback; if(callback.callback != NULL) { GPFindPlayersResponseArg * arg; GPFindPlayerMatch * match; // Start setting up the arg. //////////////////////////// arg = (GPFindPlayersResponseArg *)gsimalloc(sizeof(GPFindPlayersResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->productID = data->productID; arg->result = GP_NO_ERROR; arg->numMatches = 0; arg->matches = NULL; // Parse the message. ///////////////////// done = GPIFalse; do { // Read the next key and value. /////////////////////////////// CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); // Is the list done? //////////////////// if(strcmp(key, "psrdone") == 0) { // Done. //////// done = GPITrue; } else if(strcmp(key, "psr") == 0) { // Create a new match. ////////////////////// arg->numMatches++; arg->matches = (GPFindPlayerMatch *)gsirealloc(arg->matches, sizeof(GPFindPlayerMatch) * arg->numMatches); if(arg->matches == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); match = &arg->matches[arg->numMatches - 1]; memset(match, 0, sizeof(GPFindPlayerMatch)); match->status = GP_ONLINE; // Get the profile id. ////////////////////// match->profile = atoi(value); // PANTS|05.16.00 // Changed to be order independent, and ignore unrecognized keys. ///////////////////////////////////////////////////////////////// // Read key/value pairs. //////////////////////// doneParsingMatch = GPIFalse; do { // Read the next key/value. /////////////////////////// oldIndex = index; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); #ifndef GSI_UNICODE // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "status") == 0) strzcpy(match->statusString, value, GP_STATUS_STRING_LEN); else if(strcmp(key, "nick") == 0) strzcpy(match->nick, value, GP_NICK_LEN); if(strcmp(key, "statuscode") == 0) match->status = (GPEnum)atoi(value); else if((strcmp(key, "psr") == 0) || (strcmp(key, "psrdone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #else // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "status") == 0) UTF8ToUCS2StringLen(value, match->statusString, GP_STATUS_STRING_LEN); else if(strcmp(key, "nick") == 0) UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); if(strcmp(key, "statuscode") == 0) match->status = (GPEnum)atoi(value); else if((strcmp(key, "psr") == 0) || (strcmp(key, "psrdone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #endif } while(!doneParsingMatch); } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Do it. ///////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_PMATCH)); } } else if(data->type == GPI_SEARCH_CHECK) { callback = operation->callback; if(callback.callback != NULL) { GPCheckResponseArg * arg; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "cur") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); rcode = atoi(value); if(rcode) { iconnection->errorCode = (GPErrorCode)rcode; pid = 0; } else { if(!gpiValueForKey(data->inputBuffer.buffer, "\\pid\\", value, sizeof(value))) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); pid = atoi(value); } // Setup the arg. ///////////////// arg = (GPCheckResponseArg *)gsimalloc(sizeof(GPCheckResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = (GPResult)rcode; arg->profile = pid; // Add the callback. //////////////////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); } } else if(data->type == GPI_SEARCH_NEWUSER) { callback = operation->callback; if(callback.callback != NULL) { GPNewUserResponseArg * arg; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "nur") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); rcode = atoi(value); if(rcode) iconnection->errorCode = (GPErrorCode)rcode; if(!gpiValueForKey(data->inputBuffer.buffer, "\\pid\\", value, sizeof(value))) { if(rcode == 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); pid = 0; } else pid = atoi(value); // Setup the arg. ///////////////// arg = (GPNewUserResponseArg *)gsimalloc(sizeof(GPNewUserResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = (GPResult)rcode; arg->profile = pid; // Add the callback. //////////////////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); } } else if(data->type == GPI_SEARCH_OTHERS_BUDDY) { callback = operation->callback; if(callback.callback != NULL) { GPGetReverseBuddiesResponseArg * arg; // Setup the arg. ///////////////// arg = (GPGetReverseBuddiesResponseArg *)gsimalloc(sizeof(GPGetReverseBuddiesResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = GP_NO_ERROR; arg->numProfiles = 0; arg->profiles = NULL; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "others") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); // Get the profiles. ///////////////// done = GPIFalse; do { // Read the next key and value. /////////////////////////////// CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); // Is the list done? //////////////////// if(strcmp(key, "odone") == 0) { // Done. //////// done = GPITrue; } else if(strcmp(key, "o") == 0) { // Add it. ////////// tempPtr = gsirealloc(arg->profiles, sizeof(GPProfileSearchMatch) * (arg->numProfiles + 1)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->profiles = (GPProfileSearchMatch *)tempPtr; match = &arg->profiles[arg->numProfiles]; memset(match, 0, sizeof(GPProfileSearchMatch)); arg->numProfiles++; // Get the profile id. ////////////////////// match->profile = atoi(value); // Read key/value pairs. //////////////////////// doneParsingMatch = GPIFalse; do { // Read the next key/value. /////////////////////////// oldIndex = index; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); #ifndef GSI_UNICODE // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "nick") == 0) strzcpy(match->nick, value, GP_NICK_LEN); else if(strcmp(key, "uniquenick") == 0) strzcpy(match->uniquenick, value, GP_UNIQUENICK_LEN); else if(strcmp(key, "first") == 0) strzcpy(match->firstname, value, GP_FIRSTNAME_LEN); else if(strcmp(key, "last") == 0) strzcpy(match->lastname, value, GP_LASTNAME_LEN); else if(strcmp(key, "email") == 0) strzcpy(match->email, value, GP_EMAIL_LEN); else if((strcmp(key, "o") == 0) || (strcmp(key, "odone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #else // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "nick") == 0) UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); else if(strcmp(key, "uniquenick") == 0) UTF8ToUCS2StringLen(value, match->uniquenick, GP_UNIQUENICK_LEN); else if(strcmp(key, "first") == 0) UTF8ToUCS2StringLen(value, match->firstname, GP_FIRSTNAME_LEN); else if(strcmp(key, "last") == 0) UTF8ToUCS2StringLen(value, match->lastname, GP_LASTNAME_LEN); else if(strcmp(key, "email") == 0) UTF8ToUCS2StringLen(value, match->email, GP_EMAIL_LEN); else if((strcmp(key, "o") == 0) || (strcmp(key, "odone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #endif } while(!doneParsingMatch); } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Do it. ///////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_REVERSE_BUDDIES)); } } else if (data->type == GPI_SEARCH_OTHERS_BUDDY_LIST) { callback = operation->callback; if(callback.callback != NULL) { GPGetReverseBuddiesListResponseArg * arg; // Setup the arg. ///////////////// arg = (GPGetReverseBuddiesListResponseArg *)gsimalloc(sizeof(GPGetReverseBuddiesListResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = GP_NO_ERROR; arg->numOfUniqueMatchs = 0; arg->matches = NULL; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "otherslist") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); // Get the profiles. ///////////////// done = GPIFalse; do { // Read the next key and value. /////////////////////////////// CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); // Is the list done? //////////////////// if(strcmp(key, "oldone") == 0) { // Done. //////// done = GPITrue; } else if(strcmp(key, "o") == 0) { // Add it. ////////// tempPtr = gsirealloc(arg->matches, sizeof(GPUniqueMatch) * (arg->numOfUniqueMatchs + 1)); if(tempPtr == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->matches = (GPUniqueMatch *)tempPtr; uniqueNickMatch = &arg->matches[arg->numOfUniqueMatchs]; memset(uniqueNickMatch, 0, sizeof(GPUniqueMatch)); arg->numOfUniqueMatchs++; // Get the profile id. ////////////////////// uniqueNickMatch->profile = atoi(value); // Read key/value pairs. //////////////////////// doneParsingMatch = GPIFalse; do { // Read the next key/value. /////////////////////////// oldIndex = index; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); #ifndef GSI_UNICODE // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "uniquenick") == 0) strzcpy(uniqueNickMatch->uniqueNick, value, GP_UNIQUENICK_LEN); else if((strcmp(key, "o") == 0) || (strcmp(key, "oldone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #else // Set the field based on the key. ////////////////////////////////// if(strcmp(key, "uniquenick") == 0) UTF8ToUCS2StringLen(value, uniqueNickMatch->uniqueNick, GP_UNIQUENICK_LEN); else if((strcmp(key, "o") == 0) || (strcmp(key, "oldone") == 0)) { doneParsingMatch = GPITrue; index = oldIndex; } #endif } while(!doneParsingMatch); } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Do it. ///////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_REVERSE_BUDDIES_LIST)); } } else if(data->type == GPI_SEARCH_SUGGEST_UNIQUE) { callback = operation->callback; if(callback.callback != NULL) { int count = 0; GPSuggestUniqueNickResponseArg * arg; // Setup the arg. ///////////////// arg = (GPSuggestUniqueNickResponseArg *)gsimalloc(sizeof(GPSuggestUniqueNickResponseArg)); if(arg == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); arg->result = GP_NO_ERROR; arg->numSuggestedNicks = 0; arg->suggestedNicks = NULL; CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "us") != 0) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); arg->numSuggestedNicks = atoi(value); // Allocate memory for the nick array. ////////////////////////////////////// arg->suggestedNicks = (gsi_char **)gsimalloc(sizeof(gsi_char *) * arg->numSuggestedNicks); if(!arg->suggestedNicks) Error(connection, GP_MEMORY_ERROR, "Out of memory."); // Get the nicks. ///////////////// done = GPIFalse; do { CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); if(strcmp(key, "nick") == 0) { // Add it. ////////// #ifndef GSI_UNICODE arg->suggestedNicks[count] = gsimalloc(GP_UNIQUENICK_LEN); if(arg->suggestedNicks[count] == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); strzcpy(arg->suggestedNicks[count], value, GP_UNIQUENICK_LEN); #else arg->suggestedNicks[count] = (unsigned short*)gsimalloc(GP_UNIQUENICK_LEN * sizeof(unsigned short)); if(arg->suggestedNicks[count] == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); UTF8ToUCS2StringLen(value, arg->suggestedNicks[count], GP_UNIQUENICK_LEN); #endif count++; } else if(strcmp(key, "usdone") == 0) { // Check that the header matches the actual number of nicks. //////////////////////////////////////////////////////////// assert(count == arg->numSuggestedNicks); arg->numSuggestedNicks = count; // Done. //////// done = GPITrue; } else { CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); } } while(!done); // Do it. ///////// CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_SUGGESTED_UNIQUE)); } } else { assert(0); } // Flag the operation for removal. ////////////////////////////////// data->remove = GPITrue; // If we're looping, stop. ////////////////////////// loop = GPIFalse; } } //PANTS|05.23.00 - removed sleep //crt - added it back 6/13/00 //PANTS|07.10.00 - only sleep if looping if(loop) msleep(10); } while(loop); return GP_NO_ERROR; } GPResult gpiProcessSearches( GPConnection * connection ) { GPIConnection * iconnection = (GPIConnection*)*connection; GPIOperation ** searchList; GPIOperation * operation; GPISearchData * data; GPResult result; int num = 0; int i; // Are there any searches? ////////////////////////// if(iconnection->numSearches > 0) { // Alloc mem for a search list. /////////////////////////////// searchList = (GPIOperation **)gsimalloc(sizeof(GPIOperation *) * iconnection->numSearches); if(searchList == NULL) Error(connection, GP_MEMORY_ERROR, "Out of memory."); // Create the search list. ////////////////////////// for(operation = &iconnection->operationList[0] ; operation != NULL ; operation = operation->pnext) { // Is this a search? //////////////////// if((operation->type == GPI_PROFILE_SEARCH) && (operation->state != GPI_FINISHING)) { // Is this search being processed already? ////////////////////////////////////////// if(!((GPISearchData *)operation->data)->processing) { assert(num < iconnection->numSearches); searchList[num++] = operation; ((GPISearchData *)operation->data)->processing = GPITrue; } } } // Process the searches. //////////////////////// for(i = 0 ; i < num ; i++) { result = gpiProcessSearch(connection, searchList[i]); if(result != GP_NO_ERROR) searchList[i]->result = result; } // Clear the processing flags, and remove searches that are done. ///////////////////////////////////////////////////////////////// for(i = 0 ; i < num ; i++) { data = ((GPISearchData *)searchList[i]->data); data->processing = GPIFalse; if(data->remove) gpiRemoveOperation(connection, searchList[i]); } freeclear(searchList); } return GP_NO_ERROR; }