Subversion Repositories Games.Chess Giants

Rev

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