Subversion Repositories Games.Chess Giants

Rev

Rev 85 | Rev 89 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // dialog_registration.cpp
  2.  
  3. #include "../common.h"
  4.  
  5.  
  6. // dialog template
  7. #define THIS_DIALOG DIALOG_REGISTER
  8.  
  9.  
  10. // global variables used in this module only
  11. static wchar_t candidate_email[128] = L"";
  12. static unsigned __int32 candidate_code = 0; // 32 bits
  13.  
  14.  
  15. // prototypes of local functions
  16. static int CALLBACK DialogProc_ThisDialog (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam);
  17. static unsigned __int32 RetrieveActivationCode (wchar_t *candidate_email, wchar_t **failure_reason);
  18. static int recv_with_timeout (int socket_id, float timeout_in_seconds, char *outbuf, size_t outbuf_size, int flags);
  19.  
  20.  
  21. void DialogBox_Registration (void)
  22. {
  23.    // helper function to fire up the modal dialog box
  24.  
  25.    // display the dialog box (set the parent to be the desktop)
  26.    DialogBox (hAppInstance, MAKEINTRESOURCE (THIS_DIALOG), NULL, DialogProc_ThisDialog);
  27.  
  28.    return; // finished processing this dialog
  29. }
  30.  
  31.  
  32. static int CALLBACK DialogProc_ThisDialog (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
  33. {
  34.    // message handler for the dialog box
  35.  
  36.    static wchar_t temp_string[1024];
  37.  
  38.    unsigned short wParam_hiword;
  39.    unsigned short wParam_loword;
  40.    wchar_t *failure_reason;
  41.    int write_index;
  42.    int read_index;
  43.    int length;
  44.  
  45.    // filter out the commonly used message values
  46.    wParam_hiword = HIWORD (wParam);
  47.    wParam_loword = LOWORD (wParam);
  48.  
  49.    // have we just fired up this window ?
  50.    if (message == WM_INITDIALOG)
  51.    {
  52.       // center the window
  53.       CenterWindow (hWnd, hMainWnd);
  54.  
  55.       // set dialog icons (small one for title bar & big one for task manager)
  56.       SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon (hAppInstance, MAKEINTRESOURCE (ICON_MAIN)));
  57.       SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) LoadIcon (hAppInstance, MAKEINTRESOURCE (ICON_MAIN)));
  58.  
  59.       // set window title and control texts
  60.       SetWindowText (hWnd, LOCALIZE (L"Registration_Title"));
  61.  
  62.       // set the static texts
  63.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_QUESTION), LOCALIZE (L"Registration_Question"));
  64.       SetWindowText (GetDlgItem (hWnd, BUTTON_DONATE), LOCALIZE (L"Registration_Donate"));
  65.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_NOPAYPAL), LOCALIZE (L"Registration_NoPayPal"));
  66.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_INSTRUCTIONS), LOCALIZE (L"Registration_Instructions"));
  67.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_CODENOTRECEIVED), LOCALIZE (L"Registration_CodeNotReceived"));
  68.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_EMAILADDRESS), LOCALIZE (L"Registration_EmailAddress"));
  69.       if (options.registration.user_email[0] != 0)
  70.          SetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, options.registration.user_email);
  71.       else
  72.          SetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, L"your@email.here");
  73.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_ACTIVATIONCODE), LOCALIZE (L"Registration_ActivationCode"));
  74.       //SetDlgItemInt (hWnd, EDITBOX_REGISTRATION_ACTIVATIONCODE, options.registration.activation_code, false);
  75.       SetWindowText (GetDlgItem (hWnd, BUTTON_VALIDATECODE), LOCALIZE (L"Registration_ValidateCode"));
  76.       Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_STATUSBAR), LOCALIZE (L"Registration_StatusBar"));
  77.  
  78.       // set focus to the first settable item
  79.       SendMessage (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS), EM_SETSEL, 0, -1); // select all text
  80.       SetFocus (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS));
  81.  
  82.       // convert the "no paypal" and the status bar message to hyperlinks
  83.       ConvertStaticToHyperlink (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_NOPAYPAL));
  84.       ConvertStaticToHyperlink (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_CODENOTRECEIVED));
  85.       ConvertStaticToHyperlink (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_STATUSBAR));
  86.    }
  87.  
  88.    // else did we click the close button on the title bar ?
  89.    else if (message == WM_CLOSE)
  90.       EndDialog (hWnd, 0); // close the dialog box
  91.  
  92.    // else did we take action on one of the controls ?
  93.    else if (message == WM_COMMAND)
  94.    {
  95.       // did we cancel the dialog box ? (IDCANCEL is a system-wide dialog box handler value, that catches the ESC key)
  96.       if (wParam_loword == IDCANCEL)
  97.          EndDialog (hWnd, 0); // close the dialog box
  98.  
  99.       // else did the user enter something in the edit boxes ?
  100.       else if (wParam_hiword == EN_CHANGE)
  101.       {
  102.          // enable the validation button only if the PayPal email field has data
  103.          GetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, candidate_email, WCHAR_SIZEOF (candidate_email));
  104.  
  105.          // strip spaces and unprintable characters from candidate email, and bring it lowercase
  106.          length = wcslen (candidate_email);
  107.          write_index = 0;
  108.          for (read_index = 0; read_index < length; read_index++)
  109.             if (!iswspace (candidate_email[read_index]))
  110.             {
  111.                candidate_email[write_index] = tolower (candidate_email[read_index]); // force lowercase
  112.                write_index++; // keep only valid signs and discard spaces
  113.             }
  114.          candidate_email[write_index] = 0; // ensure string is correctly terminated
  115.  
  116.          EnableWindow (GetDlgItem (hWnd, BUTTON_VALIDATECODE), ((candidate_email[0] != 0) && (wcslen (candidate_email) > 5) && (wcsncmp (candidate_email, L"your@email.", 11) != 0)
  117.                                                                 && (wcschr (candidate_email, L'@') != NULL) && (wcschr (candidate_email, L'.') != NULL)));
  118.       }
  119.  
  120.       // else was it the validation button ?
  121.       else if (wParam_loword == BUTTON_VALIDATECODE)
  122.       {
  123.          // query the remote server for the code associated with this email. If it fails, ask why.
  124.          candidate_code = RetrieveActivationCode (candidate_email, &failure_reason);
  125.  
  126.          // was there a problem retrieving the code ?
  127.          if ((failure_reason != NULL) && (failure_reason[0] != 0))
  128.             MessageBox (hWnd, failure_reason, PROGRAM_NAME, MB_ICONERROR | MB_OK); // registration failed. Display an error and DON'T exit the program
  129.  
  130.          // else is the retrieved data correct ?
  131.          else if (IsRegistrationCorrect (candidate_email, candidate_code))
  132.          {
  133.             // if so, save activation email and activation code
  134.             wcscpy_s (options.registration.user_email, WCHAR_SIZEOF (options.registration.user_email), candidate_email);
  135.             options.registration.activation_code = candidate_code;
  136.             MessageBox (hWnd, LOCALIZE (L"Registration_ThankYou"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK);
  137.             EndDialog (hWnd, 0); // then display a thank you dialog box and exit the program
  138.          }
  139.  
  140.          // else the supplied data is wrong
  141.          else
  142.          {
  143.             swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), LOCALIZE (L"Registration_Error"), AUTHOR_EMAIL);
  144.             MessageBox (hWnd, temp_string, PROGRAM_NAME, MB_ICONERROR | MB_OK); // wrong activation. Display an error and DON'T exit the program
  145.          }
  146.       }
  147.  
  148.       // else was it the PayPal button ?
  149.       else if (wParam_loword == BUTTON_DONATE)
  150.          ShellExecute (NULL, L"open", PAYPAL_URL, NULL, NULL, SW_MAXIMIZE); // open PayPal in the default browser, maximized
  151.  
  152.       // else was it the "no PayPal" hyperlink ?
  153.       else if (wParam_loword == STATICTEXT_REGISTRATION_NOPAYPAL)
  154.          ShellExecute (NULL, L"open", NOPAYPAL_URL, NULL, NULL, SW_MAXIMIZE); // open the bank account page in the default browser, maximized
  155.  
  156.       // else was it the status bar hyperlink ?
  157.       else if (wParam_loword == STATICTEXT_REGISTRATION_STATUSBAR)
  158.          ShellExecute (NULL, L"open", PROGRAM_URL, NULL, NULL, SW_MAXIMIZE); // open the main page in the default browser, maximized
  159.    }
  160.  
  161.    // call the default dialog message processing function to keep things going
  162.    return (false);
  163. }
  164.  
  165.  
  166. static unsigned __int32 RetrieveActivationCode (wchar_t *candidate_email, wchar_t **failure_reason)
  167. {
  168.    // this function queries the remote server for registration status. If OK, the received code is returned.
  169.    // On error, 0 is returned and error_string points to the cause of the error (as reported by the server)
  170.    // which is stored in a static buffer in this very function.
  171.  
  172.    static char http_buffer[1024]; // used both for request and reply
  173.    static char ascii_email[128];
  174.  
  175.    struct sockaddr_in service;
  176.    struct hostent *hostinfo;
  177.    char *data_start;
  178.    WSADATA wsa_data;
  179.    int write_index;
  180.    int read_index;
  181.    int length;
  182.    SOCKET s;
  183.  
  184.    // initialize WinSock
  185.    if (WSAStartup (MAKEWORD (2, 2), &wsa_data) != 0)
  186.    {
  187.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  188.       return (0); // couldn't initialize WinSock, return an error condition
  189.    }
  190.  
  191.    // get our distribution server's IP address from the host name
  192.    hostinfo = gethostbyname ("pmbaty.com");
  193.    if (hostinfo == NULL)
  194.    {
  195.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  196.       return (0); // couldn't resolve hostname, return an error condition
  197.    }
  198.  
  199.    // fill in the sockaddr server structure with the server hostinfo data
  200.    service.sin_family = AF_INET;
  201.    service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0]));
  202.    service.sin_port = htons (80); // connect to webserver there (port 80)
  203.  
  204.    // create our socket
  205.    if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
  206.    {
  207.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  208.       return (0); // couldn't create socket, return an error condition
  209.    }
  210.  
  211.    // connect to the distributor's webserver using that socket
  212.    if (connect (s, (struct sockaddr *) &service, sizeof (service)) == -1)
  213.    {
  214.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  215.       return (0); // unable to connect to webserver, return an error condition
  216.    }
  217.  
  218.    // build the HTTP query and send it
  219.    ConvertTo7BitASCII (ascii_email, sizeof (ascii_email), candidate_email);
  220.    sprintf_s (http_buffer, sizeof (http_buffer),
  221.       "GET /chess/whatsmycode.php?email=%s HTTP/1.1\r\n"
  222.       "Host: pmbaty.com\r\n"
  223.       "Connection: close\r\n"
  224.       "\r\n", ascii_email);
  225.    length = strlen (http_buffer);
  226.    write_index = send (s, http_buffer, length, 0); // send the HTTP query
  227.    if (write_index != length)
  228.    {
  229.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  230.       return (0); // unable to send HTTP query, return an error condition
  231.    }
  232.  
  233.    // read the reply (10 seconds timeout)
  234.    http_buffer[0] = 0;
  235.    read_index = recv_with_timeout (s, 10.0f, http_buffer, sizeof (http_buffer), 0);
  236.    if (read_index < 1)
  237.    {
  238.       *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
  239.       return (0); // empty or erroneous HTTP reply, return an error condition
  240.    }
  241.  
  242.    closesocket (s); // finished communicating, close TCP socket
  243.    WSACleanup (); // and clean up WinSock
  244.  
  245.    // terminate recv buffer and see where the useful data starts
  246.    http_buffer[read_index] = 0;
  247.    //MessageBoxA (NULL, http_buffer, "HTTP response", MB_OK);
  248.    if ((data_start = strstr (http_buffer, "Success=")) != NULL)
  249.    {
  250.       *failure_reason = L""; // no error, set an empty string as the failure reason
  251.       return ((unsigned __int32) atoll (&data_start[strlen ("Success=")])); // and return the candidate code we got
  252.    }
  253.    else if ((data_start = strstr (http_buffer, "Error=")) != NULL)
  254.    {
  255.       data_start += strlen ("Error=");
  256.       if (strchr (data_start, '\r') != NULL) *strchr (data_start, '\r') = 0;
  257.       if (strchr (data_start, '\n') != NULL) *strchr (data_start, '\n') = 0;
  258.       if      (_stricmp (data_start, "WrongEmail") == 0)         *failure_reason = LOCALIZE (L"Registration_WrongEmail");
  259.       else if (_stricmp (data_start, "UnknownEmail") == 0)       *failure_reason = LOCALIZE (L"Registration_UnknownEmail");
  260.       else if (_stricmp (data_start, "TooManyActivations") == 0) *failure_reason = LOCALIZE (L"Registration_TooManyActivations");;
  261.       return (0); // server returned an error, return an error condition
  262.    }
  263.  
  264.    *failure_reason = LOCALIZE (L"Registration_NetworkFailure"); // this should never happen
  265.    return (0); // server returned an error, return an error condition
  266. }
  267.  
  268.  
  269. static int recv_with_timeout (int socket_id, float timeout_in_seconds, char *outbuf, size_t outbuf_size, int flags)
  270. {
  271.    unsigned long nonblocking_mode;
  272.    unsigned long msec_start;
  273.    float timediff;
  274.    int total_size;
  275.    int recv_size;
  276.  
  277.    // make socket non blocking
  278.    nonblocking_mode = 1;
  279.    ioctlsocket (socket_id, FIONBIO, &nonblocking_mode);
  280.  
  281.    // loop endlessly, noting the time at which we start
  282.    msec_start = GetTickCount ();
  283.    total_size = 0;
  284.    for (;;)
  285.    {
  286.       // see how much time elapsed since the last time we received data
  287.       timediff = (GetTickCount () - msec_start) / 1000.0f;
  288.       if (timediff > timeout_in_seconds)
  289.          break; // if we've waited long enough, give up
  290.  
  291.       // see if we have something to read from the socket
  292.       recv_size = recv (socket_id, &outbuf[total_size], outbuf_size - total_size, flags);
  293.       if (recv_size == 0)
  294.          break; // on TCP disconnection, give up too
  295.       else if (recv_size < 0)
  296.       {
  297.          Sleep (100); // if nothing was received then we want to wait a little before trying again, 0.1 seconds
  298.          continue;
  299.       }
  300.  
  301.       total_size += recv_size; // increase the received bytes count
  302.       outbuf[total_size] = 0; // terminate outbuf ourselves
  303.       if (total_size == outbuf_size)
  304.          break; // if the output buffer is full, give up
  305.       msec_start = GetTickCount (); // and remember when we last received data (i.e. now)
  306.    }
  307.  
  308.    return (total_size); // and return the number of bytes received
  309. }
  310.