Subversion Repositories Games.Chess Giants

Rev

Rev 185 | 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);
186 pmbaty 193
            was_donatebutton_clicked = false; // once is enough
153 pmbaty 194
            EndDialog (hWnd, 0); // then display a thank you dialog box and make the dialog box disappear
14 pmbaty 195
         }
196
 
197
         // else the supplied data is wrong
198
         else
199
         {
83 pmbaty 200
            swprintf_s (temp_string, WCHAR_SIZEOF (temp_string), LOCALIZE (L"Registration_Error"), AUTHOR_EMAIL);
153 pmbaty 201
            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 202
         }
203
      }
204
 
205
      // else was it the PayPal button ?
206
      else if (wParam_loword == BUTTON_DONATE)
89 pmbaty 207
      {
153 pmbaty 208
         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
209
 
89 pmbaty 210
         if (wcscmp (languages[language_id].name, L"French") == 0)
185 pmbaty 211
            wcscpy_s (temp_string, sizeof (temp_string), PAYPAL_URL_FR); // select the French PayPal page
89 pmbaty 212
         else
185 pmbaty 213
            wcscpy_s (temp_string, sizeof (temp_string), PAYPAL_URL_XX); // select the international (English) PayPal page
214
         wcscat_s (temp_string, sizeof (temp_string), transaction_uuid); // in all cases, append the transaction UUID that our server generated for us
164 pmbaty 215
 
185 pmbaty 216
         ShellExecute (NULL, L"open", temp_string, NULL, NULL, SW_MAXIMIZE); // open PayPal in the default browser, maximized
164 pmbaty 217
         was_donatebutton_clicked = true; // remember the user clicked the Donate button
89 pmbaty 218
      }
14 pmbaty 219
 
220
      // else was it the status bar hyperlink ?
221
      else if (wParam_loword == STATICTEXT_REGISTRATION_STATUSBAR)
23 pmbaty 222
         ShellExecute (NULL, L"open", PROGRAM_URL, NULL, NULL, SW_MAXIMIZE); // open the main page in the default browser, maximized
14 pmbaty 223
   }
224
 
225
   // call the default dialog message processing function to keep things going
226
   return (false);
227
}
83 pmbaty 228
 
229
 
185 pmbaty 230
static bool RetrieveActivationCode (wchar_t *candidate_email_or_uuid, unsigned int *returned_code, wchar_t **returned_email, wchar_t **failure_reason)
83 pmbaty 231
{
185 pmbaty 232
   // this function queries the remote server for registration status. If OK, the function returns TRUE and
233
   // the code and email are returned in the returned_code and returned_email pointers, and failure_reason
234
   // is set to point to a NULL string. On error, FALSE is returned and failure_reason points to the cause
235
   // of the error (localized). If candidate_email_or_uuid is a NULL string, only a server reachability test
236
   // is performed.
83 pmbaty 237
 
185 pmbaty 238
   #define REGISTRATION_HOST "pmbaty.com"
239
   #define REGISTRATION_SCRIPT "/chess/whatsmycode.php"
240
 
83 pmbaty 241
   static char http_buffer[1024]; // used both for request and reply
185 pmbaty 242
   static char ascii_email_or_uuid[128];
243
   static wchar_t wide_email[128];
83 pmbaty 244
 
245
   struct sockaddr_in service;
246
   struct hostent *hostinfo;
247
   char *data_start;
248
   int write_index;
249
   int read_index;
250
   int length;
251
   SOCKET s;
252
 
253
   // get our distribution server's IP address from the host name
185 pmbaty 254
   hostinfo = gethostbyname (REGISTRATION_HOST);
83 pmbaty 255
   if (hostinfo == NULL)
256
   {
185 pmbaty 257
      if (failure_reason != NULL)
258
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
259
      return (false); // couldn't resolve hostname, return an error condition
83 pmbaty 260
   }
261
 
262
   // fill in the sockaddr server structure with the server hostinfo data
263
   service.sin_family = AF_INET;
264
   service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0]));
265
   service.sin_port = htons (80); // connect to webserver there (port 80)
266
 
267
   // create our socket
268
   if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
269
   {
185 pmbaty 270
      if (failure_reason != NULL)
271
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 272
      return (0); // couldn't create socket, return an error condition
273
   }
274
 
275
   // connect to the distributor's webserver using that socket
276
   if (connect (s, (struct sockaddr *) &service, sizeof (service)) == -1)
277
   {
185 pmbaty 278
      closesocket (s);
279
      if (failure_reason != NULL)
280
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 281
      return (0); // unable to connect to webserver, return an error condition
282
   }
283
 
284
   // build the HTTP query and send it
185 pmbaty 285
   if (candidate_email_or_uuid != NULL)
286
      ConvertTo7BitASCII (ascii_email_or_uuid, sizeof (ascii_email_or_uuid), candidate_email_or_uuid);
83 pmbaty 287
   sprintf_s (http_buffer, sizeof (http_buffer),
185 pmbaty 288
              "GET " REGISTRATION_SCRIPT "?%s=%s HTTP/1.1\r\n"
289
              "Host: " REGISTRATION_HOST "\r\n"
290
              "Connection: close\r\n"
291
              "\r\n",
292
              (candidate_email_or_uuid != NULL ? (wcschr (candidate_email_or_uuid, '@') != NULL ? "email" : "uuid") : "test"),
293
              (candidate_email_or_uuid != NULL ? ascii_email_or_uuid : "1"));
83 pmbaty 294
   length = strlen (http_buffer);
295
   write_index = send (s, http_buffer, length, 0); // send the HTTP query
296
   if (write_index != length)
297
   {
185 pmbaty 298
      closesocket (s);
299
      if (failure_reason != NULL)
300
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 301
      return (0); // unable to send HTTP query, return an error condition
302
   }
303
 
88 pmbaty 304
   // read the reply (10 seconds timeout)
305
   http_buffer[0] = 0;
153 pmbaty 306
   read_index = RecvWithTimeout (s, 10.0f, http_buffer, sizeof (http_buffer), 0);
83 pmbaty 307
   if (read_index < 1)
308
   {
185 pmbaty 309
      closesocket (s);
310
      if (failure_reason != NULL)
311
         *failure_reason = LOCALIZE (L"Registration_NetworkFailure");
83 pmbaty 312
      return (0); // empty or erroneous HTTP reply, return an error condition
313
   }
314
 
315
   closesocket (s); // finished communicating, close TCP socket
316
 
317
   // terminate recv buffer and see where the useful data starts
318
   http_buffer[read_index] = 0;
319
   //MessageBoxA (NULL, http_buffer, "HTTP response", MB_OK);
185 pmbaty 320
   if (candidate_email_or_uuid == NULL)
83 pmbaty 321
   {
185 pmbaty 322
      if (failure_reason != NULL)
323
         *failure_reason = L""; // no error, set an empty string as the failure reason
324
      if ((data_start = strchr (http_buffer, '\n')) != NULL)
325
         *data_start = 0; // see where the first reply line ends and break the string there
326
      return ((strncmp (http_buffer, "HTTP/", 5) == 0) && (strstr (http_buffer, " 200 ") != NULL)); // reachability test only
83 pmbaty 327
   }
185 pmbaty 328
   else if ((data_start = strstr (http_buffer, "Success=")) != NULL)
329
   {
330
      if (failure_reason != NULL)
331
         *failure_reason = L""; // no error, set an empty string as the failure reason
332
      if (returned_code != NULL)
333
         *returned_code = (unsigned int) _atoi64 (&data_start[strlen ("Success=")]);
334
      if (returned_email != NULL)
335
      {
336
         data_start = strchr (data_start, ',');
337
         if (data_start != NULL)
338
         {
339
            if (strchr (data_start, '\r') != 0)
340
               *strchr (data_start, '\r') = 0; // don't report the newline
341
            ConvertToWideChar (wide_email, WCHAR_SIZEOF (wide_email), data_start + 1);
342
            *returned_email = wide_email;
343
         }
344
         else
345
            *returned_email = L"";
346
      }
347
      return (true); // and return the candidate code we got
348
   }
83 pmbaty 349
   else if ((data_start = strstr (http_buffer, "Error=")) != NULL)
350
   {
185 pmbaty 351
      if (failure_reason != NULL)
352
      {
353
         data_start += strlen ("Error=");
354
         if (strchr (data_start, '\r') != NULL) *strchr (data_start, '\r') = 0;
355
         if (strchr (data_start, '\n') != NULL) *strchr (data_start, '\n') = 0;
356
         if      (_stricmp (data_start, "WrongEmail") == 0)         *failure_reason = LOCALIZE (L"Registration_WrongEmail");
357
         else if (_stricmp (data_start, "UnknownEmail") == 0)       *failure_reason = LOCALIZE (L"Registration_UnknownEmail");
358
         else if (_stricmp (data_start, "TooManyActivations") == 0) *failure_reason = LOCALIZE (L"Registration_TooManyActivations");;
359
      }
360
      return (false); // server returned an error, return an error condition
83 pmbaty 361
   }
362
 
185 pmbaty 363
   if (failure_reason != NULL)
364
      *failure_reason = LOCALIZE (L"Registration_NetworkFailure"); // this should never happen
365
   return (false); // server returned an error, return an error condition
366
 
367
   #undef REGISTRATION_SCRIPT
368
   #undef REGISTRATION_HOST
83 pmbaty 369
}