Subversion Repositories Games.Chess Giants

Rev

Rev 179 | Rev 186 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
// dialog_registration.cpp
2
 
3
#include "../common.h"
4
 
5
 
6
// dialog template
7
#define THIS_DIALOG DIALOG_REGISTER
8
 
9
 
83 pmbaty 10
// global variables used in this module only
185 pmbaty 11
static wchar_t transaction_uuid[128] = L"";
164 pmbaty 12
static bool was_donatebutton_clicked = false;
185 pmbaty 13
static HWND hThisDialogWnd = NULL;
83 pmbaty 14
 
15
 
14 pmbaty 16
// prototypes of local functions
185 pmbaty 17
static void RegistrationCheckThread (void *thread_parms);
14 pmbaty 18
static int CALLBACK DialogProc_ThisDialog (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam);
185 pmbaty 19
static bool RetrieveActivationCode (wchar_t *candidate_email_or_uuid, unsigned int *returned_code, wchar_t **returned_email, wchar_t **failure_reason);
14 pmbaty 20
 
21
 
22
void DialogBox_Registration (void)
23
{
24
   // helper function to fire up the modal dialog box
25
 
185 pmbaty 26
   // first, test if our server is reachable. We DO NOT want the user to donate if our server isn't here to receive the donation!
27
   if (!RetrieveActivationCode (NULL, NULL, NULL, NULL))
28
      return; // if it's not, don't display anything
29
 
30
   // generate a random transaction UUID for this session
31
   srand ((unsigned int) time (NULL));
32
   swprintf_s (transaction_uuid, sizeof (transaction_uuid), L"%04x%04x-%04x-%04x-%04x-%04x%04x%04x", rand (), rand (), rand (), (rand () & 0x0fff) | 0x4000, (rand () & 0x3fff) | 0x8000, rand (), rand (), rand ());
33
 
34
   // start a new thread that will ask every 10 seconds if our transaction ID has donated
35
   _beginthread (RegistrationCheckThread, 0, NULL); // fire up the thread
36
 
14 pmbaty 37
   // display the dialog box (set the parent to be the desktop)
38
   DialogBox (hAppInstance, MAKEINTRESOURCE (THIS_DIALOG), NULL, DialogProc_ThisDialog);
39
 
40
   return; // finished processing this dialog
41
}
42
 
43
 
185 pmbaty 44
static void RegistrationCheckThread (void *thread_parms)
45
{
46
   // thread entrypoint for the thread that periodically checks whether transaction_uuid has just donated
47
 
48
   unsigned int returned_code; // 32 bits minimum
49
   wchar_t *returned_email;
50
 
51
   // loop endlessly
52
   for (;;)
53
   {
54
      // query the remote server for the code associated with this transaction UUID
55
      if (RetrieveActivationCode (transaction_uuid, &returned_code, &returned_email, NULL) && IsRegistrationCorrect (returned_email, returned_code))
56
         break; // stop looping as soon as we get correct values
57
 
58
      Sleep (10 * 1000); // next check in 10 seconds
59
   }
60
 
61
   // the user just registered, save activation email and activation code
62
   wcscpy_s (options.registration.user_email, WCHAR_SIZEOF (options.registration.user_email), returned_email);
63
   options.registration.activation_code = returned_code;
64
 
65
   if (IsWindow (hThisDialogWnd))
66
      ShowWindow (hThisDialogWnd, SW_HIDE); // make the dialog box disappear
67
   MessageBox (NULL, LOCALIZE (L"Registration_ThankYou"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK); // display a "thank you" message
68
   was_donatebutton_clicked = false; // prevent the reminder dialog box to open
69
   if (IsWindow (hThisDialogWnd))
70
      PostMessage (hThisDialogWnd, WM_CLOSE, 0, 0); // then close the dialog box
71
 
72
   return; // _endthread() implied
73
}
74
 
75
 
14 pmbaty 76
static int CALLBACK DialogProc_ThisDialog (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
77
{
78
   // message handler for the dialog box
79
 
83 pmbaty 80
   static wchar_t temp_string[1024];
14 pmbaty 81
 
82
   unsigned short wParam_hiword;
83
   unsigned short wParam_loword;
185 pmbaty 84
   unsigned int returned_code; // 32 bits minimum
83 pmbaty 85
   wchar_t *failure_reason;
86
   int write_index;
14 pmbaty 87
   int read_index;
88
   int length;
89
 
90
   // filter out the commonly used message values
91
   wParam_hiword = HIWORD (wParam);
92
   wParam_loword = LOWORD (wParam);
93
 
94
   // have we just fired up this window ?
95
   if (message == WM_INITDIALOG)
96
   {
185 pmbaty 97
      hThisDialogWnd = hWnd; // save the dialog handle
98
 
14 pmbaty 99
      // center the window
100
      CenterWindow (hWnd, hMainWnd);
101
 
102
      // set dialog icons (small one for title bar & big one for task manager)
103
      SendMessage (hWnd, WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon (hAppInstance, MAKEINTRESOURCE (ICON_MAIN)));
104
      SendMessage (hWnd, WM_SETICON, ICON_BIG, (LPARAM) LoadIcon (hAppInstance, MAKEINTRESOURCE (ICON_MAIN)));
105
 
106
      // set window title and control texts
107
      SetWindowText (hWnd, LOCALIZE (L"Registration_Title"));
108
 
109
      // set the static texts
110
      Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_QUESTION), LOCALIZE (L"Registration_Question"));
111
      Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_INSTRUCTIONS), LOCALIZE (L"Registration_Instructions"));
153 pmbaty 112
      // set email address font
113
      SendMessage (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS), WM_SETFONT, (WPARAM) GetStockObject (SYSTEM_FONT), 0);
83 pmbaty 114
      if (options.registration.user_email[0] != 0)
115
         SetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, options.registration.user_email);
116
      else
147 pmbaty 117
         SetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, LOCALIZE (L"Registration_YourEmailHere"));
14 pmbaty 118
      SetWindowText (GetDlgItem (hWnd, BUTTON_VALIDATECODE), LOCALIZE (L"Registration_ValidateCode"));
119
      Static_SetText (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_STATUSBAR), LOCALIZE (L"Registration_StatusBar"));
120
 
121
      // set focus to the first settable item
122
      SendMessage (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS), EM_SETSEL, 0, -1); // select all text
123
      SetFocus (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS));
124
 
147 pmbaty 125
      // convert the Paypal bitmap and the status bar message to hyperlinks
126
      ConvertStaticToHyperlink (GetDlgItem (hWnd, BUTTON_DONATE));
14 pmbaty 127
      ConvertStaticToHyperlink (GetDlgItem (hWnd, STATICTEXT_REGISTRATION_STATUSBAR));
128
   }
129
 
130
   // else did we click the close button on the title bar ?
131
   else if (message == WM_CLOSE)
164 pmbaty 132
   {
133
      if (was_donatebutton_clicked)
134
      {
135
         MessageBox (hWnd, LOCALIZE (L"Registration_DontForget"), PROGRAM_NAME, MB_ICONWARNING | MB_OK); // users need to be reminded that they MUST write their email in the activation form
136
         SendMessage (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS), EM_SETSEL, 0, -1); // select all text
137
         SetFocus (GetDlgItem (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS)); // focus on the email address field
138
         was_donatebutton_clicked = false; // once is enough
139
         return (true); // prevent window close this time
140
      }
141
      else
142
         EndDialog (hWnd, 0); // close the dialog box
185 pmbaty 143
 
144
      hThisDialogWnd = NULL; // this window is about to no longer have a handle, so remember it
164 pmbaty 145
   }
14 pmbaty 146
 
147
   // else did we take action on one of the controls ?
148
   else if (message == WM_COMMAND)
149
   {
150
      // did we cancel the dialog box ? (IDCANCEL is a system-wide dialog box handler value, that catches the ESC key)
151
      if (wParam_loword == IDCANCEL)
152
         EndDialog (hWnd, 0); // close the dialog box
153
 
21 pmbaty 154
      // else did the user enter something in the edit boxes ?
155
      else if (wParam_hiword == EN_CHANGE)
156
      {
83 pmbaty 157
         // enable the validation button only if the PayPal email field has data
185 pmbaty 158
         GetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, temp_string, WCHAR_SIZEOF (temp_string));
21 pmbaty 159
 
83 pmbaty 160
         // strip spaces and unprintable characters from candidate email, and bring it lowercase
185 pmbaty 161
         length = wcslen (temp_string);
14 pmbaty 162
         write_index = 0;
163
         for (read_index = 0; read_index < length; read_index++)
185 pmbaty 164
            if (!iswspace (temp_string[read_index]))
14 pmbaty 165
            {
185 pmbaty 166
               temp_string[write_index] = tolower (temp_string[read_index]); // force lowercase
83 pmbaty 167
               write_index++; // keep only valid signs and discard spaces
14 pmbaty 168
            }
185 pmbaty 169
         temp_string[write_index] = 0; // ensure string is correctly terminated
14 pmbaty 170
 
185 pmbaty 171
         EnableWindow (GetDlgItem (hWnd, BUTTON_VALIDATECODE), ((temp_string[0] != 0) && (wcslen (temp_string) > 5) && (wcscmp (temp_string, LOCALIZE (L"Registration_YourEmailHere")) != 0)
172
                                                                && (wcschr (temp_string, L'@') != NULL) && (wcschr (temp_string, L'.') != NULL)));
83 pmbaty 173
      }
14 pmbaty 174
 
83 pmbaty 175
      // else was it the validation button ?
176
      else if (wParam_loword == BUTTON_VALIDATECODE)
177
      {
185 pmbaty 178
         // enable the validation button only if the PayPal email field has data
179
         GetDlgItemText (hWnd, EDITBOX_REGISTRATION_EMAILADDRESS, temp_string, WCHAR_SIZEOF (temp_string));
180
 
83 pmbaty 181
         // query the remote server for the code associated with this email. If it fails, ask why.
185 pmbaty 182
         if (!RetrieveActivationCode (temp_string, &returned_code, NULL, &failure_reason)
183
             || ((failure_reason != NULL) && (failure_reason[0] != 0)))
153 pmbaty 184
            MessageBox (hWnd, failure_reason, PROGRAM_NAME, MB_ICONERROR | MB_OK); // registration failed. Display an error and DON'T make the dialog box disappear
83 pmbaty 185
 
186
         // else is the retrieved data correct ?
185 pmbaty 187
         else if (IsRegistrationCorrect (temp_string, returned_code))
14 pmbaty 188
         {
83 pmbaty 189
            // if so, save activation email and activation code
185 pmbaty 190
            wcscpy_s (options.registration.user_email, WCHAR_SIZEOF (options.registration.user_email), temp_string);
191
            options.registration.activation_code = returned_code;
14 pmbaty 192
            MessageBox (hWnd, LOCALIZE (L"Registration_ThankYou"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK);
153 pmbaty 193
            EndDialog (hWnd, 0); // then display a thank you dialog box and make the dialog box disappear
14 pmbaty 194
         }
195
 
196
         // else the supplied data is wrong
197
         else
198
         {
83 pmbaty 199
            swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), LOCALIZE (L"Registration_Error"), AUTHOR_EMAIL);
153 pmbaty 200
            MessageBox (hWnd, temp_string, PROGRAM_NAME, MB_ICONERROR | MB_OK); // wrong activation. Display an error and DON'T make the dialog box disappear
14 pmbaty 201
         }
202
      }
203
 
204
      // else was it the PayPal button ?
205
      else if (wParam_loword == BUTTON_DONATE)
89 pmbaty 206
      {
153 pmbaty 207
         MessageBox (hWnd, LOCALIZE (L"Registration_DontForget"), PROGRAM_NAME, MB_ICONWARNING | MB_OK); // users need to be reminded that they MUST write their email in the activation form
208
 
89 pmbaty 209
         if (wcscmp (languages[language_id].name, L"French") == 0)
185 pmbaty 210
            wcscpy_s (temp_string, sizeof (temp_string), PAYPAL_URL_FR); // select the French PayPal page
89 pmbaty 211
         else
185 pmbaty 212
            wcscpy_s (temp_string, sizeof (temp_string), PAYPAL_URL_XX); // select the international (English) PayPal page
213
         wcscat_s (temp_string, sizeof (temp_string), transaction_uuid); // in all cases, append the transaction UUID that our server generated for us
164 pmbaty 214
 
185 pmbaty 215
         ShellExecute (NULL, L"open", temp_string, NULL, NULL, SW_MAXIMIZE); // open PayPal in the default browser, maximized
164 pmbaty 216
         was_donatebutton_clicked = true; // remember the user clicked the Donate button
89 pmbaty 217
      }
14 pmbaty 218
 
219
      // else was it the status bar hyperlink ?
220
      else if (wParam_loword == STATICTEXT_REGISTRATION_STATUSBAR)
23 pmbaty 221
         ShellExecute (NULL, L"open", PROGRAM_URL, NULL, NULL, SW_MAXIMIZE); // open the main page in the default browser, maximized
14 pmbaty 222
   }
223
 
224
   // call the default dialog message processing function to keep things going
225
   return (false);
226
}
83 pmbaty 227
 
228
 
185 pmbaty 229
static bool RetrieveActivationCode (wchar_t *candidate_email_or_uuid, unsigned int *returned_code, wchar_t **returned_email, wchar_t **failure_reason)
83 pmbaty 230
{
185 pmbaty 231
   // this function queries the remote server for registration status. If OK, the function returns TRUE and
232
   // the code and email are returned in the returned_code and returned_email pointers, and failure_reason
233
   // is set to point to a NULL string. On error, FALSE is returned and failure_reason points to the cause
234
   // of the error (localized). If candidate_email_or_uuid is a NULL string, only a server reachability test
235
   // is performed.
83 pmbaty 236
 
185 pmbaty 237
   #define REGISTRATION_HOST "pmbaty.com"
238
   #define REGISTRATION_SCRIPT "/chess/whatsmycode.php"
239
 
83 pmbaty 240
   static char http_buffer[1024]; // used both for request and reply
185 pmbaty 241
   static char ascii_email_or_uuid[128];
242
   static wchar_t wide_email[128];
83 pmbaty 243
 
244
   struct sockaddr_in service;
245
   struct hostent *hostinfo;
246
   char *data_start;
247
   int write_index;
248
   int read_index;
249
   int length;
250
   SOCKET s;
251
 
252
   // get our distribution server's IP address from the host name
185 pmbaty 253
   hostinfo = gethostbyname (REGISTRATION_HOST);
83 pmbaty 254
   if (hostinfo == NULL)
255
   {
185 pmbaty 256
      if (failure_reason != NULL)
257
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
258
      return (false); // couldn't resolve hostname, return an error condition
83 pmbaty 259
   }
260
 
261
   // fill in the sockaddr server structure with the server hostinfo data
262
   service.sin_family = AF_INET;
263
   service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0]));
264
   service.sin_port = htons (80); // connect to webserver there (port 80)
265
 
266
   // create our socket
267
   if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
268
   {
185 pmbaty 269
      if (failure_reason != NULL)
270
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 271
      return (0); // couldn't create socket, return an error condition
272
   }
273
 
274
   // connect to the distributor's webserver using that socket
275
   if (connect (s, (struct sockaddr *) &service, sizeof (service)) == -1)
276
   {
185 pmbaty 277
      closesocket (s);
278
      if (failure_reason != NULL)
279
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 280
      return (0); // unable to connect to webserver, return an error condition
281
   }
282
 
283
   // build the HTTP query and send it
185 pmbaty 284
   if (candidate_email_or_uuid != NULL)
285
      ConvertTo7BitASCII (ascii_email_or_uuid, sizeof (ascii_email_or_uuid), candidate_email_or_uuid);
83 pmbaty 286
   sprintf_s (http_buffer, sizeof (http_buffer),
185 pmbaty 287
              "GET " REGISTRATION_SCRIPT "?%s=%s HTTP/1.1\r\n"
288
              "Host: " REGISTRATION_HOST "\r\n"
289
              "Connection: close\r\n"
290
              "\r\n",
291
              (candidate_email_or_uuid != NULL ? (wcschr (candidate_email_or_uuid, '@') != NULL ? "email" : "uuid") : "test"),
292
              (candidate_email_or_uuid != NULL ? ascii_email_or_uuid : "1"));
83 pmbaty 293
   length = strlen (http_buffer);
294
   write_index = send (s, http_buffer, length, 0); // send the HTTP query
295
   if (write_index != length)
296
   {
185 pmbaty 297
      closesocket (s);
298
      if (failure_reason != NULL)
299
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 300
      return (0); // unable to send HTTP query, return an error condition
301
   }
302
 
88 pmbaty 303
   // read the reply (10 seconds timeout)
304
   http_buffer[0] = 0;
153 pmbaty 305
   read_index = RecvWithTimeout (s, 10.0f, http_buffer, sizeof (http_buffer), 0);
83 pmbaty 306
   if (read_index < 1)
307
   {
185 pmbaty 308
      closesocket (s);
309
      if (failure_reason != NULL)
310
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 311
      return (0); // empty or erroneous HTTP reply, return an error condition
312
   }
313
 
314
   closesocket (s); // finished communicating, close TCP socket
315
 
316
   // terminate recv buffer and see where the useful data starts
317
   http_buffer[read_index] = 0;
318
   //MessageBoxA (NULL, http_buffer, "HTTP response", MB_OK);
185 pmbaty 319
   if (candidate_email_or_uuid == NULL)
83 pmbaty 320
   {
185 pmbaty 321
      if (failure_reason != NULL)
322
         *failure_reason = L""; // no error, set an empty string as the failure reason
323
      if ((data_start = strchr (http_buffer, '\n')) != NULL)
324
         *data_start = 0; // see where the first reply line ends and break the string there
325
      return ((strncmp (http_buffer, "HTTP/", 5) == 0) && (strstr (http_buffer, " 200 ") != NULL)); // reachability test only
83 pmbaty 326
   }
185 pmbaty 327
   else if ((data_start = strstr (http_buffer, "Success=")) != NULL)
328
   {
329
      if (failure_reason != NULL)
330
         *failure_reason = L""; // no error, set an empty string as the failure reason
331
      if (returned_code != NULL)
332
         *returned_code = (unsigned int) _atoi64 (&data_start[strlen ("Success=")]);
333
      if (returned_email != NULL)
334
      {
335
         data_start = strchr (data_start, ',');
336
         if (data_start != NULL)
337
         {
338
            if (strchr (data_start, '\r') != 0)
339
               *strchr (data_start, '\r') = 0; // don't report the newline
340
            ConvertToWideChar (wide_email, WCHAR_SIZEOF (wide_email), data_start + 1);
341
            *returned_email = wide_email;
342
         }
343
         else
344
            *returned_email = L"";
345
      }
346
      return (true); // and return the candidate code we got
347
   }
83 pmbaty 348
   else if ((data_start = strstr (http_buffer, "Error=")) != NULL)
349
   {
185 pmbaty 350
      if (failure_reason != NULL)
351
      {
352
         data_start += strlen ("Error=");
353
         if (strchr (data_start, '\r') != NULL) *strchr (data_start, '\r') = 0;
354
         if (strchr (data_start, '\n') != NULL) *strchr (data_start, '\n') = 0;
355
         if      (_stricmp (data_start, "WrongEmail") == 0)         *failure_reason = LOCALIZE (L"Registration_WrongEmail");
356
         else if (_stricmp (data_start, "UnknownEmail") == 0)       *failure_reason = LOCALIZE (L"Registration_UnknownEmail");
357
         else if (_stricmp (data_start, "TooManyActivations") == 0) *failure_reason = LOCALIZE (L"Registration_TooManyActivations");;
358
      }
359
      return (false); // server returned an error, return an error condition
83 pmbaty 360
   }
361
 
185 pmbaty 362
   if (failure_reason != NULL)
363
      *failure_reason = LOCALIZE (L"Registration_NetworkFailure"); // this should never happen
364
   return (false); // server returned an error, return an error condition
365
 
366
   #undef REGISTRATION_SCRIPT
367
   #undef REGISTRATION_HOST
83 pmbaty 368
}